/* * This program demonstrates how to do "off-screen" rendering using * the GLX pixel buffer extension. * * Written by Brian Paul for the "OpenGL and Window System Integration" * course presented at SIGGRAPH '97. Updated on 5 October 2002. * * Updated on 31 January 2004 to use native GLX by * Andrew P. Lentvorski, Jr. * * Usage: * glxpbdemo width height imgfile * Where: * width is the width, in pixels, of the image to generate. * height is the height, in pixels, of the image to generate. * imgfile is the name of the PPM image file to write. * * * This demo draws 3-D boxes with random orientation. * * On machines such as the SGI Indigo you may have to reconfigure your * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/ * directory for display configurations with the _pbuf suffix. Use * setmon -x to configure your X server and display for pbuffers. * * O2 systems seem to support pbuffers well. * */ #include #include #include #include #include /* Some ugly global vars */ static GLXFBConfig gFBconfig = 0; static Display *gDpy = NULL; static int gScreen = 0; static GLXPbuffer gPBuffer = 0; static int gWidth, gHeight; /* * Test for appropriate version of GLX to run this program * Input: dpy - the X display * screen - screen number * Return: 0 = GLX not available. * 1 = GLX available. */ static int RuntimeQueryGLXVersion(Display *dpy, int screen) { #if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4) char *glxversion; glxversion = (char *) glXGetClientString(dpy, GLX_VERSION); if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4"))) return 0; glxversion = (char *) glXQueryServerString(dpy, screen, GLX_VERSION); if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4"))) return 0; return 1; #else return 0; #endif } /* * Create the pbuffer and return a GLXPbuffer handle. */ static GLXPbuffer MakePbuffer( Display *dpy, int screen, int width, int height ) { GLXFBConfig *fbConfigs; GLXFBConfig chosenFBConfig; GLXPbuffer pBuffer = None; int nConfigs; int fbconfigid; int fbAttribs[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DEPTH_SIZE, 1, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_PBUFFER_BIT, None }; int pbAttribs[] = { GLX_PBUFFER_WIDTH, 0, GLX_PBUFFER_HEIGHT, 0, GLX_LARGEST_PBUFFER, False, GLX_PRESERVED_CONTENTS, False, None }; pbAttribs[1] = width; pbAttribs[3] = height; fbConfigs = glXChooseFBConfig(dpy, screen, fbAttribs, &nConfigs); if (0 == nConfigs || !fbConfigs) { printf("Error: glxChooseFBConfig failed\n"); XCloseDisplay(dpy); return 0; } chosenFBConfig = fbConfigs[0]; glXGetFBConfigAttrib(dpy, chosenFBConfig, GLX_FBCONFIG_ID, &fbconfigid); printf("Chose 0x%x as fbconfigid\n", fbconfigid); /* Create the pbuffer using first fbConfig in the list that works. */ pBuffer = glXCreatePbuffer(dpy, chosenFBConfig, pbAttribs); if (pBuffer) { gFBconfig = chosenFBConfig; gWidth = width; gHeight = height; } XFree(fbConfigs); return pBuffer; } /* * Do all the X / GLX setup stuff. */ static int Setup(int width, int height) { #if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4) GLXContext glCtx; /* Open the X display */ gDpy = XOpenDisplay(NULL); if (!gDpy) { printf("Error: couldn't open default X display.\n"); return 0; } /* Get default screen */ gScreen = DefaultScreen(gDpy); /* Test that GLX is available */ if (!RuntimeQueryGLXVersion(gDpy, gScreen)) { printf("Error: GLX 1.3 or 1.4 not available\n"); XCloseDisplay(gDpy); return 0; } /* Create Pbuffer */ gPBuffer = MakePbuffer( gDpy, gScreen, width, height ); if (gPBuffer==None) { printf("Error: couldn't create pbuffer\n"); XCloseDisplay(gDpy); return 0; } /* Create GLX context */ glCtx = glXCreateNewContext(gDpy, gFBconfig, GLX_RGBA_TYPE, NULL, True); if (glCtx) { if (!glXIsDirect(gDpy, glCtx)) { printf("Warning: using indirect GLXContext\n"); } } else { printf("Error: Couldn't create GLXContext\n"); XCloseDisplay(gDpy); return 0; } /* Bind context to pbuffer */ if (!glXMakeCurrent(gDpy, gPBuffer, glCtx)) { printf("Error: glXMakeCurrent failed\n"); XCloseDisplay(gDpy); return 0; } return 1; /* Success!! */ #else printf("Error: GLX version 1.3 or 1.4 not available at compile time\n"); return 0; #endif } /* One-time GL setup */ static void InitGL(void) { static GLfloat pos[4] = {0.0, 0.0, 10.0, 0.0}; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glViewport(0, 0, gWidth, gHeight); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -15.0 ); } /* Return random float in [0,1] */ static float Random(void) { int i = rand(); return (float) (i % 1000) / 1000.0; } static void RandomColor(void) { GLfloat c[4]; c[0] = Random(); c[1] = Random(); c[2] = Random(); c[3] = 1.0; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c); } /* This function borrowed from Mark Kilgard's GLUT */ static void drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1, GLfloat z0, GLfloat z1, GLenum type) { static GLfloat n[6][3] = { {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} }; static GLint faces[6][4] = { {0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4}, {4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} }; GLfloat v[8][3], tmp; GLint i; if (x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; } if (y0 > y1) { tmp = y0; y0 = y1; y1 = tmp; } if (z0 > z1) { tmp = z0; z0 = z1; z1 = tmp; } v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0; v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1; v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0; v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1; v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0; v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1; for (i = 0; i < 6; i++) { glBegin(type); glNormal3fv(&n[i][0]); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } /* Render a scene */ static void Render(void) { int NumBoxes = 100; int i; InitGL(); glClearColor(0.2, 0.2, 0.9, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (i=0;i