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)
141 XVisualInfo
*visInfo
;
144 /* Open the X display */
145 gDpy
= XOpenDisplay(NULL
);
147 printf("Error: couldn't open default X display.\n");
151 /* Get default screen */
152 gScreen
= DefaultScreen(gDpy
);
154 /* Test that GLX is available */
155 if (!RuntimeQueryGLXVersion(gDpy
, gScreen
)) {
156 printf("Error: GLX 1.3 or 1.4 not available\n");
162 gPBuffer
= MakePbuffer( gDpy
, gScreen
, width
, height
);
163 if (gPBuffer
==None
) {
164 printf("Error: couldn't create pbuffer\n");
169 /* Create GLX context */
170 glCtx
= glXCreateNewContext(gDpy
, gFBconfig
, GLX_RGBA_TYPE
, NULL
, True
);
172 if (!glXIsDirect(gDpy
, glCtx
)) {
173 printf("Warning: using indirect GLXContext\n");
177 printf("Error: Couldn't create GLXContext\n");
183 /* Bind context to pbuffer */
184 if (!glXMakeCurrent(gDpy
, gPBuffer
, glCtx
)) {
185 printf("Error: glXMakeCurrent failed\n");
191 return 1; /* Success!! */
193 printf("Error: GLX version 1.3 or 1.4 not available at compile time\n");
200 /* One-time GL setup */
204 static GLfloat pos
[4] = {0.0, 0.0, 10.0, 0.0};
205 glEnable(GL_LIGHTING
);
207 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
208 glEnable(GL_NORMALIZE
);
209 glEnable(GL_DEPTH_TEST
);
210 glEnable(GL_CULL_FACE
);
212 glViewport(0, 0, gWidth
, gHeight
);
213 glMatrixMode( GL_PROJECTION
);
215 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
216 glMatrixMode( GL_MODELVIEW
);
218 glTranslatef( 0.0, 0.0, -15.0 );
223 /* Return random float in [0,1] */
228 return (float) (i
% 1000) / 1000.0;
240 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, c
);
244 /* This function borrowed from Mark Kilgard's GLUT */
246 drawBox(GLfloat x0
, GLfloat x1
, GLfloat y0
, GLfloat y1
,
247 GLfloat z0
, GLfloat z1
, GLenum type
)
249 static GLfloat n
[6][3] =
258 static GLint faces
[6][4] =
267 GLfloat v
[8][3], tmp
;
285 v
[0][0] = v
[1][0] = v
[2][0] = v
[3][0] = x0
;
286 v
[4][0] = v
[5][0] = v
[6][0] = v
[7][0] = x1
;
287 v
[0][1] = v
[1][1] = v
[4][1] = v
[5][1] = y0
;
288 v
[2][1] = v
[3][1] = v
[6][1] = v
[7][1] = y1
;
289 v
[0][2] = v
[3][2] = v
[4][2] = v
[7][2] = z0
;
290 v
[1][2] = v
[2][2] = v
[5][2] = v
[6][2] = z1
;
292 for (i
= 0; i
< 6; i
++) {
294 glNormal3fv(&n
[i
][0]);
295 glVertex3fv(&v
[faces
[i
][0]][0]);
296 glVertex3fv(&v
[faces
[i
][1]][0]);
297 glVertex3fv(&v
[faces
[i
][2]][0]);
298 glVertex3fv(&v
[faces
[i
][3]][0]);
313 glClearColor(0.2, 0.2, 0.9, 0.0);
314 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
316 for (i
=0;i
<NumBoxes
;i
++) {
317 float tx
= -2.0 + 4.0 * Random();
318 float ty
= -2.0 + 4.0 * Random();
319 float tz
= 4.0 - 16.0 * Random();
320 float sx
= 0.1 + Random() * 0.4;
321 float sy
= 0.1 + Random() * 0.4;
322 float sz
= 0.1 + Random() * 0.4;
326 float ra
= Random() * 360.0;
328 glTranslatef(tx
, ty
, tz
);
329 glRotatef(ra
, rx
, ry
, rz
);
330 glScalef(sx
, sy
, sz
);
332 drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON
);
342 WriteFile(const char *filename
)
348 image
= malloc(gWidth
* gHeight
* 3 * sizeof(GLubyte
));
350 printf("Error: couldn't allocate image buffer\n");
354 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
355 glReadPixels(0, 0, gWidth
, gHeight
, GL_RGB
, GL_UNSIGNED_BYTE
, image
);
357 f
= fopen(filename
, "w");
359 printf("Couldn't open image file: %s\n", filename
);
363 fprintf(f
,"# ppm-file created by %s\n", "trdemo2");
364 fprintf(f
,"%i %i\n", gWidth
, gHeight
);
367 f
= fopen(filename
, "ab"); /* now append binary data */
369 printf("Couldn't append to image file: %s\n", filename
);
373 for (i
=0;i
<gHeight
;i
++) {
375 /* Remember, OpenGL images are bottom to top. Have to reverse. */
376 rowPtr
= image
+ (gHeight
-1-i
) * gWidth
*3;
377 fwrite(rowPtr
, 1, gWidth
*3, f
);
383 printf("Wrote %d by %d image file: %s\n", gWidth
, gHeight
, filename
);
389 * Print message describing command line parameters.
392 Usage(const char *appName
)
395 printf(" %s width height imgfile\n", appName
);
396 printf("Where imgfile is a ppm file\n");
402 main(int argc
, char *argv
[])
408 int width
= atoi(argv
[1]);
409 int height
= atoi(argv
[2]);
410 char *fileName
= argv
[3];
412 printf("Error: width parameter must be at least 1.\n");
416 printf("Error: height parameter must be at least 1.\n");
419 if (!Setup(width
, height
)) {
423 printf("Setup completed\n");
425 printf("Render completed.\n");
427 printf("File write completed.\n");
429 glXDestroyPbuffer( gDpy
, gPBuffer
);