case WM_CLOSE: // Did We Receive A Close Message?
{
PostQuitMessage(0); // Send A Quit Message
return 0; // Jump Back
}
If a key is being held down we can find out what key it is by reading wParam. I then make that keys cell in the array keys[ ] become TRUE. That way I can read the array later on and find out which keys are being held down. This allows more than one key to be pressed at the same time.
case WM_KEYDOWN: // Is A Key Being Held Down?
{
keys[wParam] = TRUE; // If So, Mark It As TRUE
return 0; // Jump Back
}
If a key has been released we find out which key it was by reading wParam. We then make that keys cell in the array keys[] equal FALSE. That way when I read the cell for that key I'll know if it's still being held down or if it's been released. Each key on the keyboard can be represented by a number from 0-255. When I press the key that represents the number 40 for example, keys[40] will become TRUE. When I let go, it will become FALSE. This is how we use cells to store keypresses.
case WM_KEYUP: // Has A Key Been Released?
{
keys[wParam] = FALSE; // If So, Mark It As FALSE
return 0; // Jump Back
}
Whenever we resize our window uMsg will eventually become the message WM_SIZE. We read the LOWORD and HIWORD values of lParam to find out the windows new width and height. We pass the new width and height to ReSizeGLScene(). The OpenGL Scene is then resized to the new width and height.
case WM_SIZE: // Resize The OpenGL Window
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height
return 0; // Jump Back
}
}
Any messages that we don't care about will be passed to DefWindowProc so that Windows can deal with them.
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
This is the entry point of our Windows Application. This is where we call our window creation routine, deal with window messages, and watch for human interaction.
int WINAPI WinMain(HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
We set up two variables. msg will be used to check if there are any waiting messages that need to be dealt with. the variable done starts out being FALSE. This means our program is not done running. As long as done remains FALSE, the program will continue to run. As soon as done is changed from FALSE to TRUE, our program will quit.
MSG msg; // Windows Message Structure
BOOL done=FALSE; // Bool Variable To Exit Loop
This section of code is completely optional. It pops up a messagebox that asks if you would like to run the program in fullscreen mode. If the user clicks on the NO button, the variable fullscreen changes from TRUE (it's default) to FALSE and the program runs in windowed mode instead of fullscreen mode.
// Ask The User Which Screen Mode They Prefer
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO|MB_ICONQUESTION) == IDNO) {
fullscreen=FALSE; // Windowed Mode
}
This is how we create our OpenGL window. We pass the title, the width, the height, the color depth, and TRUE (fullscreen) or FALSE (window mode) to CreateGLWindow. That's it! I'm pretty happy with the simplicity of this code. If the window was not created for some reason, FALSE will be returned and our program will immediately quit (return 0).
// Create Our OpenGL Window
if (!CreateGLWindow("NeHe's OpenGL Framework", 640, 480, 16, fullscreen)) {
return 0; // Quit If Window Was Not Created
}
This is the start of our loop. As long as done equals FALSE the loop will keep repeating.
while(!done) // Loop That Runs Until done=TRUE
{
The first thing we have to do is check to see if any window messages are waiting. By using PeekMessage() we can check for messages without halting our program. A lot of programs use GetMessage(). It works fine, but with GetMessage() your program doesn't do anything until it receives a paint message or some other window message.
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?
{
In the next section of code we check to see if a quit message was issued. If the current message is a WM_QUIT message caused by PostQuitMessage(0) the variable done is set to TRUE, causing the program to quit.
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
} else // If Not, Deal With Window Messages
{
If the message isn't a quit message we translate the message then dispatch the message so that WndProc() or Windows can deal with it.
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
} else // If There Are No Messages
{
If there were no messages we'll draw our OpenGL scene. The first line of code below checks to see if the window is active. If the ESC key is pressed the variable done is set to TRUE, causing the program to quit.
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if (active) // Program Active?
{
if (keys[VK_ESCAPE]) // Was ESC Pressed?
{
done=TRUE; // ESC Signalled A Quit
} else // Not Time To Quit, Update Screen
{
If the program is active and esc was not pressed we render the scene and swap the buffer (By using double buffering we get smooth flicker free animation). By using double buffering, we are drawing everything to a hidden screen that we can not see. When we swap the buffer, the screen we see becomes the hidden screen, and the screen that was hidden becomes visible. This way we don't see our scene being drawn out. It just instantly appears.
DrawGLScene(); // Draw The Scene
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
}
}
The next bit of code is new and has been added just recently (05-01-00). It allows us to press the F1 key to switch from fullscreen mode to windowed mode or windowed mode to fullscreen mode.
if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
if (!CreateGLWindow("NeHe's OpenGL Framework", 640, 480, 16, fullscreen)) {
return 0; // Quit If Window Was Not Created