Originally posted by roffe:
[b]
Software rasterization it is… http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnopen/html/msdn_gl6 .asp
[/b]
That web page was for Windows NT 3.5. It’s much easier now. Here are code examples for Win2k/XP in straight win32 API.
Normally you would create an image called m_hBitmapImage as follows:
m_hBitmapImage = CreateCompatibleBitmap( hDc, m_cxImage, m_cyImage );
You would then be able to select m_hBitmapImage into a memory device context and draw on it with GDI commands. That image is called a DDB, or Device Dependent Bitmap.
To be able to use OpenGL commands on it, you
need to create it as a DIB instead of as a DDB. A DIB is a Device Independent Bitmap. Create the image as a DIB as follows:
hDc = GetDC( NULL );
memset( &m_BitmapInfo, 0, sizeof(BITMAPINFO) );
m_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_BitmapInfo.bmiHeader.biWidth = m_cxImage;
m_BitmapInfo.bmiHeader.biHeight = m_cyImage;
m_BitmapInfo.bmiHeader.biPlanes = 1;
m_BitmapInfo.bmiHeader.biBitCount = 24;
m_BitmapInfo.bmiHeader.biCompression = BI_RGB;
m_hBitmapImage = CreateDIBSection( hDc, &m_BitmapInfo, DIB_RGB_COLORS,
(void **)(&m_pBitmapBits), NULL, 0 );
ReleaseDC( NULL, hDc );
Notice that we used a real device context, not a memory device context. Now we’re ready to draw on it with a memory device context. First create the memory device context and select the DIB into it:
hDc = CreateCompatibleDC( NULL );
hBitmapPrev = (HBITMAP)SelectObject( hDc, m_hBitmapImage );
Next I use the GDI Rectangle command to clear the image and give it a border:
Rectangle( hDc, 0, 0, m_cxImage, m_cyImage );
The GDI Rectangle command will use whatever pen and brush you selected into the device context. Select the desired pen and brush into hDc before calling Rectangle(), then unselect (and if necessary delete) the pen and brush.
Next, set up the pixel format. This code snippet shows important format descriptor settings:
pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cDepthBits = 16;
I don’t think Windows uses the Alpha value, but you still must use PFD_TYPE_RGBA to match Windows’ byte boundaries (they allocate 4 bytes per color).
Set pfd.cDepthBits to 32 if you want a 32 bit instead of 16 bit depth buffer. After using ChoosePixelFormat() and SetPixelFormat() you’re ready to render:
hRenderContext = wglCreateContext( hDc );
wglMakeCurrent( hDc, hRenderContext );
// OpenGL go commands here . . .
wglMakeCurrent( hDc, NULL );
wglDeleteContext( hRenderContext );
SelectObject( hDc, hBitmapPrev ); // Unselect the DIB from hDc
DeleteDC( hDc ); // Delete the Memory Device Context
Implement your OpenGL commands at the comment placeholder.
You can now use the DIB as a regular Windows bitmap.
By the way, all of the code above was in its own thread. That is because I typically have more than one OpenGL window going, and each current rendering context must be in its own thread. Theoretically, you should be able to implement that code in your main program thread. In that case, make sure you have no other rendering contexts current. If that doesn’t work, try not even defining any other rendering contexts.
Creating the thread for the code above is easy. It does not need a message loop (as a full blown OpenGL window requires), and it does not need synchronization, except to notify the parent window when it is done. That can be done by posting a WM_APP message to the parent window – be sure to use PostMessage(), not SendMessage(). When the parent window receives the message it terminates the thread, and you still have the DIB handle (m_hBitmapImage) because it was instantiated in a class in the main program thread. You can then use the DIB handle as a Windows bitmap in other threads.
For example, you can BitBlt it to the screen in a WM_PAINT handler as follows:
hdcMem = CreateCompatibleDC( hDc );
hBitmapPrev = (HBITMAP)SelectObject( hdcMem, m_hBitmapImage );
BitBlt( hDc, 0, 0, m_cxImage, m_cyImage,
hdcMem, 0, 0, SRCCOPY );
SelectObject( hdcMem, hBitmapPrev );
DeleteDC( hdcMem );
Finally, before your program ends, destroy the DIB:
DeleteObject( m_hBitmapImage );
This method of rendering offscreen works good for me. It’s pretty simple once you get the syntax correct. This posting should help others along that path.
I am writing apps for Win2k/XP with straight win32 API (no MFC). I have encountered some pitfalls, such as getting the syntax right for rendering offscreen, for which I have included the solution above. I have found other solutions and work-arounds, but I continually find new problems with developing for OpenGL on Windows.
My apps are not games, but I do include some game type features. Is this a lost art, to develop midrange apps for OpenGL on Windows? I hope programmers can help advance OpenGL on Windows by posting simple fixes and work-arounds like this. For example, I had problems with the mouse cursor when I don’t continually refresh the screen (in simple event-driven programming, which is important to use whenever possible to reduce resource usage and allow users to use other programs while yours is running). I fixed that by calling SetCursor( NULL ) just before rendering, then setting the previous cursor after rendering. I found this works best when the window’s class cursor is set to NULL, in which case you need to explicitly load and set the cursor when the window is created.
Another problem is using GDI on an OpenGL window after calling SwapBuffers(). Some Microsoft help pages say you can’t do that at all, and some of their help pages say you can, but not with double buffering. I found you can do it with double buffering, but that makes your app unstable in some circumstances. As such, I’ve decided not to use that. But I wonder if it is possible somehow.
Yet another problem I noticed recently was the occasional corruption of tooltips from toolbars over OpenGL windows in Windows XP (not on Win2k). I have not found a fix for that, but the problem seems benign enough to just let it happen.
Any help on Windows specific stuff like that will be appreciated. Help advance OpenGL on Windows by posting programming information and fixes on how to get OpenGL to work on Win2k/XP.
Thanks,
Carlos Portela