3 * This program demonstrates how to do "off-screen" rendering using
4 * the GLX pixel buffer extension.
6 * Written by Brian Paul for the "OpenGL and Window System Integration"
7 * course presented at SIGGRAPH '97. Updated on 5 October 2002.
9 * Updated on 31 January 2004 to use native GLX by
10 * Andrew P. Lentvorski, Jr. <bsder@allcaps.org>
13 * glxpbdemo width height imgfile
15 * width is the width, in pixels, of the image to generate.
16 * height is the height, in pixels, of the image to generate.
17 * imgfile is the name of the PPM image file to write.
20 * This demo draws 3-D boxes with random orientation.
22 * On machines such as the SGI Indigo you may have to reconfigure your
23 * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
24 * directory for display configurations with the _pbuf suffix. Use
25 * setmon -x <vof> to configure your X server and display for pbuffers.
27 * O2 systems seem to support pbuffers well.
37 /* Some ugly global vars */
38 static GLXFBConfig gFBconfig
= 0;
39 static Display
*gDpy
= NULL
;
40 static int gScreen
= 0;
41 static GLXPbuffer gPBuffer
= 0;
42 static int gWidth
, gHeight
;
46 * Test for appropriate version of GLX to run this program
47 * Input: dpy - the X display
48 * screen - screen number
49 * Return: 0 = GLX not available.
53 RuntimeQueryGLXVersion(Display
*dpy
, int screen
)
55 #if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
58 glxversion
= (char *) glXGetClientString(dpy
, GLX_VERSION
);
59 if (!(strstr(glxversion
, "1.3") || strstr(glxversion
, "1.4")))
62 glxversion
= (char *) glXQueryServerString(dpy
, screen
, GLX_VERSION
);
63 if (!(strstr(glxversion
, "1.3") || strstr(glxversion
, "1.4")))
75 * Create the pbuffer and return a GLXPbuffer handle.
78 MakePbuffer( Display
*dpy
, int screen
, int width
, int height
)
80 GLXFBConfig
*fbConfigs
;
81 GLXFBConfig chosenFBConfig
;
82 GLXPbuffer pBuffer
= None
;
88 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
90 GLX_DRAWABLE_TYPE
, GLX_PIXMAP_BIT
| GLX_PBUFFER_BIT
,
96 GLX_PBUFFER_HEIGHT
, 0,
97 GLX_LARGEST_PBUFFER
, False
,
98 GLX_PRESERVED_CONTENTS
, False
,
102 pbAttribs
[1] = width
;
103 pbAttribs
[3] = height
;
105 fbConfigs
= glXChooseFBConfig(dpy
, screen
, fbAttribs
, &nConfigs
);
107 if (0 == nConfigs
|| !fbConfigs
) {
108 printf("Error: glxChooseFBConfig failed\n");
113 chosenFBConfig
= fbConfigs
[0];
115 glXGetFBConfigAttrib(dpy
, chosenFBConfig
, GLX_FBCONFIG_ID
, &fbconfigid
);
116 printf("Chose 0x%x as fbconfigid\n", fbconfigid
);
118 /* Create the pbuffer using first fbConfig in the list that works. */
119 pBuffer
= glXCreatePbuffer(dpy
, chosenFBConfig
, pbAttribs
);
122 gFBconfig
= chosenFBConfig
;
135 * Do all the X / GLX setup stuff.
138 Setup(int width
, int height
)
140 #if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
143 /* Open the X display */
144 gDpy
= XOpenDisplay(NULL
);
146 printf("Error: couldn't open default X display.\n");
150 /* Get default screen */
151 gScreen
= DefaultScreen(gDpy
);
153 /* Test that GLX is available */
154 if (!RuntimeQueryGLXVersion(gDpy
, gScreen
)) {
155 printf("Error: GLX 1.3 or 1.4 not available\n");
161 gPBuffer
= MakePbuffer( gDpy
, gScreen
, width
, height
);
162 if (gPBuffer
==None
) {
163 printf("Error: couldn't create pbuffer\n");
168 /* Create GLX context */
169 glCtx
= glXCreateNewContext(gDpy
, gFBconfig
, GLX_RGBA_TYPE
, NULL
, True
);
171 if (!glXIsDirect(gDpy
, glCtx
)) {
172 printf("Warning: using indirect GLXContext\n");
176 printf("Error: Couldn't create GLXContext\n");
181 /* Bind context to pbuffer */
182 if (!glXMakeCurrent(gDpy
, gPBuffer
, glCtx
)) {
183 printf("Error: glXMakeCurrent failed\n");
188 return 1; /* Success!! */
190 printf("Error: GLX version 1.3 or 1.4 not available at compile time\n");
197 /* One-time GL setup */
201 static GLfloat pos
[4] = {0.0, 0.0, 10.0, 0.0};
202 glEnable(GL_LIGHTING
);
204 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
205 glEnable(GL_NORMALIZE
);
206 glEnable(GL_DEPTH_TEST
);
207 glEnable(GL_CULL_FACE
);
209 glViewport(0, 0, gWidth
, gHeight
);
210 glMatrixMode( GL_PROJECTION
);
212 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
213 glMatrixMode( GL_MODELVIEW
);
215 glTranslatef( 0.0, 0.0, -15.0 );
220 /* Return random float in [0,1] */
225 return (float) (i
% 1000) / 1000.0;
237 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, c
);
241 /* This function borrowed from Mark Kilgard's GLUT */
243 drawBox(GLfloat x0
, GLfloat x1
, GLfloat y0
, GLfloat y1
,
244 GLfloat z0
, GLfloat z1
, GLenum type
)
246 static GLfloat n
[6][3] =
255 static GLint faces
[6][4] =
264 GLfloat v
[8][3], tmp
;
282 v
[0][0] = v
[1][0] = v
[2][0] = v
[3][0] = x0
;
283 v
[4][0] = v
[5][0] = v
[6][0] = v
[7][0] = x1
;
284 v
[0][1] = v
[1][1] = v
[4][1] = v
[5][1] = y0
;
285 v
[2][1] = v
[3][1] = v
[6][1] = v
[7][1] = y1
;
286 v
[0][2] = v
[3][2] = v
[4][2] = v
[7][2] = z0
;
287 v
[1][2] = v
[2][2] = v
[5][2] = v
[6][2] = z1
;
289 for (i
= 0; i
< 6; i
++) {
291 glNormal3fv(&n
[i
][0]);
292 glVertex3fv(&v
[faces
[i
][0]][0]);
293 glVertex3fv(&v
[faces
[i
][1]][0]);
294 glVertex3fv(&v
[faces
[i
][2]][0]);
295 glVertex3fv(&v
[faces
[i
][3]][0]);
310 glClearColor(0.2, 0.2, 0.9, 0.0);
311 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
313 for (i
=0;i
<NumBoxes
;i
++) {
314 float tx
= -2.0 + 4.0 * Random();
315 float ty
= -2.0 + 4.0 * Random();
316 float tz
= 4.0 - 16.0 * Random();
317 float sx
= 0.1 + Random() * 0.4;
318 float sy
= 0.1 + Random() * 0.4;
319 float sz
= 0.1 + Random() * 0.4;
323 float ra
= Random() * 360.0;
325 glTranslatef(tx
, ty
, tz
);
326 glRotatef(ra
, rx
, ry
, rz
);
327 glScalef(sx
, sy
, sz
);
329 drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON
);
339 WriteFile(const char *filename
)
345 image
= malloc(gWidth
* gHeight
* 3 * sizeof(GLubyte
));
347 printf("Error: couldn't allocate image buffer\n");
351 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
352 glReadPixels(0, 0, gWidth
, gHeight
, GL_RGB
, GL_UNSIGNED_BYTE
, image
);
354 f
= fopen(filename
, "w");
356 printf("Couldn't open image file: %s\n", filename
);
360 fprintf(f
,"# ppm-file created by %s\n", "trdemo2");
361 fprintf(f
,"%i %i\n", gWidth
, gHeight
);
364 f
= fopen(filename
, "ab"); /* now append binary data */
366 printf("Couldn't append to image file: %s\n", filename
);
370 for (i
=0;i
<gHeight
;i
++) {
372 /* Remember, OpenGL images are bottom to top. Have to reverse. */
373 rowPtr
= image
+ (gHeight
-1-i
) * gWidth
*3;
374 fwrite(rowPtr
, 1, gWidth
*3, f
);
380 printf("Wrote %d by %d image file: %s\n", gWidth
, gHeight
, filename
);
386 * Print message describing command line parameters.
389 Usage(const char *appName
)
392 printf(" %s width height imgfile\n", appName
);
393 printf("Where imgfile is a ppm file\n");
399 main(int argc
, char *argv
[])
405 int width
= atoi(argv
[1]);
406 int height
= atoi(argv
[2]);
407 char *fileName
= argv
[3];
409 printf("Error: width parameter must be at least 1.\n");
413 printf("Error: height parameter must be at least 1.\n");
416 if (!Setup(width
, height
)) {
420 printf("Setup completed\n");
422 printf("Render completed.\n");
424 printf("File write completed.\n");
426 glXDestroyPbuffer( gDpy
, gPBuffer
);