// define our window width and height variables
int ww, wh;
/*************************************************************************
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
This function is called every time Windows wants to tell our window
something. hWnd is the handle to our window, uMsg is what Windows is
telling us, and wParam and lParam are extra parameters for that message
(ex. new width and height when our window is resized).
*************************************************************************/
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// PAINTSTRUCT: temporary variable for painting to the window
static PAINTSTRUCT ps;
// The window may have received a message, so lets check what it
// is and do stuff accordingly
switch(uMsg) {
case WM_PAINT:
// window is being drawn, so call our Display() function to handle it.
BeginPaint(hWnd, &ps); // tell Windows to paint our window
Display(); // run the function to display our game
EndPaint(hWnd, &ps); // now tell Windows we're done painting our window
return 0;
case WM_SIZE:
// window was resized, so call our Resize() function to handle it.
Resize(LOWORD(lParam), HIWORD(lParam));
// tell Windows to repaint our window because it has changed
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
/*************************************************************************
CreateOpenGLWindow(char* title, int x, int y, int width, int height)
This function handles creating the actual window. It's called by the WinMain
function which will be defined a little later.
Creating a window requires a WNDCLASS (window class) Object. In this class
we tell Windows about our window's cursor, icon, etc. It also tells Windows
what function to call if anything happens to our window, in this case the
function is WindowProc();.
Creating an OpenGL window also requires setting a PIXELFORMATDESCRIPTOR,
which tells Windows exactly what kind of window we want to use OpenGL in,
whether its 16bit color, 24bit color, etc.
Finally, this function will return the handle to our window (hWnd) so we can
work with it.
*************************************************************************/
HWND CreateOpenGLWindow(char* title, int x, int y, int width, int height) {
int pf;
HDC hDC;
HWND hWnd;
WNDCLASS wc;
static HINSTANCE hInstance = 0;
/* only register the window class once - use hInstance as a flag. */
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc)) {
MessageBox(NULL, "RegisterClass() failed", "Error", MB_OK);
return NULL;
}
}
// create the window using our "OpenGL" window class.
hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, width, height, NULL, NULL, hInstance, NULL);
// if the window wasn't created for some reason, quit with an error
// message.
if (hWnd == NULL) {
MessageBox(NULL, "CreateWindow() failed", "Error", MB_OK);
return NULL;
}
// get the current "device context". don't worry about what this is.
hDC = GetDC(hWnd);
// set up our PIXELFORMATDESCRIPTOR properties
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
// tell windows to choose a pixel format based on what we want
pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed", "Error", MB_OK);
return 0;
}
// now set the pixel format
if (SetPixelFormat(hDC, pf, &pfd) == false) {
MessageBox(NULL, "SetPixelFormat() failed", "Error", MB_OK);
return 0;
}
// describe the pixelformat for our device context
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
// release the device context
ReleaseDC(hWnd, hDC);
// return our created window's handle (hWnd)
return hWnd;
}
/*************************************************************************
WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow)
WinMain is the standard function to start a Windows program. In here we
create the window, set everything up, and then enter a loop. This loop
checks for messages sent to our window, handles them, does our game-specific
calculations, and displays our OpenGL stuff.
Also in this loop we run two of our own functions. One is Display(), which
executes all the OpenGL commands we want to use. After doing Display(), we
tell OpenGL to glFinish up anything it still has to do, and then swap our
buffers. The second is Idle(), which handles moving objects around, getting
keyboard input, etc.
So what exactly is swapping buffers? When we draw stuff to the screen,
the fastest way to do it is to use two buffers. The first buffer is what
is actually on the screen. The second is a "back buffer". We draw all our
new stuff to this back buffer, and then we dump everything from it onto the
screen buffer.
*************************************************************************/
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow) {
HDC hDC; /* device context */
HGLRC hRC; /* opengl context */
HWND hWnd; /* window */
MSG msg; /* message */
// call our CreateOpenGLWindow function
hWnd = CreateOpenGLWindow("Simple OpenGL App", 0, 0, 1024, 768);
if (hWnd == NULL) exit(1);
// get the device context of our created window
hDC = GetDC(hWnd);
// call a Windows GL (wgl) function to get a Rendering Context
// this is for windows to know what window we're rendering on with OpenGL
hRC = wglCreateContext(hDC);
// tell Windows to make our new Rendering Context current
wglMakeCurrent(hDC, hRC);
// Run our Init function to set up OpenGL settings and other stuff
Init();
// show and update our window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Now we enter our main loop. At this point, the window is made and
// we're all set to render
while (1) {
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
// if there's a message for us, then translate it and
// dispatch it
if(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// otherwise, the window has been closed and isn't
// receiving any more messages
else {
goto quit;
}
}
// Call the display function
Display();
// Tell OpenGL to finish up all it's instructions before moving on
glFinish();
// Swap our display buffers
SwapBuffers(hDC);
// Run other game-specific calculations
Idle();
}
quit:
// The user closed the window, so we have to shut down.
// make no OpenGL context current, we can't shut down a rendering context
// if it's still active.
wglMakeCurrent(NULL, NULL);
// release our Device Context
ReleaseDC(hWnd, hDC);
// Delete our rendering context
wglDeleteContext(hRC);
// destroy our window
DestroyWindow(hWnd);
// return something-or-other =]
return msg.wParam;
}
/*************************************************************************
Init()
This function is called to initialize OpenGL variables for our program.
You can also put anything else you want to be done before the program
starts going.
*************************************************************************/
void Init() {
// clear the screen with a black color
glClearColor (0, 0, 0, 1);
glDrawBuffer(GL_BACK);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
glEnable(GL_BLEND);
glEnable(GL_ALPHA);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glAlphaFunc(GL_GEQUAL, 0.05);
glPointSize(4);
glLineWidth(4);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
}
/*************************************************************************
Resize(int w, int h)
This function is called whenever our window gets resized or moved. OpenGL
requires that we tell it where the new rendering position is, otherwise
it'll keep rendering in spots that don't belong to our window.
*************************************************************************/
void Resize(int w, int h) {
ww = w;
wh = h;
glViewport(0, 0, ww, wh);
}
/*************************************************************************
Display()
This function executes gl commands to display stuff onscreen. It also
sets up the position of the viewer and other display-related stuff.
In this tutorial, nothing is placed in here to keep it simple.
*************************************************************************/
void Display() {
// clear the window to our glClearColor
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
/*************************************************************************
Idle()
This function is used to calculate player movement, AI, collision
detection, etc. It could be placed in the Display() function, but
that just mixes things up.
*************************************************************************/
void Idle() {
}