Couldn't create HBITMAP from glReadpixels

119 Views Asked by At

So here's a part of my code, what I'm trying to do is to make a HBITMAP from a OpenGl frame capture.

unsigned char *output = 0;
output = new unsigned char[WINDOW_WIDTH * WINDOW_HEIGHT * 3];

glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE,
    output);

HBITMAP hdm = CreateBitmap(800, 800, 1, 32, output);

But my (HBITMAP)hdm is always NULL. Maybe there's another way to do that or what's wrong? I guess CreateBitmap would allocate memory itself, so the mistake must not be here. The output array seems to be fine though.

I've also tried the code from here: Creating a HBITMAP from glReadPixels but it didn't work as well, still getting NULL.

Would appreciate any help with this!

1

There are 1 best solutions below

0
On

The 4th parameter of CreateBitmap is the number of bits required to identify the color of a single pixel.

Since the format of the pixel data is GL_RGB, the 3rd paramter of CreateBitmap has be 24 instead of 32. Note GL_RGB/GL_UNSIGNED_BYTE means 3 color components with each a byte, which leads to 24 bits:

HBITMAP hdm = CreateBitmap(WINDOW_WIDTH, WINDOW_HEIGHT, 1, 24, output);

Or you have to use the GL_RGBA format:

unsigned char *output = new unsigned char[WINDOW_WIDTH * WINDOW_HEIGHT * 4];
glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, output);

HBITMAP hdm = CreateBitmap(WINDOW_WIDTH, WINDOW_HEIGHT, 1, 32, output);


Note, If you use the GL_RGB format, you have to consider that CreateBitmap requires each scan line be word aligned.
The alignmnet for the glReadPixels operation can be set by glPixelStorei, by setting the parameter GL_PACK_ALIGNMENT, which is by default 4, so this should not be an issue.
But you have to ensure that the dynamically allocated buffer is large enough:

size_t bpl = WINDOW_WIDTH * 3; // bytes per line
size_t r   = bpl % 4;          // rest of division by 4
bpl       += r ? (4-r) : 0;    // bytes per line aligned to 4
unsigned char *output = new unsigned char[bpl * WINDOW_HEIGHT];

or

size_t bpl = (WINDOW_WIDTH * 3 + 3) & ~3;
unsigned char *output = new unsigned char[bpl * WINDOW_HEIGHT];