/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmogl.c,v 1.12 2005/06/26 19:00:12 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.12 $ * $Log: rmogl.c,v $ * Revision 1.12 2005/06/26 19:00:12 wes * New routines for push/pop the OpenGL attrib stack. These contain lots * of error checking code that can be activated via DEBUG_LEVEL in rmprivat.h. * * Revision 1.11 2005/06/08 18:32:47 wes * Replaced APIENTRY with the well-defined GLAPIENTRY. * * Revision 1.10 2005/06/06 02:13:40 wes * Updated private_rmGLGetProcAddr to convert the function name argument * from type char * to GLbyte * (why use a ubyte for a function name??) * * Revision 1.9 2005/06/06 02:04:29 wes * Lots of small additions to clean up compiler warnings. * * Revision 1.8 2005/03/16 16:45:14 wes * Minor tweak to diagnostic output produced by my_glPopAttrib in debug mode. * * Revision 1.7 2005/02/19 16:28:54 wes * Distro sync and consolidation. * Fixes for a number of state tracking buglets. * * Revision 1.6 2005/01/23 17:08:25 wes * Copyright updated to 2005. * Updates to support access and use of extensions; multitexturing on all * platforms, use of 3d texture extension to realize implementation of * volume rendering and related functions on Windows platforms. * * Revision 1.5 2004/01/16 16:46:09 wes * Updated copyright line for 2004. * * Revision 1.4 2003/03/16 21:56:16 wes * Documentation updates. * * Revision 1.3 2003/02/14 00:18:23 wes * Added new wrapper routine for glCallLists. In a CR implementation, it will * use the RMprimitive's bounding box as the source for parms for the * GL_OBJECT_BBOX_CR extension. * * Revision 1.2 2003/02/02 02:07:15 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.22 2003/01/27 05:04:42 wes * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR * platforms w/o too much disruption to existing apps. * * Revision 1.21 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.20 2003/01/11 18:44:22 wes * Added global control over whether or not display lists are used during * rendering by adding the new RMpipe controls rmPipeSetDisplayListEnable() * and rmPipeGetDisplayListEnable(). * * Revision 1.19 2003/01/07 03:11:12 wes * Removed some debug printf's inside the display list dispatch routine. * * Revision 1.18 2002/12/31 00:55:22 wes * * Various enhancements to support Chromium - achitecture-specific sections * of RMpipe were cleaned up, etc. * * Revision 1.17 2002/11/27 00:44:19 wes * Added code that honors the rmPrimitive's display list enable flag. * If set to RM_FALSE, no display lists will be generated for a primitive. * * Revision 1.16 2002/09/05 15:07:08 wes * Inside delete texture code, we no longer check for glIsTexture * when a realloc of textureIDs is imminent. Saves a little time, * and avoids a segfault. * * Revision 1.15 2002/08/29 22:20:32 wes * * Massive upgrade to accommodate dynamic object reallocation within * the component manager, and within the context cache. Use the * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf * whenever a realloc occurs. With this upgrade, there are no * OpenRM limits on the size of the scene graph. There will be external * limits, such as the amount of RAM and the amount of space available * to your OpenGL implementation. * * Revision 1.14 2002/06/02 15:15:34 wes * Added RMstateCache code to help eliminate the number of state changes * made during the render traversal. The RMstateCache tracks * the actual OpenGL rendering state w/o the need for querying OpenGL * directly, and is queried by draw code that then decides if any * real state changes are required given the configuration of data * within an RMprimitive. * * Revision 1.13 2002/04/30 19:32:47 wes * Updated copyright dates. * * Revision 1.12 2001/10/15 02:35:56 wes * Vectors, bitmaps and sprites will never be subject to lighting * when fogging is enabled. This was an error in the last checkin - * OpenGL fogging is not dependant upon lighting. * * Revision 1.11 2001/10/15 01:32:19 wes * Minor mods to support 4-byte alignment of framebuffer reads on Win32. * Problem showed up in demo "pdb." * * Revision 1.9 2001/07/15 17:19:19 wes * Added temporary code to routine that builds OpenGL display lists for * RMprimitive objects. The new code will remove an old OpenGL display * list before creating a new one. * * Revision 1.8 2001/06/03 20:48:45 wes * No significant differences. * * Revision 1.7 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.6 2000/12/03 22:33:55 wes * Mods for thread-safety. * * Revision 1.5 2000/10/03 11:40:50 wes * Contributions from jdb - prototype and compile warning cleanups. * * Revision 1.4 2000/08/31 02:11:06 wes * Tweaks to conditional compile code for local wrappers for * glPush/PopAttib. * * Revision 1.3 2000/08/23 23:24:21 wes * DO_LISTS define moved from rmogl.c to rmprivat.h. All display * list code removed from rmBitmap (will be reinserted later). * * Revision 1.2 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:48 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ /* documentation of public routines is incomplete in this file. */ #include #include "rmprivat.h" /* PRIVATE */ RMenum private_rmColorsEqual(RMcolor4D *c1, RMcolor4D *c2) { #define CEPS 0.001 float d1, d2, d3, d4; d1 = fabs(c1->r - c2->r); d2 = fabs(c1->g - c2->g); d3 = fabs(c1->b - c2->b); d4 = fabs(c1->a - c2->a); if ((d1 > CEPS) || (d2 > CEPS) || (d3 > CEPS) || (d4 > CEPS)) return RM_FALSE; else return RM_TRUE; } /* PRIVATE */ void private_rmSetBackBuffer (RMpipe *p) { RMenum cf = rmPipeGetChannelFormat(p); if ((cf == RM_MONO_CHANNEL) || (cf == RM_REDBLUE_STEREO_CHANNEL) || (cf == RM_BLUERED_STEREO_CHANNEL) || (cf == RM_MBUF_STEREO_CHANNEL)) glDrawBuffer(GL_BACK); else glDrawBuffer(GL_FRONT); } /* PRIVATE */ void private_rmReadBytePixels (unsigned char *pixelbuf, int w, int h, int ncomponents, GLenum pixel_component, int bytesPerScanline) { int j, offset = 0; int nbytes_per_component; /* the following line of code reads the entire framebuffer. it's flipped in Y, so the loop below reads a row at a time. */ nbytes_per_component = ncomponents * sizeof(unsigned char); offset = (h-1) * bytesPerScanline; for (j = 0; j < h; j++, offset -= (bytesPerScanline)) { /* grab a row... */ glReadPixels(0, j, w, 1, pixel_component, GL_UNSIGNED_BYTE, (pixelbuf + offset)); } } /* PRIVATE */ void private_rmReadFloatPixels (float *pixelbuf, int w, int h, int ncomponents, GLenum pixel_component) { int j, offset = 0; /* the following line of code reads the entire framebuffer. it's flipped in Y, so the loop below reads a row at a time. */ offset = (w * h * ncomponents) - (w * ncomponents); for (j=0; j < h; j++, offset -= (ncomponents * w)) { /* grab a row... */ glReadPixels(0, j, w, 1, pixel_component, GL_FLOAT, (pixelbuf + offset)); } } /* PRIVATE */ int private_rmGLPushAttrib (RMpipe *p, const RMnode *r, GLuint imask) { /* * returns 0 on success, non-zero when there's an error */ int rval = 0; #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK) /* debug */ int ival; glGetIntegerv(GL_ATTRIB_STACK_DEPTH, &ival); rval = ival; if (r != NULL) fprintf(stderr, " before push attrib stack depth %d, <%s> \n", ival, r->object_info.name); else fprintf(stderr, " before push attrib stack depth %d \n", ival); #endif glPushAttrib(imask); p->localMaskStack[p->localMaskStackTop] = imask; p->localMaskStackTop++; if (p->localMaskStackTop > MAX_MASK_STACK_DEPTH) rmError(" private_rmGLPushAttrib mask stack overflow! "); #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK) rval |= rmGLGetError("after glPushAttrib()"); #endif return rval; } /* PRIVATE */ int private_rmGLPopAttrib (RMpipe *p, RMstate *s, RMstateCache *rsc) { int rval = 0; glPopAttrib(); #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK) rval = glGetError(); if (rval != 0) { char buf[128]; sprintf(buf, "%s OpenGL error code (hex): 0x%04x ", s, rstat); rmWarning(buf); } #endif if (p->localMaskStack[p->localMaskStackTop] & (GL_ENABLE_BIT)) { /* synchronize lighting state */ rsc->lightingActive = s->lightingActive; /* ?? */ rsc->colorMaterialActive = s->colorMaterialActive; /* ?? */ /* todo: if rsc->colorMaterialActive is RM_TRUE, then the current OpenGL color might not be the same as s->unlit_color. */ } p->localMaskStackTop--; if (p->localMaskStackTop < 0) { rmError(" private_rmGLPushAttrib mask stack underflow! Please file a bug report."); p->localMaskStackTop = 0; /* to keep from blowing up */ } #if 0 /* debug code used to coerce correct lighting state during state tracking debugging. Keeping it around for sentimental reasons */ { int oglLightingEnabled; glFinish(); oglLightingEnabled = glIsEnabled(GL_LIGHTING); if (oglLightingEnabled == GL_TRUE) { rsc->lightingActive = s->lightingActive = RM_TRUE; } else { rsc->lightingActive = s->lightingActive = RM_FALSE; } } #endif /* * The following code doesn't always give reliable results: it * sometimes gives a false positive error indication. */ #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK) { RMcolor4D c; int rD, gD, bD, aD; glGetFloatv(GL_CURRENT_COLOR, (GLfloat *)&c); rD = (int)((s->unlit_color.r - c.r)*255.0F); gD = (int)((s->unlit_color.g - c.g)*255.0F); bD = (int)((s->unlit_color.b - c.b)*255.0F); aD = (int)((s->unlit_color.a - c.a)*255.0F); if ((aD != 0) || (rD != 0) || (gD != 0) || (bD != 0)) rmWarning("private_rmGLPopAttrib - OpenGL current color != RMstate current color"); } #endif return rval; } /* * display list routines * * from inside each RMprimitive draw routine, we potentially call two * routines. the first one will either invoke a display list that's * already built, or will prepare to build one. at the end of the * RMprimitive draw routine, we call a routine that finalizes the * display list. */ /* PRIVATE */ int private_rmPrimitiveDisplayListBegin (RMpipe *pipe, RMprimitive *p) { /* * return values: * 0 = this routine invoked a display list, caller does not need * to execute draw code * 1 = caller needs to execute draw code as part of th< * display list build process. the caller must also call * private_rmPrimitiveDisplayListEnd() to cause the display list * to be finished. * 2 = caller needs to execute draw code, we're not building a * display list * -1 = an error of some type. */ int stat = 2; GLuint newlist = 0; RMcacheKey primKey, contextCacheKey; int compListIndx; /* * check to see if display listing is disabled for this primitive. * if so, return "2" so that the caller will then invoke immediate * mode draw code. */ if ((pipe->displayListEnableBool == RM_FALSE) || (private_rmPrimitiveGetDisplayListEnable(p) == RM_FALSE)) return stat; #if DO_LISTS primKey = private_rmPrimitiveGetCacheKey(p); compListIndx = p->compListIndx; if (compListIndx >= pipe->contextCache->numPrimCacheKeys) { int newSize; int oldSize = pipe->contextCache->numPrimCacheKeys; int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx); int numOldPages = oldSize/NUM_ITEMS_PER_PAGE; newSize = numNewPages * NUM_ITEMS_PER_PAGE; pipe->contextCache->primCacheKeys = (RMcacheKey *)realloc(pipe->contextCache->primCacheKeys, newSize * sizeof(RMcacheKey)); /* initialize new stuff to -1 */ memset((void *)(pipe->contextCache->primCacheKeys + oldSize), 0xFF, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(RMcacheKey)); pipe->contextCache->numPrimCacheKeys = newSize; #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE) printf("private_rmPrimitiveDisplayListBegin() - reallocating contextCache->primCacheKeys; oldSize = %d, newSize = %d \n", oldSize, newSize); #endif } contextCacheKey = pipe->contextCache->primCacheKeys[compListIndx]; /* * compare primKey and contextCacheKey. * if they are equal, the OpenGL display list is up to date * wrt the contents of the RMprimitive. In this case, we can just * invoke the display list and return. * * if not, then first we check to see if the old display list * handle is a valid list, and if so, delete it. then, we begin * construction of an OpenGL display list. * */ if (primKey == contextCacheKey) /* call the display list */ { GLuint list; /* error check */ if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs) /* this should never happen - the realloc should occur before this branch of code is executed */ rmError("private_rmPrimitiveDisplayListBegin() error - the size of the primDisplayListIDs buffer is too small. \n"); /** end debug code */ list = pipe->contextCache->primDisplayListIDs[compListIndx]; #if 0 fprintf(stderr," calling list %d \n", list); fflush(stderr); #endif /* glCallList(list); */ private_glCallList(pipe, p, list); stat = 0; } else { /* error check */ if (compListIndx >= pipe->contextCache->numPrimCacheKeys) /* this should never happen because we should have performed any realloc before this chunk of code is executed. */ rmError("private_rmPrimitiveDisplayListBegin() error - the size of the primCacheKeys buffer is too small. \n"); /** end debug code */ pipe->contextCache->primCacheKeys[compListIndx] = primKey; /* * 7/7/01 w.bethel * * by deleting the list here, we are inserting work in the * critical path of rendering. this may not be a good idea * in all circumstances. * * the way the component manager works, an rmPrimitiveDelete will * move the newly deleted RMprimitive to the head of the alloc * list, thereby increasing the liklihood that any old display * list will be deleted the next time the RMprimitive is drawn. * an alternate design strategy would be to construct a "to delete" * list inside rmPrimitiveDelete which is later executed * via an application-invoked synchronization function. */ if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs) { int newSize; int oldSize = pipe->contextCache->numPrimDisplayListIDs; int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx); int numOldPages = oldSize/NUM_ITEMS_PER_PAGE; newSize = numNewPages * NUM_ITEMS_PER_PAGE; pipe->contextCache->primDisplayListIDs = (GLuint *)realloc(pipe->contextCache->primDisplayListIDs, newSize * sizeof(GLuint)); /* initialize new stuff to -1 */ memset((void *)(pipe->contextCache->primDisplayListIDs + oldSize), 0xFF, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(GLuint)); pipe->contextCache->numPrimDisplayListIDs = newSize; #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE) printf("private_rmPrimitiveDisplayListBegin() - reallocating the primDisplayListIDs buffer, oldsize = %d, newSize = %d. \n", oldSize, newSize); #endif } if (glIsList(pipe->contextCache->primDisplayListIDs[compListIndx])) glDeleteLists(pipe->contextCache->primDisplayListIDs[compListIndx],1); pipe->contextCache->primDisplayListIDs[compListIndx] = newlist = glGenLists(1); if (newlist != 0) { glNewList(newlist, GL_COMPILE); stat = 1; } else stat = -1; /* error */ } #endif return(stat); } /* PRIVATE */ int private_rmPrimitiveDisplayListEnd (RMpipe *pipe, RMprimitive *p, int needFinalize) { /* * when needFinalize != 0, we will assume that we need to * conclude construction of a display list. * * needFinalize might be non-zero when a primitive executes * it's own draw code rather than using a display list for * app-specific reasons, and we don't want to conclude construction * of a display list. */ if (needFinalize == 1) { GLuint list; int compListIndx = p->compListIndx; /* 8/29/02 debug code */ if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs) /* this should never happen - we should have performed the realloc before this point */ printf(" private_rmPrimitiveDisplayListEnd() error - the size of the primDisplayListIDs buffer is too small. compListIndx = %d, numPrimDisplayListIDs = %d.\n",compListIndx, pipe->contextCache->numPrimDisplayListIDs); list = pipe->contextCache->primDisplayListIDs[compListIndx]; glEndList(); #if 0 fprintf(stderr," calling list %d \n", list); fflush(stderr); glCallList(list); #endif private_glCallList(pipe, p, list); } return(1); } /* * PRIVATE: delete an OpenGL texture from a specific OpenGL context */ void private_rmOGLTextureDelete(RMtexture *toDelete, RMpipe *p) { int compListIndx; GLuint *id; compListIndx = toDelete->compListIndx; if (compListIndx >= p->contextCache->numTextureIDs) { #if 0 /* * a realloc at this point is a quasi-error condition. "Quasi" because * this code can be invoked on a texture that doesn't exist. This * happens occasionally from private_rmManageTextureState() in * rmframe.c. */ int newSize; int oldSize = p->contextCache->numTextureIDs; int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx); int numOldPages = oldSize/NUM_ITEMS_PER_PAGE; newSize = numNewPages * NUM_ITEMS_PER_PAGE; p->contextCache->textureIDs = (GLuint *)realloc(p->contextCache->textureIDs, newSize * sizeof(GLuint)); /* initialize new stuff to -1 */ memset((void *)(p->contextCache->textureIDs + oldSize), 0x00, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(GLuint)); p->contextCache->numTextureIDs = newSize; #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE) printf("private_rmOGLTextureDelete() - reallocating contextCache->textureIDs; oldSize = %d, newSize = %d \n", oldSize, newSize); #endif #endif } else { /* don't do a glIsTexture for something we know will obviously not be loaded. */ id = p->contextCache->textureIDs; if (glIsTexture(*(id+compListIndx)) == GL_TRUE) glDeleteTextures(1, id+compListIndx); *(id+compListIndx) = 0; } /* *(id+compListIndx) = 0; */ } void private_lightingStateManip(RMprimitive *p, RMstate *s, RMstateCache *rsc, RMenum forceNormals) { /* * 5/11/02 * lazy OpenGL state updates: * 1. if lighting is enabled and we don't want it, turn if off * 2. if lighting is off and we want it, turn it on. * * Assumption: that *any* normals stored in the primitive implies * that lighting should be enabled; absence of normals implies * lighting should be disabled. * * control over each individual light source is controlled at the * RMnode level; we are controlling whether or not lighting is * active here, not the attribs of a specific light source. * * it is assumed we want lighting if: * the RMprimitive has normal data OR forceNormals==RM_TRUE * */ int nnormals = 0; /* it would be nice to find a faster way to check for the presence of normal data in the RMprimitive rather than have to poke around in the blob pile. the easiest way would be to set a bit in the RMprimitive when normals data is loaded up. */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, NULL, &nnormals, NULL, NULL); if (forceNormals == RM_TRUE) nnormals++; /* make it non-zero */ /* if lighting is off and we want it, turn it on */ if ((nnormals != 0) && (rsc->lightingActive == RM_FALSE)) { glEnable(GL_LIGHTING); s->lightingActive = RM_TRUE; rsc->lightingActive = RM_TRUE; } /* if lighting is enabled and we don't want it, turn if off */ if ( ((s->shademodel == RM_SHADER_NOLIGHT) || (nnormals == 0)) && (rsc->lightingActive == RM_TRUE) ) { rsc->lightingActive = RM_FALSE; s->lightingActive = RM_FALSE; glDisable(GL_LIGHTING); } #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK) /* * debug code to read current lighting state from OpenGL and * compare it to the values in the state cache. You don't want * this test enabled in production code because it will slow you * down. Enable this code for debugging if you suspect lighting * state problems. */ { int oglLightingEnabled; glFinish(); oglLightingEnabled = glIsEnabled(GL_LIGHTING); if ((oglLightingEnabled == GL_TRUE) && (rsc->lightingActive != RM_TRUE)) rmError("private_lightingStateManip error: OpenGL lighting state != rm state"); if ((oglLightingEnabled == GL_FALSE) && (rsc->lightingActive != RM_FALSE)) rmError("private_lightingStateManip error: OpenGL lighting state != rm state"); } #endif } void private_colorMaterialStateManip(RMprimitive *p, RMstate *s, RMstateCache *rsc) { /* * 5/14/02 * lazy OpenGL state updates: * 1. if colormaterial is enabled and we don't want it, turn if off * 2. if colormaterial is off and we want it, turn it on. * * Assumption: that *any* colors stored in the primitive requires * use of glColorMaterial. */ int ncolors; /* it would be nice to find a faster way to check for the presence of color data in the RMprimitive rather than have to poke around in the blob pile. the easiest way would be to set a bit in the RMprimitive when color data is loaded up. */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, NULL, &ncolors, NULL, NULL); #if (DEBUG_LEVEL & DEBUG_RSTATECACHECHECK) /* debug code */ { int oglCMEnabled = glIsEnabled(GL_COLOR_MATERIAL); if ((oglCMEnabled == GL_TRUE) && (rsc->colorMaterialActive != RM_TRUE)) rmError("private_colorMaterialStateManipNew error: OpenGL colormaterial state ON, != rm state = OFF"); if ((oglCMEnabled == GL_FALSE) && (rsc->colorMaterialActive != RM_FALSE)) rmError("private_colorMaterialStateManipNew error: OpenGL colormaterial state OFF != rm state ON"); } #endif /* if colormaterial is off and we want it, turn it on */ if ((ncolors != 0) && (rsc->colorMaterialActive == RM_FALSE)) private_rmColorMaterial(s, rsc, RM_TRUE); /* if colormaterial is enabled and we don't want it, turn if off */ if (ncolors == 0) { if (rsc->colorMaterialActive == RM_TRUE) private_rmColorMaterial(s, rsc, RM_FALSE); } } void private_rmColorMaterial(RMstate *s, RMstateCache *rsc, RMenum newVal) { if (newVal == RM_TRUE) { glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); rsc->colorMaterialActive = RM_TRUE; } else { rsc->colorMaterialActive = RM_FALSE; glColor4fv((GLfloat *)&(s->unlit_color)); glDisable(GL_COLOR_MATERIAL); } } void private_textureStateManip(RMprimitive *p, RMstate *s, RMstateCache *rsc) { int ntc; private_rmGetBlobData(BLOB_TC_INDEX, p, NULL, &ntc, NULL, NULL); /* if lighting is off and we want it, turn it on */ if ((ntc != 0) && (rsc->texturingActive == RM_FALSE)) { glEnable(s->texture_mode); rsc->texturingActive = RM_TRUE; } /* if lighting is enabled and we don't want it, turn if off */ if ( ((ntc == 0)) && (rsc->texturingActive == RM_TRUE) ) { rsc->texturingActive = RM_FALSE; glDisable(s->texture_mode); } } /* * PRIVATE: private_glCallList(). this is a wrapper function for * glCallList. For CR applications, we issue a GL_OBJECT_BBOX_CR * call, then call the list, then turn off the GL_OBJECT_BBOX_CR. */ void private_glCallList(RMpipe *pipe, RMprimitive *prim, GLuint listIndx) { #ifdef RM_CR RMvertex3D bmin, bmax; RMenum useBox; useBox = rmPrimitiveGetBoundingBox(prim,&bmin,&bmax); /* check for null crStuff - this can happen when the app doesn't call rmPipeNew() using RM_PIPE_CR, but OpenRM is built using -DRM_CR */ #if 1 if ((pipe->crStuff != NULL) && (useBox == RM_CHILL)) { float fvec[6]; fvec[0] = bmin.x; fvec[1] = bmin.y; fvec[2] = bmin.z; fvec[3] = bmax.x; fvec[4] = bmax.y; fvec[5] = bmax.z; pipe->crStuff->glChromiumParametervCR(GL_OBJECT_BBOX_CR, GL_FLOAT, 6, (void *)fvec); #if (DEBUG_LEVEL & DEBUG_CR_BBOX) fprintf(stderr, "CR_BBOX: PE %d setting GL_OBJECT_BBOX_CR to (%g, %g, %g) - (%g, %g, %g) \n", pipe->myRank, fvec[0], fvec[1], fvec[2], fvec[3], fvec[4], fvec[5]); fflush(stderr); #endif } #endif #endif glCallList(listIndx); #ifdef RM_CR if ((pipe->crStuff != NULL) && (useBox == RM_CHILL)) { pipe->crStuff->glChromiumParametervCR(GL_DEFAULT_BBOX_CR, GL_FLOAT, 0, NULL); #if (DEBUG_LEVEL & DEBUG_CR_BBOX) fprintf(stderr, "CR_BBOX: PE %d setting GL_DEFAULT_BBOX_CR \n", pipe->myRank); fflush(stderr); #endif } #else /* foil compiler warnings */ pipe = NULL; prim = NULL; #endif } void * private_rmGLGetProcAddr(const char *funcName) { #ifdef RM_X void (GLAPIENTRY *fptr)() = NULL; GLubyte *newFName = (GLubyte *)malloc(sizeof(GLubyte)*(strlen(funcName)+1)); memcpy((void *)newFName, (void *)funcName, strlen(funcName)); newFName[strlen(funcName)] = '\0'; fptr = glXGetProcAddressARB(newFName); if (fptr == NULL) { char buf[256]; sprintf(buf, "private_rmGLGetProcAddress error: unable to find the routine named %s ", funcName); rmError(buf); } return fptr; #endif #ifdef RM_WIN PROC func; func = wglGetProcAddress(funcName); if (func == NULL) { char buf[256]; sprintf(buf, "private_rmGLGetProcAddress error: unable to find the routine named %s ", funcName); rmError(buf); } return (void *)(func); #endif } /* PRIVATE */ int private_glStateCheck(RMstate *s) { int rstat = 0; /* 0=OK, non-zero means error */ #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK) /* * Compare the contents of an RMstate with the current OpenGL state * and report any differences. This is a debug routine that should * not be used in production because it will slow things way down. */ /* shade model */ { GLint oglShadeModel; glGetIntegerv(GL_SHADE_MODEL, &oglShadeModel); switch (oglShadeModel) { case GL_SMOOTH: if (s->shademodel != RM_SHADER_SMOOTH) { rmError("private_glStateCheck - OpenGL shader == GL_SMOOTH, RM shader != RM_SHADER_SMOOTH "); rstat = 1; } break; case GL_FLAT: if ((s->shademodel != RM_SHADER_FLAT) && (s->shademodel != RM_SHADER_NOLIGHT)) { rmError("private_glStateCheck - OpenGL shader == GL_FLAT, RM shader != RM_SHADER_SMOOTH or RM_SHADER_NOLIGHT "); rstat = 1; } break; } } /* lighting */ { GLint oglLightingEnabled; glGetIntegerv(GL_LIGHTING, &oglLightingEnabled); if ((oglLightingEnabled == 1) && (s->lightingActive != RM_TRUE)) { rmError("private_glStateCheck - OpenGL lighting is enabled, but RM lighting is not. "); rstat = 1; } else if ((oglLightingEnabled == 0) && (s->lightingActive == RM_TRUE)) { rmError("private_glStateCheck - OpenGL lighting is NOT enabled, but RM lighting is enabled. "); rstat = 1; } } /* color material */ { GLint oglColorMaterialEnabled; glGetIntegerv(GL_COLOR_MATERIAL, &oglColorMaterialEnabled); if ((oglColorMaterialEnabled == 1) && (s->colorMaterialActive != RM_TRUE)) { rmError("private_glStateCheck - OpenGL COLOR_MATERIAL is enabled, but RM COLOR_MATERIAL is not. "); rstat = 1; } else if ((oglColorMaterialEnabled == 0) && (s->colorMaterialActive == RM_TRUE)) { rmError("private_glStateCheck - OpenGL COLOR_MATERIAL is NOT enabled, but RM COLOR_MATERIAL is enabled. "); rstat = 1; } } /* current color */ { GLfloat c[4]; RMcolor4D currentGLColor; glGetFloatv(GL_CURRENT_COLOR, c); currentGLColor.r = c[0]; currentGLColor.g = c[1]; currentGLColor.b = c[2]; currentGLColor.a = c[3]; if (private_rmColorsEqual(¤tGLColor, &(s->unlit_color)) == RM_FALSE) rstat = 0; } if (rstat == 0) rmNotice("private_glStateCheck - OK. "); else rmNotice("private_glStateCheck - not OK. "); #else s = NULL; /* foil compiler warning */ #endif return rstat; } /* EOF */