Welcome to the new Friends-of-FPC!

Here you can find all kinds of information about the FreePascal Compiler. We have many tutorials and howtos as well as a selection of tools to help you with your programming. We also have some example codes for you. And if you want to contribute some information/ sources/ tools yourself you can do so.
Also we have finally relaunched the FoFPC forum. It's your chance for some Q&A about everything FreePascal.

Friends-of-FPC

Tutorials: Learn how to code with FreePascal.

Source Codes: A collection of examples, miscellaneous source codes and open source stuff.

Tools and Help Files: Intro- duction of some tools that might help you with FPC.

Community

Forum: Ask or answer questions about the FreePascal Compiler, programming or just babble about coding.

Contribute! Contribute your own Tutorial, Source Codes or Tools and send them to us!

Website

About: Information about Friends-of-FPC.org.

Einführung in OpenGL - Teil 2 - by Delax

Zunächst ist ein OpenGL Fenster nichts anderes als eben der Name schon sagt: ein Fenster. Im Prinzip beginnen wir unsere Initialisierung also mit dem definieren einer Windows Klasse, dem definieren des Fensters und dann dem erzeugen des solchen.

PROCEDURE Window_Register;
begin

  wc.cbSize             := sizeof(wc);
  wc.style		:= CS_OWNDC;
  wc.lpfnWndProc	:= WndProc(@GlWndProc);
  wc.cbClsExtra		:= 0;
  wc.cbWndExtra		:= 0;
  wc.hInstance		:= hInstance;
  wc.hIcon		:= LoadIcon( 0, IDI_APPLICATION );
  wc.hCursor		:= LoadCursor( 0, IDC_ARROW );
  wc.hbrBackground	:= 0;
  wc.lpszMenuName	:= nil;
  wc.lpszClassName	:= 'forwardGL';
  wc.hIconSm            := LoadIcon(0, IDI_APPLICATION);

  RegisterClassEx( wc );

end;

Sehr einfach, oben stehend die Prozedur zum definieren der Windows Klasse. Das einzig besondere ist die hbrBackground. Jenen brauchen wir nämlich nicht zu definieren, da der Hintergrund des Fensters so wie so nicht zu sehen sein wird. Schließlich wollen wir im Fenster ja OpenGL ausgeben.

Jetzt folgt die Prozedur zum Erzeugen des Fensters. Auch hier nichts besonderes.

PROCEDURE Window_Create;
begin

 window_hWnd := CreateWindowEx(WS_EX_TOPMOST,
				'forwardGL',
				'OpenGL/ FPC Tutorial', 
				WS_CAPTION OR WS_POPUPWINDOW OR WS_VISIBLE,
				0, 0, 
				width, 
				height,
				0, 0, 
				hInstance, 
				nil );

  if (window_hWnd = 0) then Throw('Window could not be created');

end;

Beachtet das wir die Größe des Fensters durch die Variablen width und height definiert wird.

Hier ein Blick auf die Initialisierung unseres Fensters. Als erstes benötigen wir einen Device Context. Als nächstes definieren wir ein Pixel Format für unser Fenster. Dabei sind einige Besonderheiten zu beachten.

In pfd.dwFlags muß auf jeden Fall PFD_SUPPORT_OPENGL definiert werden. Je nach gewünschter Beschaffenheit des Fensters auch noch PFD_DRAW_TO_WINDOW und/ oder PFD_DOUBLEBUFFER. Dazu kommt die Definition der Bit-Tiefe und andere Dinge. Anschließend speichern wir diese Definitionen in unserer Variable für das Pixelformat.

Als nächstes folgt die Zeile window_hRC := wglCreateContext( window_hDC );. Damit holen wir für unser Fenster einen OpenGL Render Context. Schließlich sagen wir noch, das wir unser neu erzeugtes Fenster von nun an das Ziel unserer OpenGL Aktionen sein soll.

PROCEDURE Window_Init;
begin

  window_hDC := GetDC( window_hWnd );	// Get Device Context

  FillChar(pfd, sizeof(pfd), 0);	// Define Pixel Format
  pfd.nSize         := sizeof(pfd);
  pfd.nVersion      := 1;
  pfd.dwFlags       := PFD_SUPPORT_OPENGL OR PFD_DRAW_TO_WINDOW OR PFD_DOUBLEBUFFER;
  pfd.iPixelType    := PFD_TYPE_RGBA;
  pfd.cColorBits    := bits;
  pfd.cDepthBits    := 16;
  pfd.iLayerType    := PFD_MAIN_PLANE;

  iFormat := ChoosePixelFormat( window_hDC, pfd );	// Create Pixel Format

  if (iFormat = 0) then Throw('Pixel Format not Available');

  SetPixelFormat( window_hDC, iFormat, @pfd );		// Set Pixel Format
  window_hRC := wglCreateContext( window_hDC );		// Create OpenGL Context

  if (window_hRc = 0) then Throw('Render Context could not be set');

  wglMakeCurrent( window_hDC, window_hRC );		// Bind OpenGL to our Window

end;

O.k. Wenn man diese Prozeduren hintereinander aufruft hat man also ein Fenster mit einem OpenGL Render Context. Alles, was nun an OpenGL Instruktionen kommt wird direkt in das Fenster geschrieben, zumindest wenn wir das so wollen.

Als nächstes müssen wir OpenGL selbst konfigurieren. Da machen wir es uns erst einmal einfach und nutzen nur eine einzige Zeile.

PROCEDURE OpenGL_Init;
begin

  glClearColor( 0.0, 0.0, 0.0, 0.0 );

end;

Mit glClearColor() definiert man die Farbe, mit der unser Fenster jede Runde gelöscht wird. Die Angaben folgen im RGB System, will sagen der erste Wert ist die Intensität der Farbe Rot, der zweite Grün, der dritte Blau. 0.0 ist der minimale Wert, 1.0 ist der maximale Wert. 1.0, 0.0, 0.0 wäre also maximales Rot. Der letzte Wert ist der sogenannte Alpha Wert, aber auf den kommen wir später zu sprechen.

Kommen wir nun zur Hauptschleife. Auch hier steht eine wichtige Zeile, nämlich SwapBuffers( window_hDC );. Mit SwapBuffers() wird bei gebufferten Fenstern der eigentliche Inhalt des Grafikspeichers in das Fenster kopiert. Also einfach nur OpenGL Kommandos schreiben bringt ohne diese Zeile herzlich wenig.

Hier also der Source Code des ersten Programmes. Es initialisiert einfach nur das Fenster und macht sonst nicht viel.

{$APPTYPE GUI}
{$MODE DELPHI}

PROGRAM source_1;

USES
  windows,		// Windows API Stuff
  gl_sl,		// OpenGL API Stuff
  OpenGL32;		// OpenGL API Stuff

CONST

  window_hdc   : HDC     = 0;
  window_hrc   : HGLRC   = 0;
  window_hwnd  : HWND    = 0;

  width = 640;		// width of the Window
  height = 480;		// height of the Window
  bits = 16;		// depth of the window

VAR

  pfd : PIXELFORMATDESCRIPTOR;
  wc : WNDCLASSEX;	// Window Class
  msg : MSG;		// Windows messages
  iFormat : integer;	// Pixel Format

  active : boolean;	// is program active?

// ----------------- Try, Throw, Catch -------------------- //
PROCEDURE Throw(throw_string : pChar);
begin
  MessageBox(0, throw_string, 'Error', MB_OK);
  Halt(0);
end;

// --------------------- WinProc -------------------------- //
FUNCTION GlWndProc(window_hwnd : HWND; message : DWORD; wParam : WPARAM; lParam : LPARAM) : LRESULT; export;
begin
  case (message) of

    WM_CREATE:			// program started
      begin
	active := true;
        GlWndProc := 0;
      end;

    WM_DESTROY:			// program shutdown
      begin
	active := false;
	GlWndProc := 0;
      end;

    WM_KeyDown:			// keypressed, thus shutdown
      begin
	SendMessage(window_hwnd,wm_destroy,0,0);
        GlWndProc := 0;
      end;

  else				// other msg
    GlWndProc := DefWindowProc(window_hwnd, message, wParam, lParam);
  end;
end;

// ------------- Register Windows Class ------------------ //
PROCEDURE Window_Register;
begin

  wc.cbSize             := sizeof(wc);
  wc.style		:= CS_OWNDC;
  wc.lpfnWndProc	:= WndProc(@GlWndProc);
  wc.cbClsExtra		:= 0;
  wc.cbWndExtra		:= 0;
  wc.hInstance		:= hInstance;
  wc._hIcon		:= LoadIcon( 0, IDI_APPLICATION );
  wc.hCursor		:= LoadCursor( 0, IDC_ARROW );
  wc.hbrBackground	:= 0;
  wc.lpszMenuName	:= nil;
  wc.lpszClassName	:= 'forwardGL';
  wc.hIconSm            := LoadIcon(0, IDI_APPLICATION);

  RegisterClassEx( wc );

 end;

// ---------------- Window Creation ---------------------- //
 PROCEDURE Window_Create;
 begin

 window_hWnd := CreateWindowEx(WS_EX_TOPMOST,
				'forwardGL',
				'OpenGL/ FPC Tutorial', 
				WS_CAPTION OR WS_POPUPWINDOW OR WS_VISIBLE,
				0, 0, 
				width, 
				height,
				0, 0, 
				hInstance, 
				nil );

  if (window_hWnd = 0) then Throw('Window could not be created');

end;

// ------------- Window Initialisation ----------------- //
PROCEDURE Window_Init;
begin

  window_hDC := GetDC( window_hWnd );	// Get Device Context

  FillChar(pfd, sizeof(pfd), 0);	// Define Pixel Format
  pfd.nSize         := sizeof(pfd);
  pfd.nVersion      := 1;
  pfd.dwFlags       := PFD_SUPPORT_OPENGL OR PFD_DRAW_TO_WINDOW OR PFD_DOUBLEBUFFER;
  pfd.iPixelType    := PFD_TYPE_RGBA;
  pfd.cColorBits    := bits;
  pfd.cDepthBits    := 16;
  pfd.iLayerType    := PFD_MAIN_PLANE;

  iFormat := ChoosePixelFormat( window_hDC, pfd );	// Create Pixel Format

  if (iFormat = 0) then Throw('Pixel Format not Available');

  SetPixelFormat( window_hDC, iFormat, @pfd );		// Set Pixel Format
  window_hRC := wglCreateContext( window_hDC );		// Create OpenGL Context

  if (window_hRc = 0) then Throw('Render Context could not be set');

  wglMakeCurrent( window_hDC, window_hRC );		// Bind OpenGL to our Window

end;

// ----------------- Kill Window ----------------------- //
PROCEDURE Window_DeInit;
begin

  wglMakeCurrent( window_hDc, 0 );	// kill Devie Context
  wglDeleteContext( window_hRC );	// Kill Render Context
  ReleaseDC( window_hWnd, window_hDC );	// Release Window

end;

// ----------------- Init OpenGL ------------------------ //
PROCEDURE OpenGL_Init;
begin

  glClearColor( 0.0, 0.0, 0.0, 0.0 );

end;

// ~~~~~~~~~~~~~~~~~~~~~~ Main ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
begin

 Window_Register;		// register window
 Window_Create;			// create window
 Window_Init;			// init window

 OpenGL_Init;			// init opengl stuff

 REPEAT				// start main proc

if PeekMessage(@msg,0,0,0,0) = true then begin
  GetMessage(@msg,0,0,0);
  TranslateMessage(msg);
  DispatchMessage(msg);
end;

 SwapBuffers( window_hDC );	// put opengl stuff to screen

UNTIL active = false;		// end main proc

  Window_DeInit;		// kill window stuff
  DestroyWindow( window_hWnd );	// kill window itself
end.

Recht lang, aber Cut & Paste ist unnötig, denn hier gibt es das Programm zum Download. Schaut es euch mal in Ruhe an, compiliert es und dann weiter im Text.

Delax/ Sundancer Inc.
[delax@sundancerinc.de]

Back to previous page

Useful Links









Link to us