offscreen rendering to DIB

Can anyone help?

I am attempting to output my OGL 3D graph screen image to a DIB (because I require a very large pixmap - much larger than the screen size).

I am coding in C on Win32 NT4 and have derived a successful offscreen render result using chapter 18 of OpenGL Superbible edition 2. I am creating a new DC & RC with a PFD_DRAW_TO_BITMAP flag in the PFD.

I can render any size offscreen buffer BUT I have to edit out the RenderScene() in 'case WM_PAINT: which of course means I get no onscreen image.

I use the RenderScene() function with all my OGL drawing code for both onscreen and offscreen rendering.

When initiating the offscreen render I make the RC current and delete it and the DC when the function is terminated.

I am using the wgl Win32 OGL interface with many Win32 GDI facilities and NOT the glut interface functions - I started OGL from the first edition of OGL Superbible.

I have run a PFD enumerator and found all OK.

The code in Superbible 2 only shows an offscreen render and not how this managed plus an onscreen render.

Where am I going wrong?

Many thanks in anticipation.

Peter Lee.

Sound like at the beginning of RenderScene() you’re calling wglMakeCurrent on the onscreen RC (which is standard practice). That would be the reason you need to comment it out - it changes the RC back from the memory context to the screen context and you end up with a black DIB (or something).

I hope I’m getting this right…

Anyways, what you probably want to do is pass the correct RC into RenderScene, therefore requesting it make that particular context active and render to it. Thats the real solution to your problem, I think, assuming I understand it right.

What I do in my programs is a “two stage” rendering call. I use the MFC framework so it makes it a bit easier, but if you look at it similarly what you can do is have a something similar to the following:

PreRender(HDC, HRC)
{
wglMakeCurrent(HDC, HRC);
// do some presetup for your window/context
RenderScene();
glFinish();
SwapBuffers(HDC);
}

RenderScene()
{
// Render whatever you want here
}

Granted you’re hit with an extra function call, but the flexibility is worth it.

Also, it gives you a modular approach, such that you can have some logic before RenderScene, such as being able to call a renderer utilizing various hardware features if they’re available, or your stock renderer.

Another ability is to break your scene down into different render functions. Again, it increases function call overhead, but its negligable and convienient.

Siwko

Hello Siwko,
Thank you very much for your help and prompt reply, but I am still unable
to initiate the change from render to screen to render to an off screen bitmap
followed by a return to on screen without editing and recompiling my code.
I am including a simplified version of my test code incase you
have time to look at it and let me know where I am going wrong.
Best regards,
Peter Lee.

//globals
static HDC hDC; //GDI DC for main window
static HGLRC hRC; //RC for main window
static HDC dc; //GDI DCt for bitmap
static HGLRC rc; //RC for bimap
void ChangeSize(long width, long hieght)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0f, fAspect, 100.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0f, 0.0f, -200.0f);
}
void PreRender(HDC hDC, HGLRC hRC)
{
if(render_screen == TRUE)
{
wglMakeCurrent(hDC, hRC);
RenderScene();
glFinish();
}
SwapBuffers(hDC);
}
void RenderScene(void)
{
//OGL drawing code
glFlush();
}
HPALETTE GetOpenGLPalette(HDC hDC)
{
//create a palette for the DC listed
return hRetPal; //return the handle to the new palette
}
void SetDCPixelFormat(HDC hDC)
{
//select the pixel format for a given DC
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//code
}
LRESULT CALLBACK WndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hDC = GetDC(hWnd);
SetDCPixelFormat(hDC);
hRC = wglCreateContext(hDC);
//wglMakeCurrent(hDC, hRC);
hPalette = GetOpenGLPalette(hDC);
break;
case WM_DESTROY:
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
if(hPalette != NULL)
{
DeleteObject(hPalette);
}
PostQuitMessage(0);
break;
case WM_SIZE:
maxX = LOWORD(lParam);
maxY = HIWORD(lParam);
ChangeSize(LOWORD(lParam), HIWORD(lParam));
InvalidateRect(hWnd,NULL,FALSE);
break;
case WM_KEYDOWN: //initiates on screen or off screen rendering
{
if(wParam == VK_END)
{
InvalidateRect(hWnd,NULL,FALSE);
Make_DIB();
}
if(wParam == VK_HOME)
{
render_screen = FALSE;
InvalidateRect(hWnd,NULL,FALSE);
}
break;
}
case WM_PAINT:
{
PreRender(hDC, hRC);
//RenderScene();
//SwapBuffers(hDC);
ValidateRect(hWnd,NULL);
}
break;
case WM_QUERYNEWPALETTE:
//code
case WM_PALETTECHANGED:
//code
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0L);
}
void Make_DIB(void)
{
//declare variables etc
dc = CreateCompatibleDC(NULL);
//code
memset(&info, 0, sizeof(info));
//code - info
bitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, NULL, 0);
//code
SelectObject(dc, bitmap);
memset(&pfd, 0, sizeof(pfd));
//code - pfd
pf = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, pf, &pfd);
rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
glClearColor(0.3f, 0.2f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluPerspective(80.0f, (float)Width/Height, 100.0, 1000.0);
glTranslatef(0.0f, 0.0f, -200.0f);
RenderScene();
glFlush();
render_screen = TRUE; //resets render destination logic
SaveDIBitmap(“PJL_Contour.bmp”, &info, bits);
//Free everything:
wglDeleteContext(rc);
DeleteObject(bitmap);
DeleteDC(dc);
}
int SaveDIBitmap(const char *filename,
BITMAPINFO *info,
GLubyte *bits)
{
//code
}

Hmm, after a brief glance, the only thing that comes to mind is that before you go about destroying the DIB DC and RC, call wglMakeCurrent(NULL, NULL) so that OpenGL releases the memory context first. I believe that you must do this inorder for OpenGL to properly release the contexts. After that, you should be able to deselect the bitmap DC and destroy it. That should free you up so that the next call to wglMakeCurrent(hDC, hRC) actually works.

Let me know how you fare, and if I can find anything else, I’ll let you know.

Siwko

Originally posted by Peter Lee:
//Free everything:
wglDeleteContext(rc);
DeleteObject(bitmap);
DeleteDC(dc);

In fact, here it is right here. Before you delete a context you need to deselect it first. Thus, before your call to wglDeleteContext(rc) throw in wglMakeCurrent(NULL, NULL) and it should work. (Cross fingers)

Good luck, and let me know!

Siwko

Hello Siwko,

Thank you so much for your time and help.

I am still unable to initiate a render to offscreen DIB from the situation where I have a rendered screen image. I am unable to delete the screen RC using the OGL/Win32 functions. I just can not disable the render to screen (giving a black screen) other than commenting out the functions WglCreateContext() and/or wglMakeCurrent() in WM_CREATE or RenderScene() in WM_PAINT and recompiling.

My first task must be to interrupt the render to screen using, in my test code, a WM_KEYDOWN plus logic.

The second step is render to offscreen DIB - this function seems to be working.

The third step is to restore the render to screen - after destroying the DIB, RC etc.

If you have any suggestions, I would be very grateful.

Best regards,
Peter

Hello Siwko,
Thank you for all your patients and help. I have found the problem - the glaux library solids that I was using in my test code (just as a convenient 3D solid).

What put me on to it was when reading through some other OGL forum topics where one contibutor stated that they thought the glaux lib. was to be avoided.

Any way as soon as I used vertex & triangles in my test code the problem cleared and I am now able to generate an offscreen DIB!

Best regards,
Peter.