/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ /*********************************************************************/ /* I.B.M. CONFIENTIAL */ /*********************************************************************/ #include /*---------------------------------------------------------------------------*\ $Source: /home/gda/dxcvs/dx/src/exec/hwrender/opengl/hwPortOGL.c,v $ \*---------------------------------------------------------------------------*/ #define STRUCTURES_ONLY #include "hwDeclarations.h" #include "hwWindow.h" #include "hwPortOGL.h" #include "hwMemory.h" #include "hwMatrix.h" #include "hwPortLayer.h" #include "hwObjectHash.h" #include "hwDebug.h" /* deal with DX/GL namespace collisions */ #define Object dxObject #define Matrix dxMatrix #include "internals.h" #undef Object #undef Matrix #include #include /* for getenv prototype */ #ifdef intelnt #include #endif #if defined (alphax) || defined(sgi) || defined(solaris) # if !defined (DEBUG) # include # endif #endif #define DXHW_DD_VERSION 0x080000 /* * Next three functions are used for keeping track of all GLX contexts in * use. We need to do this in order to share display lists among * contexts. */ static int nCtx = 0 ; static int ctxListSize = 0 ; static GLXContext *ctxList = 0 ; static int fontListBase = 0 ; static GLXContext getGLXContext (void) { int i ; ENTRY(("getGLXContext()")); for (i=0 ; idpy = DPY ; ret->visual = NULL ; ret->cmap = (ArrayHandle)CLRMAP ; ret->depth = 24 ; ret->invertY = FALSE ; #if sgi ret->gamma = 1.0 ; #else ret->gamma = 2.0 ; #endif ret->translationType = ThreeMap ; ret->redRange = 256 ; ret->greenRange = 256 ; ret->blueRange = 256 ; ret->usefulBits = 8 ; ret->rtable = &ret->data[256*3] ; ret->gtable = &ret->data[256*2] ; ret->btable = &ret->data[256] ; ret->table = NULL ; for(i=0 ; i<256 ; i++) { ret->rtable[i] = i << 24 ; ret->gtable[i] = i << 16 ; ret->btable[i] = i << 8 ; } if (gammaStr = getenv("DXHWGAMMA")) { ret->gamma = atof(gammaStr); if (ret->gamma < 0) ret->gamma = 0.0; PRINT(("gamma environment var: ",atof(gammaStr))); PRINT(("gamma: ",ret->gamma)); } EXIT(("ret = 0x%x",ret)); return ret ; } static void* _dxf_CREATE_WINDOW (void *globals, char *winName, int w, int h) { /* * Create a new hardware graphics window with specified name and * dimensions. Return the X identifier associated with the window. */ Window xid ; Visual *vis ; XVisualInfo *vi ; XWindowAttributes attr ; XSetWindowAttributes sattr ; int depth, screen ; GLXContext oglctx, oglctx_share ; DEFGLOBALDATA(globals) ; char *str; /* The following code was changed to fix problems in intel and on Stylus */ #if 0 static int glattr[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 23, 0 }; ENTRY(("_dxf_CREATE_WINDOW (0x%x, \"%s\", %d, %d)", globals, winName, w, h)); if (! glXQueryExtension (DPY, 0, 0)) { PRINT (("GLX extension not supported by this server")) ; DXSetError(ERROR_NOT_IMPLEMENTED, "GLX extension not installed\n"); goto error; /* DXErrorGoto (ERROR_INTERNAL, "#13670") ; */ } screen = DefaultScreen(DPY) ; if (! (vi = glXChooseVisual (DPY, screen, glattr))) { glattr[3] = glattr[5] = glattr[7] = 4; if (! (vi = glXChooseVisual (DPY, screen, glattr))) { glattr[3] = glattr[5] = 3; glattr[7] = 2; if (! (vi = glXChooseVisual (DPY, screen, glattr))) { PRINT (("Unable to find acceptable X visual")) ; DXErrorGoto (ERROR_INTERNAL, "#11720") ; } } } #else /* index into glattr struct */ #define R_DEPTH 3 #define G_DEPTH 5 #define B_DEPTH 7 #define IMAGE_DEPTH 9 static int glattr[] = { GLX_RGBA, /* 0 */ GLX_DOUBLEBUFFER, /* 1 */ GLX_RED_SIZE, 8, /* 2,3 */ GLX_GREEN_SIZE, 8, /* 4,5 */ GLX_BLUE_SIZE, 8, /* 6,7 */ GLX_DEPTH_SIZE, 23, /* 8,9 */ 0 /* 10 */ }; ENTRY(("_dxf_CREATE_WINDOW (0x%x, \"%s\", %d, %d)", globals, winName, w, h)); if (! glXQueryExtension (DPY, 0, 0)) { PRINT (("GLX extension not supported by this server")) ; DXSetError(ERROR_NOT_IMPLEMENTED, "GLX extension not installed\n"); goto error; } screen = DefaultScreen(DPY) ; if ((vi = glXChooseVisual (DPY, screen, glattr)) != NULL) goto got_visual; /* for pc hardware driver bug - relax the image depth requirement * and see what you get. if it is >= 23, it's ok. */ #ifdef intelnt glattr[IMAGE_DEPTH] = 0; #else glattr[IMAGE_DEPTH] = 1; #endif if ((vi = glXChooseVisual (DPY, screen, glattr)) != NULL) { glXGetConfig(DPY, vi, GLX_DEPTH_SIZE, &depth); if (depth >= 16) goto got_visual; XFree(vi); } glattr[R_DEPTH] = 4; glattr[G_DEPTH] = 4; glattr[B_DEPTH] = 4; if ((vi = glXChooseVisual (DPY, screen, glattr)) != NULL) { glXGetConfig(DPY, vi, GLX_DEPTH_SIZE, &depth); if (depth >= 16) goto got_visual; XFree(vi); } glattr[R_DEPTH] = 3; glattr[G_DEPTH] = 3; glattr[B_DEPTH] = 2; if ((vi = glXChooseVisual (DPY, screen, glattr)) != NULL) { glXGetConfig(DPY, vi, GLX_DEPTH_SIZE, &depth); if (depth >= 16) goto got_visual; XFree(vi); } glattr[IMAGE_DEPTH] = 0; if ((vi = glXChooseVisual (DPY, screen, glattr)) != NULL) { glXGetConfig(DPY, vi, GLX_DEPTH_SIZE, &depth); if (depth >= 16) goto got_visual; XFree(vi); } PRINT (("Unable to find acceptable X visual")) ; /* request any visual and tell the user what we got vs what we wanted */ if ((vi = glXChooseVisual (DPY, screen, NULL)) != NULL) { DXWarning("Direct or True color window required"); DXWarning("with double buffering, a depth of at least 23"); DXWarning("and either 24, 12 or 8 bit colors"); DXWarning("Default X window is class %d, depth %d, %d bit colors", vi->class, vi->depth, vi->bits_per_rgb); XFree(vi); } DXSetError(ERROR_NOT_IMPLEMENTED, "Unable to open an X window which can be used with OpenGL"); goto error; got_visual: #endif PRINT (("visual depth = %d", vi->depth)); PRINT (("visual class = %d", vi->class)); PRINT (("visual bits per rgb = %d", vi->bits_per_rgb)); PRINT (("visual colormap size = %d", vi->colormap_size)); vis = vi->visual ; depth = vi->depth ; /* find an existing GLX context with which to share display lists */ oglctx_share = getGLXContext() ; /* create a GLX direct rendering context */ if (! (oglctx = glXCreateContext (DPY, vi, NULL, TRUE))) { if (! (oglctx = glXCreateContext (DPY, vi, NULL, FALSE))) { PRINT (("Unable to create GLX rendering context")) ; DXErrorGoto (ERROR_INTERNAL, "#13670") ; } } /* release visual info structure */ XFree(vi) ; /* create colormap and X window */ sattr.border_pixel = None ; sattr.background_pixel = None ; sattr.colormap = XCreateColormap (DPY, XRootWindow(DPY, screen), vis, AllocNone) ; if (! (XWINID = xid = XCreateWindow (DPY, XRootWindow(DPY, screen), 0, 0, w, h, 0, depth, InputOutput, vis, CWBackPixel | CWBorderPixel | CWColormap, &sattr))) { PRINT (("Could not create X window")) ; DXErrorGoto (ERROR_INTERNAL, "#13770") ; } PIXDEPTH = depth ; PRINT (("X Display: 0x%x", DPY)) ; PRINT (("X Window: 0x%x", xid)) ; PRINT (("GLX context: 0x%x", oglctx)) ; PRINT (("getenv('DISPLAY') = \"%s\"", getenv("DISPLAY"))); /* * Bind the GLX context to the X window. If there is already a GLX * context in use, we have to explicitly release it since DX uses * separate display connections for each window. We think this is a * bug in OpenGL. */ glXWaitX() ; if(CurrentDpy) glXMakeCurrent (CurrentDpy, None, NULL) ; if (glXMakeCurrent (DPY, xid, oglctx)) { CurrentDpy = DPY ; } else { PRINT (("glXMakeCurrent() failed")) ; DXErrorGoto (ERROR_INTERNAL, "#13670") ; } /* put GLX context in list of existing contexts */ if (! putGLXContext(oglctx)) { PRINT (("Unable to record GLX context")); DXErrorGoto (ERROR_INTERNAL, "#13000") ; } /* install the colormap for the UI to manage, if color is not static */ glXWaitGL() ; XGetWindowAttributes (DPY, xid, &attr) ; CLRMAP = attr.colormap ; XInstallColormap (DPY, CLRMAP) ; /* if this is 1st GLX context in this process, create font display lists */ if (! oglctx_share) { Font f ; if (! (fontListBase = glGenLists(256))) { PRINT (("Unable to allocate font display lists")) ; DXErrorGoto (ERROR_INTERNAL, "#13000") ; } f = XLoadFont (DPY, "9x15") ; glXUseXFont (f, 0, 256, fontListBase) ; XUnloadFont (DPY, f) ; } /* Initialize the hwRender port private context */ if(! (PORT_HANDLE->private = tdmAllocateZero(sizeof(tdmOGLctxT)))) { PRINT (("out of memory allocating private context")) ; DXErrorGoto (ERROR_INTERNAL, "#13000") ; } else { DEFPORT(PORT_HANDLE) ; OGLDPY = DPY ; OGLSCREEN = screen ; OGLXWIN = xid ; OGLCTX = oglctx ; WINWIDTH = w ; WINHEIGHT = h ; XMAXSCREEN = DisplayWidth (DPY, screen) - 1 ; YMAXSCREEN = DisplayHeight (DPY, screen) - 1 ; OGLWINT = _wdata; FONTLISTBASE = fontListBase ; { GLint mcp; glGetIntegerv(GL_MAX_CLIP_PLANES, &mcp); MAX_CLIP_PLANES = mcp; } if (NULL != (str = getenv("DX_USE_DISPLAYLISTS"))) { if (atoi(str)) { _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_USE_DISPLAYLISTS); DO_DISPLAY_LISTS = 1; } else DO_DISPLAY_LISTS = 1; } else { _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_USE_DISPLAYLISTS); DO_DISPLAY_LISTS = 1; } if (!(OGLTRANSLATION = _dxf_CREATE_HW_TRANSLATION(LWIN))) { PRINT (("out of memory allocating translation table")) ; DXErrorGoto (ERROR_INTERNAL, "#13000") ; } } OGL_FAIL_ON_ERROR(_dxf_CREATE_WINDOW); EXIT(("xid = 0x%x",xid)); return (void *)xid ; error: OGL_FAIL_ON_ERROR(_dxf_CREATE_WINDOW); EXIT(("ERROR: xid = NULL")); return NULL ; } /* * These are only used on the DEC alpha to see what kind of * graphics adapter we are on. For certain adapters we need to * disable certain things. */ #if defined(alphax) static GLboolean isVendor(char *vendor) { char vendor_string[256]; strcpy(vendor_string, glGetString(GL_VENDOR)); return !strcmp(vendor_string,vendor); } static GLboolean isRenderer(char *renderer) { char renderer_string[256]; strcpy(renderer_string, glGetString(GL_RENDERER)); return !strcmp(renderer_string,renderer); } #endif static Error _dxf_INIT_RENDER_MODULE (void *globals) { /* * This routine is called once, after the graphics window has been * created. It's function is loosely defined to encompass all the * `first time' initialization of the graphics window. */ int i ; char * ch; DEFGLOBALDATA(globals) ; ENTRY(("_dxf_INIT_RENDER_MODULE (0x%x)",globals)); /* Mark the save buffer unallocated. */ SAVE_BUF = (void *) NULL ; SAVE_BUF_SIZE = 0 ; BUFFER_MODE = DoubleBufferMode ; /* enable Z buffering */ glEnable(GL_DEPTH_TEST) ; #if defined(newBroken) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif /* Byte Align the Pixel Buffer */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); # if defined(sgi) /* Temporary fix for SGI OpenGL problem : gl[Read|Write]Buffer(* GL_RGB *) when ! using glColor4*() */ _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE); # endif /* For this release we will use the glColorMaterial mechanism even though it is not being used correctly in the macros in hwPortUtilOGL.c We do this because fixing the problem exposes a bug on the DEC HW */ #if 1 glEnable(GL_COLOR_MATERIAL) ; #else glDisable(GL_COLOR_MATERIAL) ; #endif /* * Explicitly set draw buffer to BACK because default value * differs on different implementations, and set the ReadBuffer * to FRONT for consistancy. Don't do it on the DEC becuase that * causes problems with FRONT/BACK buffer management. */ glDrawBuffer(GL_BACK); #if !defined(alphax) glReadBuffer(GL_FRONT); #endif /* IBM's Soft OpenGL seems to default to styled lines */ glDisable(GL_LINE_STIPPLE); /* Renormalize the normals after transformation */ glEnable(GL_NORMALIZE); #if defined(alphax) if(isVendor("DEC") && isRenderer("PXG")) if(!getenv("DX_PXG_TRANSPARENCY")) _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_TRANSPARENT_OFF); #endif EXIT(("TRUE;")); return TRUE ; } static void * _dxf_ALLOCATE_PIXEL_ARRAY (void *ctx, int width, int height) { void *ret ; ENTRY(("_dxf_ALLOCATE_PIXEL_ARRAY(0x%x, %d, %d)",ctx, width, height)); ret = tdmAllocateLocal(width*height*sizeof(int32)) ; EXIT(("ret = 0x%x", ret)); return ret ; } static void _dxf_FREE_PIXEL_ARRAY (void *ctx, void *pixels) { ENTRY(("_dxf_FREE_PIXEL_ARRAY(0x%x, 0x%x)",ctx, pixels)); if (pixels) tdmFree(pixels) ; EXIT(("")); } static void _dxf_DESTROY_WINDOW (void *win) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_DESTROY_WINDOW (0x%x)",win)); if (PORT_CTX) { /* remove GLX context from list of existing contexts */ remGLXContext(OGLCTX) ; if (SAVE_BUF) { _dxf_FREE_PIXEL_ARRAY (PORT_CTX, SAVE_BUF) ; SAVE_BUF = (void *) NULL ; } if (OGLTRANSLATION) { tdmFree(OGLTRANSLATION) ; OGLTRANSLATION = NULL ; } /* OpenGL is a lot happier if we set context NULL before destroying */ glXMakeCurrent (DPY, None, NULL) ; /* we no longer have a display associated with current GLX context */ CurrentDpy = 0 ; if (DISPLAY_LIST_HASH) _dxf_DeleteDisplayListHash(DISPLAY_LIST_HASH); if (TEXTURE_HASH) _dxf_DeleteObjectHash(TEXTURE_HASH); PRINT (("Destroying GLX context 0x%x on display 0x%x", OGLCTX, OGLDPY)) ; glXDestroyContext (DPY, OGLCTX) ; tdmFree(PORT_CTX) ; PORT_HANDLE->private = (void *) NULL ; } EXIT(("")); } static void _dxf_SET_OUTPUT_WINDOW(void *win, Window w) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE); ENTRY(("_dxf_SET_OUTPUT_WINDOW(0x%x)",win)); RT_IFNDEF(DXMAKE_CURRENT) if (CurrentDpy) /* release context on current display */ glXMakeCurrent (CurrentDpy, None, NULL) ; if (glXMakeCurrent (DPY, w, OGLCTX)) { CurrentDpy = DPY ; EXIT(("")); } else { EXIT(("glXMakeCurrent failed")); } RT_ELSE EXIT(("No action RT_IFNDEF'd")); RT_ENDIF } static int _dxf_SET_BACKGROUND_COLOR (void *ctx, RGBColor c) { DEFCONTEXT(ctx) ; ENTRY(("_dxf_SET_BACKGROUND_COLOR (0x%x, 0x%x)", ctx, &c)); CPRINT(c); c.r = (c.r <= 0.0) ? 0.0 : pow(c.r,1./OGLTRANSLATION->gamma); c.g = (c.g <= 0.0) ? 0.0 : pow(c.g,1./OGLTRANSLATION->gamma); c.b = (c.b <= 0.0) ? 0.0 : pow(c.b,1./OGLTRANSLATION->gamma); BACKGROUND_COLOR = c ; glClearColor (c.r, c.g, c.b, 0) ; OGL_FAIL_ON_ERROR(_dxf_SET_BACKGROUND_COLOR); EXIT(("")); } static void _dxf_INIT_RENDER_PASS (void *win, int bufferMode, int zBufferMode) { /* * Clear the window and prepare for a rendering pass. */ DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_INIT_RENDER_PASS (0x%x, %d, %d)", win, bufferMode, zBufferMode)); _dxfChangeBufferMode (win, bufferMode) ; SAVE_BUF_VALID = FALSE ; OGL_FAIL_ON_ERROR(_dxf_INIT_RENDER_PASS); EXIT(("")); } static void _dxf_SET_VIEWPORT (void *ctx, int left, int right, int bottom, int top) { /* * Set up viewport in pixels. */ ENTRY(("_dxf_SET_VIEWPORT (0x%x, %d, %d, %d, %d)", ctx, left, right, bottom, top)); glViewport (left, bottom, (right-left)+1, (top-bottom)+1) ; OGL_FAIL_ON_ERROR(_dxf_SET_VIEWPORT); EXIT(("")); } static void _dxf_CLEAR_AREA(void *ctx, int left, int right, int bottom, int top) { ENTRY(("_dxf_CLEAR_AREA(0x%x, %d, %d, %d, %d)", ctx, left, right, bottom, top)); glPushAttrib(GL_VIEWPORT_BIT) ; glViewport (left, bottom, (right-left)+1, (top-bottom)+1) ; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; glPopAttrib() ; OGL_FAIL_ON_ERROR(_dxf_CLEAR_AREA); EXIT(("")); } static void _dxf_SET_WINDOW_SIZE (void *win, int w, int h) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_SET_WINDOW_SIZE (0x%x, %d, %d)", win, w, h)); WINHEIGHT = h ; WINWIDTH = w ; glXWaitGL() ; XResizeWindow (DPY, XWINID, w, h) ; glXWaitX() ; _dxf_SET_VIEWPORT (PORT_CTX, 0, w-1, 0, h-1) ; OGL_FAIL_ON_ERROR(_dxf_SET_WINDOW_SIZE); EXIT(("")); } static void _dxf_MAKE_PROJECTION_MATRIX (int projection, float width, float aspect, float Near, float Far, register float M[4][4]) { /* * Compute a projection matrix for a simple orthographic or perspective * camera model (no oblique projections). This matrix projects view * coordinates into a normalized projection coordinate system spanning * [-1..1] in X, Y, and Z. * * The Near and Far parameters are distances from the view coordinate * origin along the line of sight. The Z clipping planes are at -Near * and -Far since we are using a right-handed coordinate system. For * perspective, Near and Far must be positive in order to avoid drawing * objects at or behind the eyepoint depth. * * The perspective depth scaling is handled as in Newman & Sproull * Chap. 23, except for their left-handed orientation and a different * range for the projection depth [D..F], which for GL is [1..-1]. * * In the non-oblique perspective matrix of Equation 23-4, * Zs = (Ze*M33 + M43) / (Ze*M34) * = M33/M34 + (M43/M34)/Ze * = a + b/Ze * * In this formulation, M34 = S/D = fov/2. Alternatively, if we use * M34 = 1, then M33 = a and M43 = b. We must then divide M11 and M22 * by fov/2 (the same as is done for an ordinary ortho projection). * * Substituting D and F for Ze in Equation 23-2 (Zs = a +b/Ze) produces * a + b/D = 1 and a + b/F = -1. Solving results in a = 1 - 2*F/(F-D) * and b = 2*F*D/(F-D). * * The projection matrix so produced seems to have adequate precision * to represent view angles down to 0.001 degree, which is what DX * requires. */ ENTRY(("_dxf_MAKE_PROJECTION_MATRIX (%d, %f, %f, %f, %f, 0x%x)", projection, width, aspect, Near, Far, M)); Far = -Far ; Near = -Near ; M[0][0]=1/(width/2) ; M[0][1]=0 ; M[0][2]=0 ; M[0][3]=0 ; M[1][0]=0 ; M[1][1]=M[0][0]/aspect ; M[1][2]=0 ; M[1][3]=0 ; M[2][0]=0 ; M[2][1]=0 ; /* M[2][2]=1 ; M[2][3]=0 ; */ M[3][0]=0 ; M[3][1]=0 ; /* M[3][2]=0 ; M[3][3]=1 ; */ if (projection) { /* perspective */ M[2][2] = 1 - (2*Far) / (Far-Near) ; M[3][2] = (2*Far*Near) / (Far-Near) ; M[2][3] = -1 ; /* Ze < 0, but clipper wants positive w */ M[3][3] = 0 ; } else { /* orthographic */ M[2][2] = 1 / ((Far-Near) / 2) ; M[3][2] = -Near*M[2][2] - 1 ; M[2][3] = 0 ; M[3][3] = 1 ; } MPRINT(M); EXIT(("")); } static void _dxf_SET_ORTHO_PROJECTION (void *ctx, float width, float aspect, float Near, float Far) { /* * Set up an orthographic view projection. */ float M[4][4] ; ENTRY(("_dxf_SET_ORTHO_PROJECTION (0x%x %f, %f, %f, %f)", ctx, width, aspect, Near, Far)); _dxf_MAKE_PROJECTION_MATRIX (0, width, aspect, Near, Far, M) ; glMatrixMode(GL_PROJECTION) ; glLoadMatrixf((GLfloat *)M) ; glMatrixMode(GL_MODELVIEW) ; MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_SET_ORTHO_PROJECTION); EXIT(("")); } static void _dxf_SET_PERSPECTIVE_PROJECTION (void *ctx, float xfov, float aspect, float Near, float Far) { /* * Set up a perspective projection. */ float M[4][4] ; ENTRY(("_dxf_SET_PERSPECTIVE_PROJECTION (0x%x, %f, %f, %f, %f)", ctx, xfov, aspect, Near, Far)); _dxf_MAKE_PROJECTION_MATRIX (1, xfov, aspect, Near, Far, M) ; glMatrixMode(GL_PROJECTION) ; glLoadMatrixf((GLfloat *)M) ; glMatrixMode(GL_MODELVIEW) ; MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_SET_PERSPECTIVE_PROJECTION); EXIT(("")); } static void _dxf_GET_PROJECTION(void * ctx, float M[4][4]) { /* Fetch the current Projection matrix */ ENTRY(("_dxf_GET_PROJECTION(0x%x)", ctx)); glGetFloatv(GL_PROJECTION_MATRIX, (float *)M); MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_GET_PROJECTION); EXIT(("")); } static void _dxf_GET_MATRIX(void * ctx, float M[4][4]) { /* Fetch the current modelview matrix */ ENTRY(("_dxf_GET_MATRIX(0x%x)", ctx)); glGetFloatv(GL_MODELVIEW_MATRIX, (float *)M); MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_GET_MATRIX); EXIT(("")); } static void _dxf_LOAD_MATRIX (void *ctx, float M[4][4]) { /* * Load (replace) M onto the hardware matrix stack. */ ENTRY(("_dxf_LOAD_MATRIX (0x%x, 0x%x)", ctx, M)); glLoadMatrixf((GLfloat *)M) ; MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_LOAD_MATRIX); EXIT(("")); } static void _dxf_PUSH_MULTIPLY_MATRIX (void *ctx, float M[4][4]) { /* * Pushing and multiplying are combined here since some API's (such as * Starbase) don't provide a separate push. */ ENTRY(("_dxf_PUSH_MULTIPLY_MATRIX (0x%x, 0x%x)",ctx, M)); OGL_FAIL_ON_ERROR(into_dxf_PUSH_MULTIPLY_MATRIX); glPushMatrix() ; glMultMatrixf((GLfloat *)M) ; MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_PUSH_MULTIPLY_MATRIX); EXIT(("")); } static void _dxf_PUSH_REPLACE_MATRIX (void *ctx, float M[4][4]) { /* * Pushing and loading are combined here since some API's (such as * Starbase) don't provide a separate push. */ ENTRY(("_dxf_PUSH_REPLACE_MATRIX (0x%x, 0x%x)",ctx, M)); glPushMatrix() ; glLoadMatrixf((GLfloat *)M) ; MPRINT(M) ; OGL_FAIL_ON_ERROR(_dxf_PUSH_REPLACE_MATRIX); EXIT(("")); } static void _dxf_REPLACE_VIEW_MATRIX (void *ctx, float M[4][4]) { /* * This is a badly named routine. It actually replaces the projection * matrix. */ ENTRY(("_dxf_REPLACE_VIEW_MATRIX (0x%x, 0x%x)",ctx, M)); glMatrixMode(GL_PROJECTION) ; glLoadMatrixf((GLfloat *)M) ; glMatrixMode(GL_MODELVIEW) ; MPRINT(M); OGL_FAIL_ON_ERROR(_dxf_REPLACE_VIEW_MATRIX); EXIT(("")); } static void _dxf_POP_MATRIX (void *ctx) { ENTRY(("_dxf_POP_MATRIX (0x%x)",ctx)); glPopMatrix() ; OGL_FAIL_ON_ERROR(_dxf_POP_MATRIX); EXIT(("")); } static void _dxf_SWAP_BUFFERS(void *ctx, Window w) { DEFCONTEXT(ctx) ; ENTRY(("_dxf_SWAP_BUFFERS(0x%x)",ctx)); glXSwapBuffers (OGLDPY, w) ; OGL_FAIL_ON_ERROR(_dxf_SWAP_BUFFERS); EXIT(("")); } static Error _dxf_ClearBuffer(void *win) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; } static void _dxf_SET_MATERIAL_SPECULAR (void *ctx, float r, float g, float b, float power) { /* * Set material specular color and shininess. OpenGL range for specular * power is 0-128. Material diffuse and ambient colors are set when * generating OpenGL graphics primitives in hwPortUtilOGL.c. DX * doesn't use the notion of varying specular properties across a * single material's surface. */ float color[4] ; ENTRY(("_dxf_SET_MATERIAL_SPECULAR (0x%x, %f, %f, %f, %f)", ctx, r, g, b, power)); power = (power < 0 ? 0 : (power > 127 ? 127 : power)) ; color[0] = r ; color[1] = g ; color[2] = b ; color[3] = 1 ; glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, power) ; glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, color) ; OGL_FAIL_ON_ERROR(_dxf_SET_MATERIAL_SPECULAR); EXIT(("")); } static void _dxf_SET_GLOBAL_LIGHT_ATTRIBUTES (void *ctx, int on) { /* * Set global lighting attributes. Some API's, like IBM GL, can only * set certain lighting attributes such as attenuation globally across * all defined lights; these API's should do the appropriate * initialization through this call. If `on' is FALSE, turn lighting * completely off. * * For OpenGL, we will keep some default values: no local viewer for * specular reflection computations, and one-sided instead of two-sided * lighting. Note that GL_LIGHTING is also turned on and off in the * geometry rendering routines in hwPortUtilOGL.c. */ ENTRY(("_dxf_SET_GLOBAL_LIGHT_ATTRIBUTES(0x%x, %d)",ctx, on)); if (on) { /* * Specify no pervasive ambient lighting over the entire scene. * Ambient lighting is handled with specific ambient lights passed to * _dxf_DEFINE_LIGHT(). * * tjm says this will probably change soon. */ glEnable(GL_LIGHTING) ; /* * Try this some day: * glLightModel(GL_LIGHT_MODEL_TWO_SIDED, GL_TRUE); */ } else { glDisable(GL_LIGHTING) ; } OGL_FAIL_ON_ERROR(_dxf_SET_GLOBAL_LIGHT_ATTRIBUTES); EXIT(("")); } static int _dxf_DEFINE_LIGHT (void *win, int n, Light light) { /* * Define and switch on light `id' using the attributes specified by * the `light' parameter. If `light' is NULL, turn off light `id'. * If more lights are defined than supported by the API, the extra * lights are ignored. */ DEFWINDATA(win) ; DEFPORT(PORT_HANDLE); RGBColor color ; Vector direction ; float gamma; float M[4][4], new[4] ; int lightNumber = GL_LIGHT0 + (n - 1); ENTRY(("_dxf_DEFINE_LIGHT (0x%x, %d, 0x%x)", win, n, light)); gamma = OGLTRANSLATION->gamma; if (n > 8) { /* some API's don't support more than 8 lights */ DXWarning("#5195") ; EXIT(("more than 8 lights")); return OK ; } if (!light) { if (n == 0) { new[0] = new[1] = new[2] = 0.0 ; new[3] = 1 ; glLightModelfv (GL_LIGHT_MODEL_AMBIENT, new) ; } else { /* turn this light off */ PRINT (("switching off light %d", n)) ; glDisable(lightNumber) ; } EXIT(("OK")); return OK ; } if (DXQueryCameraDistantLight (light, &direction, &color)) { /* Some funny DEBUGGING stuff left in */ PRINT (("camera-relative, light direction")) ; SPRINT(direction) ; PRINT (("color")); CPRINT(color) ; if (n == 0) { PRINT (("tried to redefine light 0")) ; DXErrorGoto (ERROR_INTERNAL, "#13740"); } /* load identity for camera relative-light */ glPushMatrix() ; glLoadIdentity() ; new[0] = direction.x ; new[1] = direction.y ; new[2] = direction.z ; new[3] = 0.0 ; /* homogeneous representation of distant light */ glLightfv (lightNumber, GL_POSITION, new) ; /* set diffuse color. ambient illumination supplied by separate light */ new[0] = pow(color.r, 1./gamma); new[1] = pow(color.g, 1./gamma); new[2] = pow(color.b, 1./gamma); new[3] = 1 ; glLightfv (lightNumber, GL_DIFFUSE, new) ; /* set specular color */ glLightfv (lightNumber, GL_SPECULAR, new) ; /* switch on the light */ glEnable(lightNumber) ; /* pop identity matrix */ glPopMatrix() ; } else if (DXQueryDistantLight (light, &direction, &color)) { PRINT (("world-absolute, light direction")) ; SPRINT(direction) ; PRINT (("color")) ; CPRINT(color) ; if (n == 0) { PRINT (("tried to redefine light 0")) ; DXErrorGoto (ERROR_INTERNAL, "#13740"); } new[0] = direction.x ; new[1] = direction.y ; new[2] = direction.z ; new[3] = 0.0 ; /* homogeneous representation of distance light */ glLightfv (lightNumber, GL_POSITION, new) ; /* set diffuse color. ambient illumination supplied by separate light */ new[0] = pow(color.r, 1./gamma); new[1] = pow(color.g, 1./gamma); new[2] = pow(color.b, 1./gamma); new[3] = 1; glLightfv (lightNumber, GL_DIFFUSE, new) ; /* set specular color */ glLightfv (lightNumber, GL_SPECULAR, new) ; /* switch on the light */ glEnable(lightNumber) ; } else if(DXQueryAmbientLight (light, &color)) { PRINT (("ambient")) ; PRINT (("color")) ; CPRINT(color) ; new[0] = pow(color.r, 1./gamma); new[1] = pow(color.g, 1./gamma); new[2] = pow(color.b, 1./gamma); new[3] = 1; glLightModelfv (GL_LIGHT_MODEL_AMBIENT, new) ; } else { PRINT (("invalid light")) ; DXErrorGoto (ERROR_INVALID_DATA, "#13750"); } OGL_FAIL_ON_ERROR(_dxf_DEFINE_LIGHT); EXIT(("OK")); return OK ; error: OGL_FAIL_ON_ERROR(_dxf_DEFINE_LIGHT); EXIT(("ERROR")); return ERROR ; } static int _dxf_READ_APPROX_BACKSTORE(void *win, int camw, int camh) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_READ_APPROX_BACKSTORE(0x%x, %d, %d)",win, camw, camh)); if (SAVE_BUF_SIZE != camw * camh) { if (SAVE_BUF) { _dxf_FREE_PIXEL_ARRAY (PORT_CTX, SAVE_BUF) ; SAVE_BUF = (void *) NULL ; } /* allocate a buffer */ SAVE_BUF_SIZE = camw * camh ; if (!(SAVE_BUF = _dxf_ALLOCATE_PIXEL_ARRAY (PORT_CTX, camw, camh))) { PRINT(("Out of memory in _dxf_READ_APPROX_BACKSTORE")); DXErrorGoto (ERROR_NO_MEMORY, "#13790") ; } /* * If we are running against an adapter that does not do * readpixels well (i.e. E&S) then simply fill * the buffer with black pixels. Return OK so * common layer uses the buffer for the interactors. */ if (_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE)) { bzero(SAVE_BUF,SAVE_BUF_SIZE*sizeof(GLuint)); EXIT(("OK")); return OK ; } } /* * DX hardware renderer expects pixels to be packed into 32-bit integers, * so we use GL_RGBA format with a type of GL_UNSIGNED_BYTE. Default * read buffer is GL_BACK, so we must explicitly set GL_FRONT. * * Don't do the read if we are running against hardware that * does not do readpixels well. */ if (!_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE)) { glReadBuffer(GL_FRONT) ; glReadPixels(0, 0, camw, camh, GL_RGBA, GL_UNSIGNED_BYTE, SAVE_BUF) ; /* Reset to Back buffer */ glReadBuffer(GL_BACK) ; } OGL_FAIL_ON_ERROR(_dxf_READ_APPROX_BACKSTORE); EXIT(("OK")); return OK ; error: OGL_FAIL_ON_ERROR(_dxf_READ_APPROX_BACKSTORE); EXIT(("ERROR")); return NULL ; } /* * This function is only called if SAVE_BUFFER_VALID is TRUE * This will never be the case when SF_INVALIDATE_BACKSTORE * services flag is set. */ static void _dxf_WRITE_APPROX_BACKSTORE(void *win, int camw, int camh) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_WRITE_APPROX_BACKSTORE(0x%x, %d, %d)",win, camw, camh)); /* Draw saved backstore into front buffer */ glDrawBuffer (GL_FRONT) ; /* Disable Z-buffer */ glDisable (GL_DEPTH_TEST) ; SET_RASTER_SCREEN (0, 0) ; glDrawPixels(camw, PIXH, GL_RGBA, GL_UNSIGNED_BYTE, SAVE_BUF) ; /* make it visible */ glFlush() ; /* Reset draws for normal operations */ glDrawBuffer (GL_BACK) ; glEnable (GL_DEPTH_TEST) ; /* redraw interactor echos; don't save them in SAVE_BUF */ _dxfRedrawInteractorEchos(INTERACTOR_DATA) ; OGL_FAIL_ON_ERROR(_dxf_WRITE_APPROX_BACKSTORE); EXIT(("")); } static void _dxf_WRITE_PIXEL_RECT(void* win, uint32 *buf, int x, int y, int w, int h) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; int i ; ENTRY(("_dxf_WRITE_PIXEL_RECT(0x%x, 0x%x, %d, %d, %d, %d)", win, buf, x, y, w, h)); /* There still seems to be a bug here. When the window is resized * larger than the 2d image, there is junk and gray in the new area. * Also...with multiple vertical arranged 2d images, the top image * is chopped off at the top (sometimes) */ SET_RASTER_SCREEN (0, 0) ; glDrawPixels (w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf) ; /* This finish should be a flush */ glFinish() ; OGL_FAIL_ON_ERROR(_dxf_WRITE_PIXEL_RECT); EXIT(("")); } static Error _dxf_DRAW_IMAGE(void* win, dxObject image, hwTranslationP dummy) { DEFWINDATA(win) ; DEFPORT(PORT_HANDLE) ; int x,y,w,h ; uint32 *pixels = NULL ; void * translation = OGLTRANSLATION ; ENTRY(("_dxf_DRAW_IMAGE(0x%x, 0x%x, 0x%x)", win, image, dummy)); if(!DXGetImageBounds(image,&x,&y,&w,&h)) goto error ; if(!(pixels = tdmAllocateZero(sizeof(uint32) * w * h))) goto error ; if(!_dxf_dither(image,w,h,x,y,translation,pixels)) goto error ; _dxf_WRITE_PIXEL_RECT(win, pixels, 0, 0, w, h) ; tdmFree(pixels) ; pixels = NULL ; OGL_FAIL_ON_ERROR(_dxf_DRAW_IMAGE); EXIT(("OK")); return OK ; error: if(pixels) { tdmFree(pixels) ; pixels = NULL ; } OGL_FAIL_ON_ERROR(_dxf_DRAW_IMAGE); EXIT(("ERROR")); return ERROR ; } static int _dxf_ADD_CLIP_PLANES (void* win, Point *pt, Vector *normal, int count) { DEFWINDATA(win); DEFPORT(PORT_HANDLE) ; int planeCount; ClipPlane *planes = NULL; float view[4][4]; double dview[4][4],datview[4][4]; int i; ENTRY(("_dxf_ADD_CLIP_PLANES(0x%x, 0x%x, 0x%x, %d)",win, pt, normal, count)); planes = (ClipPlane *)DXAllocate(count*sizeof(ClipPlane)); if (! planes) goto error; planeCount = CLIP_PLANE_CNT; CLIP_PLANE_CNT += count; if (CLIP_PLANE_CNT > MAX_CLIP_PLANES) { /* Too many clip planes specified, clip object ignored */ DXWarning("#13890",MAX_CLIP_PLANES); EXIT(("CNT > MAX")); return OK; } /* * pt and normal are in world coordinates. Because the view matrix is * in the PROJECTION_MATRIX for xgl, this implies that we have view * coordinates for clip planes (not world as the document says). * * So we need to apply the inverse of the clipping transform to the * pt and normal to correct for this. */ /* !!!!! This is unused !!!!! */ _dxfGetViewMatrix(MATRIX_STACK,view); COPYMATRIX(dview,view); _dxfAdjointTranspose(datview,dview); for(i=0;i < count; i++) { planes[planeCount].a = normal[i].x; planes[planeCount].b = normal[i].y; planes[planeCount].c = normal[i].z; planes[planeCount].d = -DXDot(normal[i],pt[i]); planeCount++; } planeCount--; for(i=0;i MAX_CLIP_PLANES) { CLIP_PLANE_CNT -= count; EXIT(("CNT > MAX")); return OK; } planeCount = CLIP_PLANE_CNT; CLIP_PLANE_CNT -= count; if(count > planeCount) { /* Too many clip planes deleted */ DXErrorGoto(ERROR_INTERNAL,"#13900"); } planeCount--; for(i=0;iportFuncs = NULL ; portHandle->echoFuncs = NULL ; /* * Don't free portHandle->private here cause it's * done in DESTROY_WINDOW as PORT_CTX */ tdmFree(portHandle) ; } EXIT(("")); } tdmPortHandleP _dxfInitPortHandleOGL(Display *dpy, char *hostname) { tdmPortHandleP ret ; static int beenHere = 0 ; int execSymbolInterface; void* (*symVer)(); void* (*expVer)(); void* DX_handle; ENTRY(("_dxfInitPortHandleOGL(0x%x, \"%s\")",dpy, hostname)); #ifdef intelnt HCLXtInit(); #endif _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_TMESH | SF_QMESH | SF_POLYLINES | SF_DOES_TRANS | SF_VOLUME_BOUNDARY); #if !defined(DEBUG) && defined(RTLOAD) /* If the hardware rendering load module requires a newer set of * DX exported symbols than those available in the calling dxexec * return NULL. */ #if defined(alphax) || defined(sgi) || defined(solaris) /* If the hardware rendering load module requires a newer set of * DX exported symbols than those available in the calling dxexec */ if (!(DX_handle=dlopen(NULL,RTLD_LAZY))) { DXSetError(ERROR_UNEXPECTED,dlerror()); EXIT(("ERROR")); return NULL; } if ((symVer = (void*(*)())dlsym(DX_handle, "DXSymbolInterface")) && (expVer = (void*(*)())dlsym(DX_handle, "_dxfExportHwddVersion"))) { PRINT(("found DXSymbolInterface;")); (*symVer)(&execSymbolInterface); (*expVer)(DXD_HWDD_INTERFACE_VERSION); } else { execSymbolInterface = 0; } if(LOCAL_DXD_SYMBOL_INTERFACE_VERSION > execSymbolInterface) { DXSetError(ERROR_UNEXPECTED,"#13910", "hardware rendering", "DX Symbol Interface"); EXIT(("ERROR")); return NULL; } #elif !defined(DXD_WIN) if(! loadbind(0,_dxfInitPortHandleOGL,DXSymbolInterface)) { DXSymbolInterface(&execSymbolInterface); _dxfExportHwddVersion(DXD_HWDD_INTERFACE_VERSION); } else { execSymbolInterface = 0; } if(LOCAL_DXD_SYMBOL_INTERFACE_VERSION > execSymbolInterface) { DXSetError(ERROR_UNEXPECTED,"#13910", "hardware rendering", "DX Symbol Interface"); EXIT(("ERROR: Symbol interface")); return NULL; } #else _dxfExportHwddVersion(DXD_HWDD_INTERFACE_VERSION); #endif #else _dxfExportHwddVersion(DXD_HWDD_INTERFACE_VERSION); #endif ret = (tdmPortHandleP)tdmAllocateLocal(sizeof(tdmPortHandleT)) ; if(ret) { ret->portFuncs = &_oglDrawPort ; ret->echoFuncs = &_dxd_hwInteractorEchoPortOGL ; ret->uninitP = _dxfUninitPortHandle ; ret->private = NULL ; } EXIT(("ret = 0x%x",ret)); return ret ; } int _dxf_READ_IMAGE (void* win, void *buf) { DEFWINDATA(win); DEFPORT(PORT_HANDLE) ; ENTRY(("_dxf_READ_IMAGE (0x%x, 0x%x)", win, buf)); if (glXMakeCurrent (DPY, XWINID, OGLCTX)) { glReadBuffer(GL_FRONT) ; glReadPixels(0, 0, PIXW, PIXH, GL_RGB, GL_UNSIGNED_BYTE, buf) ; } EXIT(("OK")); return OK; }