how to write an imagefile of a current glutwindow?

Hello,

I have two problems, the first is, that I’am a beginner in OpenGL and I have to learn it for my diploma thesis as physicist!

My tasks are to improve a programm, written in C++ and OpenGL, that reads measured data and simulate a watersurface of this data. The program also use the glut-library to create a window.

The problem is, that I have to implement a possibility to write each frame of the animation in an bmp- or tiff-… file, so one can build a avi or something else of this images with a suitable other program!

My question is: is there anybody who can tell me a way to solve this problem or can give me information that can be useful for me, to write each rendered image of my glutwindow into an bitmap-file for example.

Sorry for my bad english and thanks for any help!

If you’re rendering to the screen, double-buffering, and haven’t swapped buffers yet:


  glPixelStorei( GL_PACK_ALIGNMENT, 1 );
  glReadBuffer ( GL_FRONT ) ;
  glReadPixels( 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
  glReadBuffer ( GL_BACK ) ;

If you’re not double-buffering, just whack the glReadBuffer calls.

That’ll get you an RGB8 image in memory (RGBRGBBRGB…) in scanline order. Of course, buffer needs to be preallocated to be at least widthheight3 bytes.

Then use some free image library like libtiff, libpng, libgif, libjpeg, etc. to write it to your favorite format.

eeeek why would you want to read from front with double buffering ?
I never needed those glReadBuffer calls for a gl screenshot.

@dark photon:

Here the code to display the wave surface:

//here the wave is drawn in strips along the x axis
  for (int i = 0; i < yRes - 1; ++i)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int j = 0; j < xRes; ++j)
		{
	  //draw two points at (x,y) = (j,i) and (x,y) = (j+1,i)
	  //std::cout << height[i*xRes+j] << std::endl;
      setColor(i * xRes + j);
			//normal vector for the given slope values
			//will be normalized automatically
      glNormal3f( - slopeX[i * xRes + j],
                  - slopeY[i * xRes + j],
                 1.0);
			//point at (x,y) = (j,i)
			glVertex3f(j, i, height[i * xRes + j]);

      setColor((i+1) * xRes + j);
      glNormal3f( - slopeX[(i+1) * xRes + j],
                  - slopeY[(i+1) * xRes + j],
                 1.0);
			//point at (x,y) = (j+1,i)
			glVertex3f(j, (i+1), height[(i+1) * xRes + j]);		}
		glEnd();
	}

and after that I call:



	glFlush();
	glutSwapBuffers();

Now I have to put your code snippet before I call glFlush(); and glutSwapBuffers(); ? If that is correct, can you tell me again what I have to do after that? I don’t understand what you meant with scanline order and what is to do in preallocating?

Thanks for yor help again

At the moment I do this:

int WIDTH = glutGet(GLUT_WINDOW_WIDTH);
	int HEIGTH = glutGet(GLUT_WINDOW_HEIGHT);
	const int BIT_R = sizeof(float);
	const int BIT_G = sizeof(float);
	const int BIT_B = sizeof(float);
	const int BIT_A = sizeof(float);

	glDrawBuffer(GL_BACK);

render();

glReadBuffer(GL_BACK);
	GLvoid *imageData = malloc(WIDTH*HEIGHT*(BIT_R+BIT_G+BIT_B+BIT_A));
	glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

	glFlush();
	glutSwapBuffers();

compilation works fine, but I don’t know what to do now. How can I store the image?

After the glReadPixels call, the image is stored at the imageData location.
Use whatever image library to write this raw binary data to a file on disk, as said Dark Photon : “like libtiff, libpng, libgif, libjpeg, etc”

… or simply store it directly as .raw format if you have tools able to read it with a manually specified size and format.

Ok, 1000 thanks for your help, your hints was very useful! For the other with a similar problem my code looks now like this and works fine:

I used the DevIL image library and include:

#include <IL/il.h>
#pragma comment( lib, “DevIL.lib” )


float WIDTH = glutGet(GLUT_WINDOW_WIDTH);
float HEIGHT = glutGet(GLUT_WINDOW_HEIGHT);
float BIT_R = sizeof(float);
float BIT_G = sizeof(float);
float BIT_B = sizeof(float);
float BIT_A = sizeof(float);

renderScene();

unsigned char* imageData = (unsigned char*)malloc((int)(WIDTH*HEIGHT*(BIT_R+BIT_G+BIT_B+BIT_A)));
	glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_FLOAT, imageData);


	ilInit(); 
	ILuint imageID = ilGenImage() ;
	ilBindImage( imageID );
	
	ilTexImage(WIDTH, HEIGHT, 1, 4, IL_RGBA, IL_FLOAT, imageData ) ;
	

	ilSave( IL_JPG, "output.jpg" ) ;

free(imageData);

Just depends on where in the frame you want to eat the readback time from.

You can read FRONT after drawing before SwapBuffers and eat it from the end of the current frame, or read BACK after SwapBuffers before clear/draw for the next frame and eat it from the beginnning of the next.

When using AA, a pro for the latter is you pay for the downsample only once.