/* opengl.c: OpenGL graphics driver. */ #include #include #include #include #include #include #include #include "render.h" #include "camera.h" #include "error.h" #include "pools.h" #include static XVisualInfo *glx_visual; static GLXContext glx_context; static Display *glx_display; static Window glx_window; static int attribute_list_db[] = {GLX_RGBA, GLX_RED_SIZE, 2, GLX_GREEN_SIZE, 2, GLX_BLUE_SIZE, 2, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None}; static int attribute_list_nodb[] = {GLX_RGBA, GLX_RED_SIZE, 2, GLX_GREEN_SIZE, 2, GLX_BLUE_SIZE, 2, GLX_DEPTH_SIZE, 16, None}; static int ogl_inited = FALSE, doublebuf = FALSE; static XVisualInfo *OpenGLGetVisual(Display *dpy) { if (!glXQueryExtension(dpy, NULL, NULL)) Fatal(1, NULL, "No GLX extension available on the display"); /* get an appropriate visual: first look for a visual with double buffering */ glx_visual = glXChooseVisual(dpy, DefaultScreen(dpy), attribute_list_db); if (glx_visual) { doublebuf = TRUE; return glx_visual; } else { /* look for a visual without double buffering */ doublebuf = FALSE; return glx_visual = glXChooseVisual(dpy, DefaultScreen(dpy), attribute_list_nodb); } } /* finds the visual and colormap to be used for OpenGL rendering on the specified * screen */ Boolean RenderGetVisualInfoAndColormap(Screen *screen, XVisualInfo *visual_info, Colormap *colormap) { XVisualInfo *vi; Display *dpy = DisplayOfScreen(screen); vi = OpenGLGetVisual(dpy); if (!vi) Fatal(1, NULL, "Failed to get a suitable X visual"); *visual_info = *vi; *colormap = XCreateColormap(dpy, RootWindow(dpy, visual_info->screen), visual_info->visual, AllocNone); return TRUE; } void RenderClearWindow(void) { glClearColor(Camera.background.r, Camera.background.g, Camera.background.b, 0.); glClearDepth(1.); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void RenderSetCamera(void) { RenderClearWindow(); /* use full viewport */ glViewport(0, 0, Camera.hres, Camera.vres); /* determine distance to front- and backclipping plane */ RenderGetNearFar(&Camera.near, &Camera.far); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(Camera.vfov*2., (float)Camera.hres/(float)Camera.vres, Camera.near, Camera.far); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(Camera.eyep.x, Camera.eyep.y ,Camera.eyep.z, Camera.lookp.x, Camera.lookp.y, Camera.lookp.z, Camera.updir.x, Camera.updir.y, Camera.updir.z); } static void OpenGLInitCallback(Widget canvas, XtPointer client_data, XtPointer call_data) { glx_display = XtDisplay(canvas); glx_window = XtWindow(canvas); /* create a GLX context */ glx_context = glXCreateContext(glx_display, glx_visual, 0, GL_TRUE); /* connect the context to the window */ glXMakeCurrent(glx_display, glx_window, glx_context); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glDrawBuffer(GL_FRONT); RenderClearWindow(); glFinish(); ogl_inited = TRUE; XtRemoveCallback(canvas, XmNexposeCallback, OpenGLInitCallback, (XtPointer)NULL); } /* open window for rendering */ Widget RenderCreateWindow(Widget parent) { Widget canvas; /* Dimension hres, vres; */ canvas = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass, parent, NULL); ogl_inited = FALSE; XtAddCallback(canvas, XmNexposeCallback, OpenGLInitCallback, (XtPointer)NULL); return canvas; } /* Returns 0 if not yet ready for rendering */ int RenderStartFrame(void) { if (!ogl_inited) return 0; if (doublebuf) glDrawBuffer(GL_BACK); RenderSetCamera(); switch (renderopts.backface_culling) { case BC_ON: glEnable(GL_CULL_FACE); break; case BC_OFF: glDisable(GL_CULL_FACE); break; default: break; } return 1; } /* Finishes rendering a frame */ void RenderEndFrame(void) { glFinish(); if (doublebuf) glXSwapBuffers(glx_display,glx_window); glDrawBuffer(GL_FRONT); } void SaveScreen(FILE *fp) { long i, j, x=Camera.hres, y=Camera.vres; GLubyte *screen, *pixel; screen = (GLubyte *)Alloc(x * y * sizeof(GLubyte) * 4); glReadBuffer(GL_FRONT); glReadPixels(0, 0, x, y, GL_RGBA, GL_UNSIGNED_BYTE, screen); fprintf(fp, "P6\n%ld %ld\n255\n", x, y); for (j=y-1; j>=0; j--) for (i=0, pixel=screen+4*(j*x); i