Printing an OpenGL scene

I do Windows programming in C, using Visual C++. Rendering my scene on screen works beautifully, but I can’t print at all, and the OpenGL Superbible by R.S.Wright is not quite clear on the subject.
This is the beginning of my printing function (Superbible p. 599):

BOOL GL_PrintLocal(HDC hdc)
HDC hdcImpr;
BITMAPINFO bmapinfo;
HBITMAP bitmap;
GLubyte *bits; // etc

hdcImpr = CreateCompatibleDC (NULL);
memset (&bmapinfo, 0, sizeof (bmapinfo));
bmapinfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bmapinfo.bmiHeader.biWidth = 300;
bmapinfo.bmiHeader.biHeight = 450;
bmapinfo.bmiHeader.biPlanes = 1;
bmapinfo.bmiHeader.biBitCount = BI_RGB;
bitmap = CreateDIBSection (hdcImpr, &bmapinfo, DIB_RGB_COLORS, &bits, NULL, 0);
// etc
At this point, CreateDIBSection returns NULL.
Am I on the wrong track ? Any simple method to have my program produce a hardcopy (no PrintScreen please) ? Thanks.

I don’t know if it will solve the problem but here is what I am using (which works) :

myBitmapInfo->bmiHeader.biSize = sizeof(myBitmapInfo->bmiHeader);
myBitmapInfo->bmiHeader.biWidth = BitmapWidth;
myBitmapInfo->bmiHeader.biHeight = BitmapHeight;
myBitmapInfo->bmiHeader.biPlanes = 1;
myBitmapInfo->bmiHeader.biBitCount = N_Color_Bits;
myBitmapInfo->bmiHeader.biCompression = BI_RGB;
myBitmapInfo->bmiHeader.biSizeImage = BitmapWidthBitmapHeightN_Color_Bits/8;

As you see, I do not affect BI_RGB to biBitCount but to biCompression. The value of biBitCount is either 16 or 32 (depending on the resolution I am using). Next, I fill in the biSizeImage field.

Try that and tell us if it works !

Regards.

Eric

Actually, you’ve got a couple problems.

First, biCompression should be set to BI_RGB and biBitCount should be set to your desired color depth.

Eric, I’ve got a question, how do you get away with a bitcount of 32? Are you storing the alpha channel too? Bitmaps don’t generally store that, and I’m surprised that software is actually displaying your bitmaps correctly.

Siwko

Thanks to Erik and to Siwko. I had the wrong value for the
BitmapInfo.bmiHeader.biCompression
due to miscopying that line from the OpenGL Superbible, which was OK.
This works, though it still needs some polishing (StretchBlt…):

BOOL GL_PrintLocal(HDC hdc)
{
HDC hdcImpr;
BITMAPINFO bmapinfo;
HBITMAP bitmap;
GLubyte *bits;
HGLRC hrc;
DWORD error;
BOOL bRet;
extern short int xExt, yExt;/////////////////

int iWidth = xExt;
int iHeight = yExt;
hdcImpr = CreateCompatibleDC (NULL);
memset (&bmapinfo, 0, sizeof (bmapinfo));
bmapinfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bmapinfo.bmiHeader.biWidth = iWidth;
bmapinfo.bmiHeader.biHeight = iHeight;
bmapinfo.bmiHeader.biPlanes = 1;
bmapinfo.bmiHeader.biBitCount = 24;
bmapinfo.bmiHeader.biCompression = BI_RGB;
bitmap = CreateDIBSection (hdcImpr, &bmapinfo, DIB_RGB_COLORS, &bits, NULL, 0);
SelectObject (hdcImpr, bitmap);
if (!SetupPixelFormat(hdcImpr, 0)) 
	return FALSE;
hrc = wglCreateContext(hdcImpr);
wglMakeCurrent(hdcImpr, hrc);
Perspective (iWidth / (float)iHeight); // calls gluPerspective()
GL_DrawScene();
StretchBlt(hdc, 0, 0, 700, 800, hdcImpr, 0, 0, iWidth, iHeight, SRCCOPY);
GL_DestroyDC(hdcImpr);
DeleteObject (bitmap);
DeleteDC (hdcImpr);
return TRUE;

}

Siwko,

You are right : I never thought that the alpha channel was useless when printing… Nevertheless, I did never notice any problem with my prints…

PART 2 : just after having written the lines above, I had a look at the documentation. Here is what I found :

From MSDN :
"biBitCount=32 : The bitmap has a maximum of 2^32 colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member is NULL. Each DWORD in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The bmiColors color table is used for optimizing colors used on palette-based devices, and must contain the number of entries specified by the biClrUsed member of the BITMAPINFOHEADER. "

The important thing is : “The high byte in each DWORD is not used”.

Well, it is useless to store the alpha channel but it is ignored anyway : that’s why I have a correct print (I guess !).

Regards.

Eric

Originally posted by Eric:
Well, it is useless to store the alpha channel but it is ignored anyway : that’s why I have a correct print (I guess !).
[/b]

I would just be concerned, because with little modification you can use that to store the bitmap to disk as a bmp. Depending on how an app opens it (IE mspaint, PSP, Photoshop, etc), it may have trouble if they’re not conforming to “Microsoft” specs on that.

Thats all I was trying to convey, and now that you mention it, I’m thinking a bit-width of 32 may be a decent way of doing it, as the width of the image must be divisible by 4 bytes anyways, instead of padding at the end, you’re padding each triple.

Cool idea!

Siwko

Originally posted by André:
Thanks to Erik and to Siwko. I had the wrong value for the
BitmapInfo.bmiHeader.biCompression
due to miscopying that line from the OpenGL Superbible, which was OK.
This works, though it still needs some polishing (StretchBlt…):

Cool, glad you’ve got it working. From my personal tests, I feel that I should blurt here.

If you grab the DeviceCaps of the printer for both horizontal and vertical resolution, and render to the DIB with a width and height of horiz/2 and vert/2 from the device caps, then stretchblt both dimensions * 2, I’ve noticed the quality is very good (not too many jaggies anywhere), and at 600dpi color print, full “screen (page)” takes 1.7meg. If you try to divide down smaller, the jaggies are more pronounced when you stretchblt back up.

Also, if you’re only trying to print a thumbnail or 3x5 size, etc, 1:1 isn’t half bad, as it gives you the resolution of the printer without too much size overhead. In this case you’d bitblt.

Just adding my 2 cents here.

Siwko