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
]);
138 for (i
=0;i
<nConfigs
;i
++) {
139 printf("Config %d\n", i
);
140 PrintFBConfigInfo(dpy
, screen
, fbConfigs
[i
], 0);
144 /* Create the pbuffer using first fbConfig in the list that works. */
145 for (i
=0;i
<nConfigs
;i
++) {
146 pBuffer
= CreatePbuffer(dpy
, screen
, fbConfigs
[i
], width
, height
, preserve
, largest
);
148 gFBconfig
= fbConfigs
[i
];
161 printf("Using: %s\n", fbString
[attempt
]);
167 #undef NUM_FB_CONFIGS
173 * Do all the X / GLX setup stuff.
176 Setup(int width
, int height
)
179 XVisualInfo
*visInfo
;
181 /* Open the X display */
182 gDpy
= XOpenDisplay(NULL
);
184 printf("Error: couldn't open default X display.\n");
188 /* Get default screen */
189 gScreen
= DefaultScreen(gDpy
);
191 /* Test that pbuffers are available */
192 pbSupport
= QueryPbuffers(gDpy
, gScreen
);
193 if (pbSupport
== 1) {
194 printf("Using GLX 1.3 Pbuffers\n");
196 else if (pbSupport
== 2) {
197 printf("Using SGIX Pbuffers\n");
200 printf("Error: pbuffers not available on this screen\n");
206 gPBuffer
= MakePbuffer( gDpy
, gScreen
, width
, height
);
207 if (gPBuffer
==None
) {
208 printf("Error: couldn't create pbuffer\n");
213 /* Get corresponding XVisualInfo */
214 visInfo
= GetVisualFromFBConfig(gDpy
, gScreen
, gFBconfig
);
216 printf("Error: can't get XVisualInfo from FBconfig\n");
221 /* Create GLX context */
222 glCtx
= glXCreateContext(gDpy
, visInfo
, NULL
, True
);
225 glCtx
= glXCreateContext(gDpy
, visInfo
, NULL
, False
);
227 printf("Error: Couldn't create GLXContext\n");
233 printf("Warning: using indirect GLXContext\n");
237 /* Bind context to pbuffer */
238 if (!glXMakeCurrent(gDpy
, gPBuffer
, glCtx
)) {
239 printf("Error: glXMakeCurrent failed\n");
245 return 1; /* Success!! */
250 /* One-time GL setup */
254 static GLfloat pos
[4] = {0.0, 0.0, 10.0, 0.0};
255 glEnable(GL_LIGHTING
);
257 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
258 glEnable(GL_NORMALIZE
);
259 glEnable(GL_DEPTH_TEST
);
260 glEnable(GL_CULL_FACE
);
262 glViewport(0, 0, gWidth
, gHeight
);
263 glMatrixMode( GL_PROJECTION
);
265 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
266 glMatrixMode( GL_MODELVIEW
);
268 glTranslatef( 0.0, 0.0, -15.0 );
272 /* Return random float in [0,1] */
277 return (float) (i
% 1000) / 1000.0;
289 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, c
);
293 /* This function borrowed from Mark Kilgard's GLUT */
295 drawBox(GLfloat x0
, GLfloat x1
, GLfloat y0
, GLfloat y1
,
296 GLfloat z0
, GLfloat z1
, GLenum type
)
298 static GLfloat n
[6][3] =
307 static GLint faces
[6][4] =
316 GLfloat v
[8][3], tmp
;
334 v
[0][0] = v
[1][0] = v
[2][0] = v
[3][0] = x0
;
335 v
[4][0] = v
[5][0] = v
[6][0] = v
[7][0] = x1
;
336 v
[0][1] = v
[1][1] = v
[4][1] = v
[5][1] = y0
;
337 v
[2][1] = v
[3][1] = v
[6][1] = v
[7][1] = y1
;
338 v
[0][2] = v
[3][2] = v
[4][2] = v
[7][2] = z0
;
339 v
[1][2] = v
[2][2] = v
[5][2] = v
[6][2] = z1
;
341 for (i
= 0; i
< 6; i
++) {
343 glNormal3fv(&n
[i
][0]);
344 glVertex3fv(&v
[faces
[i
][0]][0]);
345 glVertex3fv(&v
[faces
[i
][1]][0]);
346 glVertex3fv(&v
[faces
[i
][2]][0]);
347 glVertex3fv(&v
[faces
[i
][3]][0]);
361 glClearColor(0.2, 0.2, 0.9, 0.0);
362 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
364 for (i
=0;i
<NumBoxes
;i
++) {
365 float tx
= -2.0 + 4.0 * Random();
366 float ty
= -2.0 + 4.0 * Random();
367 float tz
= 4.0 - 16.0 * Random();
368 float sx
= 0.1 + Random() * 0.4;
369 float sy
= 0.1 + Random() * 0.4;
370 float sz
= 0.1 + Random() * 0.4;
374 float ra
= Random() * 360.0;
376 glTranslatef(tx
, ty
, tz
);
377 glRotatef(ra
, rx
, ry
, rz
);
378 glScalef(sx
, sy
, sz
);
380 drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON
);
390 WriteFile(const char *filename
)
396 image
= malloc(gWidth
* gHeight
* 3 * sizeof(GLubyte
));
398 printf("Error: couldn't allocate image buffer\n");
402 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
403 glReadPixels(0, 0, gWidth
, gHeight
, GL_RGB
, GL_UNSIGNED_BYTE
, image
);
405 f
= fopen(filename
, "w");
407 printf("Couldn't open image file: %s\n", filename
);
411 fprintf(f
,"# ppm-file created by %s\n", "trdemo2");
412 fprintf(f
,"%i %i\n", gWidth
, gHeight
);
415 f
= fopen(filename
, "ab"); /* now append binary data */
417 printf("Couldn't append to image file: %s\n", filename
);
421 for (i
=0;i
<gHeight
;i
++) {
423 /* Remember, OpenGL images are bottom to top. Have to reverse. */
424 rowPtr
= image
+ (gHeight
-1-i
) * gWidth
*3;
425 fwrite(rowPtr
, 1, gWidth
*3, f
);
431 printf("Wrote %d by %d image file: %s\n", gWidth
, gHeight
, filename
);
437 * Print message describing command line parameters.
440 Usage(const char *appName
)
443 printf(" %s width height imgfile\n", appName
);
444 printf("Where imgfile is a ppm file\n");
450 main(int argc
, char *argv
[])
456 int width
= atoi(argv
[1]);
457 int height
= atoi(argv
[2]);
458 char *fileName
= argv
[3];
460 printf("Error: width parameter must be at least 1.\n");
464 printf("Error: height parameter must be at least 1.\n");
467 if (!Setup(width
, height
)) {
473 DestroyPbuffer(gDpy
, gScreen
, gPBuffer
);