Platform specifics: Windows
What should I do before the window is created?
Be sure to use the CS_OWNDC flag.
If you are doing plain old WinMain coding, RegisterClassEx() takes the WNDCLASSEX structure.
WNDCLASSEX.style should have the CS_OWNDC
If you are using MFC (SDI or MDI project), override PreCreateWindow and add the CS_OWNDC to cs.
For CDialog based project, PreCreateWindow doesn't get called.
This flag is really needed for Win9x systems.
Since DCs (device contexts) consume resources, the OS does not assign a DC but might share it between multiple windows and GUI elements.
On WinNT and its derivatives, it is said that resources are not a problem and it assigns a unique DC per window.
For good practice, I recommend using CS_OWNDC.
When is a good time to create the GL context?
When the WM_CREATE message is sent.
This is when the window is created (has a valid HWND and DC).
Normally, the window is visible at this point. Even if you create a invisible window, this is the place to create the GL context.
This is also a good place to make the context current, setup some GL states and setup some things for your program.
For MFC, you override the OnCreate function for your "View" class.
It's flickering! Why?
Windows send a WM_ERASEBKGND message when the background needs to be erased.
Tell Windows that you handled the message by returning a non-zero number (TRUE).
On MFC, override OnEraseBkgnd and just return TRUE.
When do I render my scene?
If you are making an application like CAD, 3D model viewer or anything that doesn't require constant updating, do it when you receive the WM_PAINT message. If you are making a game, don't do anything here. Render from your "infinite loop".
- Clear the background with glClear
- Swap buffers
To swap buffers, use SwapBuffers instead of wglSwapBuffers.
For MFC, override OnPaint or OnDraw (depending on the parent class)
When do I destroy the GL context?
Some people do it when the WM_DESTROY message is received. In my experience, this is not correct because at this point, the window resources and DC are destroyed already. Functions like wglMakeCurrent may fail.
Try the following: call wglMakeCurrent(NULL, NULL) followed by wglMakeCurrent(hdc, hglrc).
The second call will(might) fail.
Instead, destroy the GL context when the WM_CLOSE message is received. With MFC, override OnClose.
Don't forget to deallocate your textures, display lists, VBOs, PBOs, FBOs, shaders, etc before destroying the GL context.
It is good programming practice to release resources!
Call wglMakeCurrent(NULL, NULL) to make the GL context non-current.
Call wglDeleteContext(glrc) to destroy the GL context.
If you have allocated a DC for your window, release it and/or destroy it (ReleaseDC and/or DeleteDC)
How many times can I call SetPixelFormat?
For each windows, once. Acoording to MSDN, it would lead to significant complications if they allowed for more flexibility.
Never call GetDC(NULL) and then call SetPixelFormat.
This gives the DC for the entire desktop. Instead, create a fullscreen window.
What about the WGL functions?
We call then the "wiggle" functions.
There are many wgl functions and some aren't even documented in MSDN.
Mostly, you will only need :
The first 3 are obvious.
According to MSDN, wglShareLists shares display list space. MSDN is outdated and full of errors.
This function allows you to share textures, VBOs, shaders, etc. Be careful because some GL object might not be shareable (NV_fence)
If you writing an extension loader, you will make plenty use og wglGetProcAddress.
I don't recommend that you use some of thise wgl functions :
- ChoosePixelFormat instead of wglChoosePixelFormat
- DescribePixelFormat instead of wglDescribePixelFormat
- SetPixelFormat instead of wglSetPixelFormat
- GetPixelFormat instead of wglGetPixelFormat
- SwapBuffers instead of wglSwapBuffers