CImg does not interleave its colors. That is, 3 red, green, blue pixels would be stored linearly as:
R1, R2, R3, ..., G1, G2, G3, ..., B1, B2, B3, ...
However, OpenGL's glReadPixel and glDrawPixel expect interleaved color components like this:
R1, G1, B1, R2, G2, B2, ...
Additionally, OpenGL puts the origin (0,0) at the lower left corner of an image. CImg uses the more approach where the origin is at the top left of the image.
Here is a routine I wrote convert the interleaved colors to CImg's channel-oriented format.
void convertToNonInterleaved(int w, int h, unsigned char* tangled, unsigned char* untangled) {
//Take string in format R1 G1 B1 R2 G2 B2... and re-write it
//in the format format R1 R2 G1 G2 B1 B2...
//Assume 8 bit values for red, green and blue color channels.
//Assume there are no other channels
//tangled is a pointer to the input string and untangled
//is a pointer to the output string. This method assumes that
//memory has already been allocated for the output string.
int numPixels = w*h;
int numColors = 3;
for(int i=0; i<numPixels; ++i) {
int indexIntoInterleavedTuple = numColors*i;
//Red
untangled[i] = tangled[indexIntoInterleavedTuple];
//Green
untangled[numPixels+i] = tangled[indexIntoInterleavedTuple+1];
//Blue
untangled[2*numPixels+i] = tangled[indexIntoInterleavedTuple+2];
}
}
I should have probably added the code to account for the change in origin, but I felt lazy and decided to use CImg to do that. Once this routine is run, this code creates the image object:
unsigned char* p = (unsigned char *)malloc(bytes);
convertToNonInterleaved(width, height, buffer, p);
CImg<unsigned char> img(p, width, height,1,3);
free(p);
img.mirror('y');
CImgDisplay main_disp(img,"Snapshot");
while (!main_disp.is_closed() ) {
main_disp.wait();
}
And as far as I can tell, I do not have to set any packing parameters. Here is the code I use to grab the pixels from the OpenGL render target:
bytes = width*height*3; //Color space is RGB
if(buffer)
free(buffer);
buffer = (GLubyte *)malloc(bytes);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);