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.
10 * pbuffers width height imgfile
12 * width is the width, in pixels, of the image to generate.
13 * height is the height, in pixels, of the image to generate.
14 * imgfile is the name of the PPM image file to write.
17 * This demo draws 3-D boxes with random orientation. A pbuffer with
18 * a depth (Z) buffer is prefered but if such a pbuffer can't be created
19 * we use a non-depth-buffered config.
21 * On machines such as the SGI Indigo you may have to reconfigure your
22 * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
23 * directory for display configurationswith the _pbuf suffix. Use
24 * setmon -x <vof> to configure your X server and display for pbuffers.
26 * O2 systems seem to support pbuffers well.
28 * IR systems (at least 1RM systems) don't have single-buffered, RGBA,
29 * Z-buffered pbuffer configs. BUT, they DO have DOUBLE-buffered, RGBA,
30 * Z-buffered pbuffers. Note how we try four different fbconfig attribute
43 /* Some ugly global vars */
44 static Display
*gDpy
= NULL
;
45 static int gScreen
= 0;
46 static FBCONFIG gFBconfig
= 0;
47 static PBUFFER gPBuffer
= 0;
48 static int gWidth
, gHeight
;
49 static GLXContext glCtx
;
54 * Create the pbuffer and return a GLXPbuffer handle.
56 * We loop over a list of fbconfigs trying to create
57 * a pixel buffer. We return the first pixel buffer which we successfully
61 MakePbuffer( Display
*dpy
, int screen
, int width
, int height
)
63 #define NUM_FB_CONFIGS 4
64 const char fbString
[NUM_FB_CONFIGS
][100] = {
65 "Single Buffered, depth buffer",
66 "Double Buffered, depth buffer",
67 "Single Buffered, no depth buffer",
68 "Double Buffered, no depth buffer"
70 int fbAttribs
[NUM_FB_CONFIGS
][100] = {
72 /* Single buffered, with depth buffer */
73 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
74 GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
,
84 /* Double buffered, with depth buffer */
85 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
86 GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
,
96 /* Single buffered, without depth buffer */
97 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
98 GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
,
108 /* Double buffered, without depth buffer */
109 GLX_RENDER_TYPE
, GLX_RGBA_BIT
,
110 GLX_DRAWABLE_TYPE
, GLX_PBUFFER_BIT
,
121 Bool preserve
= False
;
123 PBUFFER pBuffer
= None
;
128 for (attempt
=0; attempt
<NUM_FB_CONFIGS
; attempt
++) {
130 /* Get list of possible frame buffer configurations */
131 fbConfigs
= ChooseFBConfig(dpy
, screen
, fbAttribs
[attempt
], &nConfigs
);
132 if (nConfigs
==0 || !fbConfigs
) {
133 printf("Note: glXChooseFBConfig(%s) failed\n", fbString
[attempt
]);
139 for (i
=0;i
<nConfigs
;i
++) {
140 printf("Config %d\n", i
);
141 PrintFBConfigInfo(dpy
, screen
, fbConfigs
[i
], 0);
145 /* Create the pbuffer using first fbConfig in the list that works. */
146 for (i
=0;i
<nConfigs
;i
++) {
147 pBuffer
= CreatePbuffer(dpy
, screen
, fbConfigs
[i
], width
, height
, largest
, preserve
);
149 gFBconfig
= fbConfigs
[i
];
162 printf("Using: %s\n", fbString
[attempt
]);
168 #undef NUM_FB_CONFIGS
174 * Do all the X / GLX setup stuff.
177 Setup(int width
, int height
)
180 XVisualInfo
*visInfo
;
182 /* Open the X display */
183 gDpy
= XOpenDisplay(NULL
);
185 printf("Error: couldn't open default X display.\n");
189 /* Get default screen */
190 gScreen
= DefaultScreen(gDpy
);
192 /* Test that pbuffers are available */
193 pbSupport
= QueryPbuffers(gDpy
, gScreen
);
194 if (pbSupport
== 1) {
195 printf("Using GLX 1.3 Pbuffers\n");
197 else if (pbSupport
== 2) {
198 printf("Using SGIX Pbuffers\n");
201 printf("Error: pbuffers not available on this screen\n");
207 gPBuffer
= MakePbuffer( gDpy
, gScreen
, width
, height
);
208 if (gPBuffer
==None
) {
209 printf("Error: couldn't create pbuffer\n");
214 /* Test drawable queries */
217 glXQueryDrawable( gDpy
, gPBuffer
, GLX_WIDTH
, &v
);
218 printf("GLX_WIDTH = %u\n", v
);
219 glXQueryDrawable( gDpy
, gPBuffer
, GLX_HEIGHT
, &v
);
220 printf("GLX_HEIGHT = %u\n", v
);
221 glXQueryDrawable( gDpy
, gPBuffer
, GLX_PRESERVED_CONTENTS
, &v
);
222 printf("GLX_PRESERVED_CONTENTS = %u\n", v
);
223 glXQueryDrawable( gDpy
, gPBuffer
, GLX_LARGEST_PBUFFER
, &v
);
224 printf("GLX_LARGEST_PBUFFER = %u\n", v
);
225 glXQueryDrawable( gDpy
, gPBuffer
, GLX_FBCONFIG_ID
, &v
);
226 printf("GLX_FBCONFIG_ID = %u\n", v
);
229 /* Get corresponding XVisualInfo */
230 visInfo
= GetVisualFromFBConfig(gDpy
, gScreen
, gFBconfig
);
232 printf("Error: can't get XVisualInfo from FBconfig\n");
237 /* Create GLX context */
238 glCtx
= glXCreateContext(gDpy
, visInfo
, NULL
, True
);
241 glCtx
= glXCreateContext(gDpy
, visInfo
, NULL
, False
);
243 printf("Error: Couldn't create GLXContext\n");
249 printf("Warning: using indirect GLXContext\n");
253 /* Bind context to pbuffer */
254 if (!glXMakeCurrent(gDpy
, gPBuffer
, glCtx
)) {
255 printf("Error: glXMakeCurrent failed\n");
261 return 1; /* Success!! */
266 /* One-time GL setup */
270 static GLfloat pos
[4] = {0.0, 0.0, 10.0, 0.0};
271 glEnable(GL_LIGHTING
);
273 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
274 glEnable(GL_NORMALIZE
);
275 glEnable(GL_DEPTH_TEST
);
276 glEnable(GL_CULL_FACE
);
278 glViewport(0, 0, gWidth
, gHeight
);
279 glMatrixMode( GL_PROJECTION
);
281 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
282 glMatrixMode( GL_MODELVIEW
);
284 glTranslatef( 0.0, 0.0, -15.0 );
288 /* Return random float in [0,1] */
293 return (float) (i
% 1000) / 1000.0;
305 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, c
);
309 /* This function borrowed from Mark Kilgard's GLUT */
311 drawBox(GLfloat x0
, GLfloat x1
, GLfloat y0
, GLfloat y1
,
312 GLfloat z0
, GLfloat z1
, GLenum type
)
314 static GLfloat n
[6][3] =
323 static GLint faces
[6][4] =
332 GLfloat v
[8][3], tmp
;
350 v
[0][0] = v
[1][0] = v
[2][0] = v
[3][0] = x0
;
351 v
[4][0] = v
[5][0] = v
[6][0] = v
[7][0] = x1
;
352 v
[0][1] = v
[1][1] = v
[4][1] = v
[5][1] = y0
;
353 v
[2][1] = v
[3][1] = v
[6][1] = v
[7][1] = y1
;
354 v
[0][2] = v
[3][2] = v
[4][2] = v
[7][2] = z0
;
355 v
[1][2] = v
[2][2] = v
[5][2] = v
[6][2] = z1
;
357 for (i
= 0; i
< 6; i
++) {
359 glNormal3fv(&n
[i
][0]);
360 glVertex3fv(&v
[faces
[i
][0]][0]);
361 glVertex3fv(&v
[faces
[i
][1]][0]);
362 glVertex3fv(&v
[faces
[i
][2]][0]);
363 glVertex3fv(&v
[faces
[i
][3]][0]);
377 glClearColor(0.2, 0.2, 0.9, 0.0);
378 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
380 for (i
=0;i
<NumBoxes
;i
++) {
381 float tx
= -2.0 + 4.0 * Random();
382 float ty
= -2.0 + 4.0 * Random();
383 float tz
= 4.0 - 16.0 * Random();
384 float sx
= 0.1 + Random() * 0.4;
385 float sy
= 0.1 + Random() * 0.4;
386 float sz
= 0.1 + Random() * 0.4;
390 float ra
= Random() * 360.0;
392 glTranslatef(tx
, ty
, tz
);
393 glRotatef(ra
, rx
, ry
, rz
);
394 glScalef(sx
, sy
, sz
);
396 drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON
);
406 WriteFile(const char *filename
)
412 image
= malloc(gWidth
* gHeight
* 3 * sizeof(GLubyte
));
414 printf("Error: couldn't allocate image buffer\n");
418 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
419 glReadPixels(0, 0, gWidth
, gHeight
, GL_RGB
, GL_UNSIGNED_BYTE
, image
);
421 f
= fopen(filename
, "w");
423 printf("Couldn't open image file: %s\n", filename
);
427 fprintf(f
,"# ppm-file created by %s\n", "trdemo2");
428 fprintf(f
,"%i %i\n", gWidth
, gHeight
);
431 f
= fopen(filename
, "ab"); /* now append binary data */
433 printf("Couldn't append to image file: %s\n", filename
);
437 for (i
=0;i
<gHeight
;i
++) {
439 /* Remember, OpenGL images are bottom to top. Have to reverse. */
440 rowPtr
= image
+ (gHeight
-1-i
) * gWidth
*3;
441 fwrite(rowPtr
, 1, gWidth
*3, f
);
447 printf("Wrote %d by %d image file: %s\n", gWidth
, gHeight
, filename
);
453 * Print message describing command line parameters.
456 Usage(const char *appName
)
459 printf(" %s width height imgfile\n", appName
);
460 printf("Where imgfile is a ppm file\n");
466 main(int argc
, char *argv
[])
472 int width
= atoi(argv
[1]);
473 int height
= atoi(argv
[2]);
474 char *fileName
= argv
[3];
476 printf("Error: width parameter must be at least 1.\n");
480 printf("Error: height parameter must be at least 1.\n");
483 if (!Setup(width
, height
)) {
489 DestroyPbuffer(gDpy
, gScreen
, gPBuffer
);