PDA

View Full Version : Saving Framebuffer as BMP



Mathias Brito
11-29-2005, 08:30 PM
I wrote a simple code, that draws a triangle in the screen, and i can move this triangle using the directional keys and rotate it with F1 and F2. So, i wrote also a function that reads the framebuffer and generates a bmp image. Problem: i get the bmp image just fine, but only with the background, the object, in this case the triangle, doesn't appear in the bmp created, someone can help me with this issue!? Here is the code: Due to a problem with alignment of the structure i was forced to use a feature of the gnu compiler, to compile with another one you should use the similar solotion from your compiler for this problem, it is the __attribute__((packed)) at the end of the structure declaration.

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>

#define X 0
#define Y 1
#define WIDTH 500
#define HEIGHT 500
#define BMP_HEADER_SIZE 54

struct BMP_HEADER {
short int type; /* Magic identifier */
int size; /* File size in bytes */
short int reserved1, reserved2;
int offset; /* Offset to image data, bytes */
int headerSize; /* Header size in bytes */
int width,height; /* Width and height of image */
short int planes; /* Number of colour planes */
short int bits; /* Bits per pixel */
int compression; /* Compression type */
int imagesize; /* Image size in bytes */
int xresolution,yresolution; /* Pixels per meter */
int ncolours; /* Number of colours */
int importantcolours; /* Important colours */
}__attribute__((packed)); /* gcc solution for alignment problem */

void draw();
void saveBuffer();
void drawTriangle();
void specialKeys(GLint, GLint, GLint);

int vTriangles[2] = {0, 0}; //keep triangles first vertexs values

int main(int argc, char *argv[]) {
glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize( WIDTH, HEIGHT );
glutCreateWindow("Saving Buffer...");
glClearColor(0.5, 0.5 , 0.5 , 0.0);
gluOrtho2D(0, WIDTH , 0, HEIGHT );

glutSpecialFunc(specialKeys);
glutDisplayFunc(draw);
glutMainLoop();

return 0;
}

void specialKeys(GLint key, GLint x, GLint y) {
switch(key) {
case GLUT_KEY_UP:
glTranslatef(0, 1, 0);
vTriangles[Y]++;
break;
case GLUT_KEY_DOWN:
glTranslatef(0, -1, 0);
vTriangles[Y]--;
break;
case GLUT_KEY_RIGHT:
glTranslatef(1, 0, 0);
vTriangles[X]++;
break;
case GLUT_KEY_LEFT:
glTranslatef(-1, 0, 0);
vTriangles[X]++;
break;
case GLUT_KEY_F1:
glTranslatef(vTriangles[X] * (-1), vTriangles[Y] * (-1), 0);
glRotatef(20, 0, 0, 1);
glTranslatef(vTriangles[X], vTriangles[Y], 0);
break;
case GLUT_KEY_F2:
glTranslatef(vTriangles[X] * (-1), vTriangles[Y] * (-1), 0);
glRotatef(-20, 0, 0, 1);
glTranslatef(vTriangles[X], vTriangles[Y], 0);
break;
}
glClear(GL_COLOR_BUFFER_BIT);
draw();
saveBuffer();
glFlush();
}

void draw() {
glColor3f(1.0, 0.0, 0.0);
drawTriangle();
glFlush();
}

void drawTriangle() {
glBegin(GL_TRIANGLES);
glVertex2f(250,250);
glVertex2f(300,300);
glVertex2f(300,250);
glEnd();
}

/* Saves the Buffer as an BMP image */
void saveBuffer() {
static GLint count = 0; //used to increment the number in filename
GLbyte fileName[32];
GLubyte *bmp;
GLubyte *data;
FILE *file;
struct BMP_HEADER *hdr;
GLint headerSize = sizeof(struct BMP_HEADER);

/* get memory, 54 bytes for the BMP header and
* 3(R G B) * WIDTH * HEIGHT bytes for data
*/
bmp = malloc( (headerSize + ( 3 * WIDTH * HEIGHT )) * sizeof(GLubyte) );

hdr = (struct BMP_HEADER *) bmp;
memset(hdr, 0, headerSize);
data = (GLubyte *) bmp + headerSize;

/* fill the header */
hdr->type = 19778;
hdr->size = (( headerSize + (3 * WIDTH * HEIGHT) ) * sizeof(GLubyte));
hdr->reserved1 = 0;
hdr->reserved2 = 0;
hdr->offset = headerSize;
hdr->headerSize = headerSize;
hdr->width = 500;
hdr->height = 500;
hdr->planes = 1;
hdr->bits = 8;
hdr->compression = 0;
hdr->imagesize = 0;
hdr->xresolution = 0;
hdr->yresolution = 0;
hdr->ncolours = 0;
hdr->importantcolours = 0;

sprintf(fileName,"image%i.bmp", count);

file = fopen(fileName, "w");

glPixelStorei(GL_PACK_ALIGNMENT,1);
glReadBuffer(GL_FRONT);
if( glGetError() == GL_INVALID_OPERATION) /* the display is single buffered */
printf("Error setting FRAMEBUFFER\n");

glReadPixels(0,0,WIDTH,HEIGHT,GL_RGB,GL_UNSIGNED_B YTE,data);
if( glGetError() != GL_NO_ERROR)
printf("Unknown error Reading Pixels\n");

fwrite(hdr, headerSize, 1, file); /* write bmp header */
fwrite(data, ( 3 * WIDTH * HEIGHT ), 1, file); /* write bmp pixels */

fclose(file);
free(bmp);

count++;
}