1313#include <GL/glext.h>
1414
1515enum Constants { SCREENSHOT_MAX_FILENAME = 256 };
16- static const char * SCREENSHOT_FILENAME_PREFIX = "tmp" ;
1716static GLubyte * pixels = NULL ;
1817static GLuint fbo ;
1918static GLuint rbo_color ;
@@ -23,25 +22,37 @@ static const GLuint FORMAT_NBYTES = 4;
2322static const unsigned int HEIGHT = 100 ;
2423static const unsigned int WIDTH = 100 ;
2524static int offscreen = 1 ;
26- static unsigned int time0 ;
2725static unsigned int max_nframes = 100 ;
2826static unsigned int nframes = 0 ;
27+ static unsigned int time0 ;
2928
3029/* Model. */
3130static double angle ;
3231static double delta_angle ;
3332
33+ /*
34+ Take screenshot with glReadPixels and save to a file in PPM format.
35+ - filename: file path to save to, without extension
36+ - width: screen width in pixels
37+ - height: screen height in pixels
38+ - format: glReadPixelsFormat
39+ - format_nbytes: number of bytes per pixel. This is implied by format,
40+ but we haven't found a built-in way to get this information automatically.
41+ - pixels: intermediate buffer to avoid repeated mallocs across multiple calls.
42+ Contents of this buffer do not matter.
43+ May be NULL, in which case it is initialized.
44+ You must `free` it when you won't be calling this function anymore.
45+ */
3446static void screenshot_ppm (const char * filename , unsigned int width , unsigned int height ,
35- GLenum format , unsigned int pixel_nbytes , GLubyte * * pixels ) {
47+ GLenum format , unsigned int format_nbytes , GLubyte * * pixels ) {
3648 size_t i , j , k , cur ;
37- if (* pixels == NULL )
38- (* pixels ) = malloc (pixel_nbytes * width * height );
39- glReadPixels (0 , 0 , width , height , format , GL_UNSIGNED_BYTE , pixels );
4049 FILE * f = fopen (filename , "w" );
4150 fprintf (f , "P3\n%d %d\n%d\n" , width , height , 255 );
51+ * pixels = realloc (* pixels , format_nbytes * width * height );
52+ glReadPixels (0 , 0 , width , height , format , GL_UNSIGNED_BYTE , * pixels );
4253 for (i = 0 ; i < height ; i ++ ) {
4354 for (j = 0 ; j < width ; j ++ ) {
44- cur = pixel_nbytes * ( ((height - i - 1 ) * width + j );
55+ cur = format_nbytes * ((height - i - 1 ) * width + j );
4556 fprintf (f , "%3d %3d %3d " , (* pixels )[cur ], (* pixels )[cur + 1 ], (* pixels )[cur + 2 ]);
4657 }
4758 fprintf (f , "\n" );
@@ -113,7 +124,7 @@ static void deinit(void) {
113124 }
114125}
115126
116- static void draw_scene () {
127+ static void draw_scene (void ) {
117128 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
118129 glLoadIdentity ();
119130 glRotatef (angle , 0.0f , 0.0f , -1.0f );
@@ -135,14 +146,10 @@ static void display(void) {
135146 } else {
136147 glutSwapBuffers ();
137148 }
138- assert (
139- snprintf (filename , SCREENSHOT_MAX_FILENAME , "%s%d.ppm" ,
140- SCREENSHOT_FILENAME_PREFIX , nframes )
141- < SCREENSHOT_MAX_FILENAME
142- );
149+ snprintf (filename , SCREENSHOT_MAX_FILENAME , "tmp%d.ppm" , nframes );
143150 screenshot_ppm (filename , WIDTH , HEIGHT , FORMAT , FORMAT_NBYTES , & pixels );
144151 nframes ++ ;
145- if (nframes >= max_nframes )
152+ if (nframes > max_nframes )
146153 exit (EXIT_SUCCESS );
147154}
148155
0 commit comments