|

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
|