Platform specifics: Windows
Compiler errors and gl.h
If you get compiler errors pointing to gl.h, this is because there are some things like WINGDI which are used in gl.h but are only defined in some other header files. Include windows.h before including gl.h
If you have link errors, then you need to figure out how to link with your specific compiler/IDE.
Example : with VC++6 (which is very old by now), you go to Project->Settings and click on the links tab.
Add opengl32.lib to the Object/library modules list.
If you use other libs like GLU, add glu32.lib.
Other compiler/IDE mind need to link with opengl32.a
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 sends 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?
Answer to this question depends on the situation:
- For application like CAD, 3D model viewer or anything that doesn't require constant updating, render when you receive the WM_PAINT message
- For high performance game do not use WM_PAINT and render directly from your "infinite loop"
Besides this simple division, please consider following advices:
- If you are developing game or dynamic visualisation in window (not fullscreen), consider setting up a timer and render only when receiving WM_TIMER message. You will be still able to get high framerate, but your program will not eat so much CPU resources
- If you are developing fullscreen application, do not render when user ALT-TABs from your program. You can detect this by handling WM_ACTIVATEAPP. This will again prevent CPU "hogging" when it is not necessary
To render image on the screen, you can follow this simple scheme:
glClear( ... ) // Clear the color/depth/stencil buffer // // Draw your geometry using OpenGL commands here // SwapBuffers( ... ) // Swap buffers to make geometry visible on screen
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 window, once. According 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.
This flag is for making an offscreen render buffer onto with you render with your GL commands. Typically, people do this so that they can BitBlt the result to a window or a BitBlt to a printer device context or so that they can use some Win32 commands on that same surface.
A few source code examples from 1995 show how to use PFD_DRAW_TO_BITMAP.
You should avoid using this flag during context creation, as it may cause you to not get a hardware-accelerated rendering context..
If your project opens other windows and you want GL on the other window as well, in each function that you have, call wglMakeCurrent(hdc, glrc) and when
you are done call wglMakeCurrent(NULL, NULL)
wglMakeCurrent(hdc, glrc); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); RenderThis(); RenderThat(); SwapBuffers(hdc); wglMakeCurrent(NULL, NULL);
This is because a GL context can be current to 1 thread. Since window 1 has a GL context and window 2 has a GL context, both can't be current at the same time. You can either create a window in another thread, this way each context is in its own thread, or if both windows use the same pixelformat, use 1 GL context for both windows. In the 2 window 1 context case, you still have to call wglMakeCurrent(hdc, glrc) wglMakeCurrent(NULL, NULL) because the hdc would be different for each window.
According to MSDN, wglShareLists shares display list space between 2 GL contexts. MSDN is outdated and full of errors.
This function allows you to share textures, VBO (Vertex Buffer Object), IBO (Index Buffer Object), shaders, FBO (Framebuffer Object), PBO (Pixel Buffer Object), UBO (Uniform Buffer Object), Texture Buffer Object (TBO).
VAO (Vertex Array Objects) are not shared. OQ (Occlusion Queries) are not shared. Transform Feedbacks are not shared.
The best time to call wglShareLists is when you create the 2 GL contexts (yes, you can create many more and share between all of them), and just after call wglShareLists. So the best time to call it is as soon as possible, even before you create any textures or VBOs, otherwise there is a risk that wglShareLists will fail.
Note that under *nix systems, there is no wglShareLists. Sharing is enabled at context creation time. This is a better design as it makes drivers simpler. Perhaps one day the ARB will have a better solution in the form of an extension.
SwapInterval aka vsync
If you need information on WGL_EXT_swap_control which gives wglSwapIntervalEXT, read
SwapInterval aka vsync
This function is for getting a pointer to a function. Since on Windows, opengl32.dll will never get updated, opengl32.dll only provides the GL 1.1 functionality subset. To get the higher ones, you need wglGetProcAddress. Note that wglGetProcAddress gives a direct pointer to the real opengl driver implemented by your IHV, so you get to bypass opengl32.dll. This doesn't mean your GL code will run faster. In the case of modern games, they are often fill rate limited due to the enormous about of pixels they need to render.
What about the WGL functions?
We call them the "wiggle" functions.
There are many wgl functions and some aren't even documented in MSDN.
Mostly, you will only need :
If you are writing an GL extension loader, you will make plenty use of wglGetProcAddress.
I don't recommend that you use some of these wgl functions :
- Use ChoosePixelFormat instead of wglChoosePixelFormat
- Use DescribePixelFormat instead of wglDescribePixelFormat
- Use SetPixelFormat instead of wglSetPixelFormat
- Use GetPixelFormat instead of wglGetPixelFormat
- Use SwapBuffers instead of wglSwapBuffers
glX vs wgl
This is a list of glX functions and there equivalent wgl functions. There migth be some missing entries.
glXChooseVisual --- ChoosePixelFormat
glXCopyContext —-- NULL
glXCreateContext --- wglCreateContext
glXCreateGLXPixmap --- CreateDIBitmap and CreateDIBSection
glXDestroyContext --- wglDeleteContext
glXDestroyGLXPixmap --- DeleteObject
glXGetConfig --- DescribePixelFormat
glXGetCurrentContext --- wglGetCurrentContext
glXGetCurrentDrawable --- wglGetCurrentDC
glXIsDirect —-- NULL
glXMakeCurrent --- wglMakeCurrent
glXQueryExtension ---- GetVersion
glXQueryVersion --- GetVersion
glXSwapBuffers --- SwapBuffers
glXUseXFont wglUseFontBitmaps and wglUseFontOutlines
glXWaitGL —-- NULL
glXWaitX --— NULL
XGetVisualInfo --- GetPixelFormat
XCreateWindow --- CreateWindow/CreateWindowEx and GetDC/BeginPaint
NULL —-- SetPixelFormat
glXGetProcAddress --— wglGetProcAddress
NULL —-- wglShareLists