/* * 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: rmrstate.c,v 1.7 2005/06/26 19:01:36 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.7 $ * $Log: rmrstate.c,v $ * Revision 1.7 2005/06/26 19:01:36 wes * Use new routine to compute viewport matrix. * * Revision 1.6 2005/02/19 16:28:54 wes * Distro sync and consolidation. * Fixes for a number of state tracking buglets. * * Revision 1.5 2004/12/11 16:19:14 wes * Fixed bug in how RMstate->aspect_ratio was computed. * * Revision 1.4 2004/01/16 16:48:35 wes * Updated copyright line for 2004. * * Revision 1.3 2003/06/14 16:24:20 wes * Minor documentation tweaks. * * 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.9 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.8 2002/06/17 01:02:37 wes * Added back in code that syncs the lighting state between the render * state cache and the RMrstate used during rendering. * * Revision 1.7 2002/06/02 15:16:27 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.6 2002/04/30 19:33:26 wes * Updated copyright dates. * * Revision 1.5 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.4 2000/08/23 23:28:50 wes * Assertions added to some routines. * * Revision 1.3 2000/05/14 23:37:11 wes * Added control via RMpipe attribute to how OpenGL matrix stack * is initialized or used during rendering. * * 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" /* * ---------------------------------------------------- * @Name rmStateNew @pstart RMstate *rmStateNew (void) @pend @astart No arguments. @aend @dstart Create and initialize an RMstate object, meaning that all RMstate matrices are set to the identity. Upon success, a handle to the new RMstate is returned to the caller. Otherwise, a NULL pointer is returned to the caller. @dend * ---------------------------------------------------- */ RMstate * rmStateNew (void) { RMstate *t = (RMstate *)malloc(sizeof(RMstate)); if (RM_ASSERT(t, "rmStateNew() malloc failure") == RM_WHACKED) return(NULL); memset(t, 0, sizeof(RMstate)); /* initialize everything the right way, set matrices to I */ rmMatrixIdentity(&(t->model)); rmMatrixIdentity(&(t->view)); rmMatrixIdentity(&(t->modelView)); rmMatrixIdentity(&(t->composite)); rmMatrixIdentity(&(t->pick)); rmMatrixIdentity(&(t->projection)); rmMatrixIdentity(&(t->projection_inverse)); rmMatrixIdentity(&(t->textureMatrix)); return(t); } /* * ---------------------------------------------------- * @Name rmStateDelete @pstart void rmStateDelete (RMstate *s) @pend @astart RMstate *s - a handle to the RMstate object to delete (modified). @aend @dstart Frees the resources for an RMstate object. No error checking is performed, so the result of deleting a non-object will be system-dependent (generllay this is something to avoid). No status is returned. @dend * ---------------------------------------------------- */ void rmStateDelete (RMstate *s) { if (RM_ASSERT(s,"rmStateDelete() error: the input RMstate object is NULL.") == RM_WHACKED) return; free((void *)s); } /* * ---------------------------------------------------- * @Name rmStateCopy @pstart void rmStateCopy (const RMstate *s, RMstate *d) @pend @astart const RMstate *s - a handle to the source RMstate (input). RMstate *d - a handle to the destination RMstate (modified). @aend @dstart Copies the RMstate object s to the RMstate object d. No error checking is performed, so the copy is only valid if s and d are valid RMstate objects. No status is returned. @dend * ---------------------------------------------------- */ void rmStateCopy (const RMstate *s, RMstate *d) { if ((RM_ASSERT(s,"rmStateCopy() error: the input RMstate object is NULL") == RM_WHACKED) || (RM_ASSERT(d,"rmStateCopy() error: the destination RMstate object is NULL") == RM_WHACKED)) return; memcpy((void *)d, (void *)s, sizeof(RMstate)); } /* * ---------------------------------------------------- * @Name rmStateGetModelViewMatrix @pstart const RMmatrix *rmStateGetModelViewMatrix (const RMstate *toQuery) @pend @astart const RMstate *toQuery - a handle to an RMstate object (input). @aend @dstart During a render-time traversal, the RMstate object reflects the current state of many rendering parameters as affected by nodes in the scene graph. The RMstate object is provided to node callback functions as a parameter. The rmStateGet*() family of routines can be used by developers to obtain current render state parameters. This routine is used to obtain a handle to the OpenGL "model-view" matrix. The modelView matrix is the concatenation of model transformations with the view transformation defined by the current camera. The RMmatrix handle that is returned is "read only." NULL is returned if the input RMstate object is NULL. @dend * ---------------------------------------------------- */ const RMmatrix * rmStateGetModelViewMatrix (const RMstate *s) { if (RM_ASSERT(s, "rmStateGetModelViewMatrix() error: the input RMstate object is NULL.\n") == RM_WHACKED) return(NULL); return(&(s->modelView)); } /* * ---------------------------------------------------- * @Name rmStateGetProjectionMatrix @pstart const RMmatrix *rmStateGetProjectionMatrix (const RMstate *toQuery) @pend @astart const RMstate *toQuery - a handle to an RMstate object (input). @aend @dstart During a render-time traversal, the RMstate object reflects the current state of many rendering parameters as affected by nodes in the scene graph. The RMstate object is provided to node callback functions as a parameter. The rmStateGet*() family of routines can be used by developers to obtain current render state parameters. This routine is used to obtain a handle to the OpenGL "projection" matrix. The projection matrix represents the transformation from eye coordinates to clip coordinates, typically defined only by 3D cameras. The RMmatrix handle that is returned is "read only." NULL is returned if the input RMstate object is NULL. @dend * ---------------------------------------------------- */ const RMmatrix * rmStateGetProjectionMatrix (const RMstate *s) { if (RM_ASSERT(s, "rmStateGetModelViewMatrix() error: the input RMstate object is NULL.\n") == RM_WHACKED) return(NULL); return(&(s->projection)); } /* * ---------------------------------------------------- * @Name rmStateGetShader @pstart RMenum rmStateGetShader(const RMstate *toQuery) @pend @astart const RMstate *toQuery - a handle to an RMstate object (input). @aend @dstart Use this routine to obtain the shader attribute of an RMstate object. Upon success, one of the RM shade model enumerators is returned to the caller (RM_SHADER_SMOOTH, RM_SHADER_FLAT or RM_SHADER_NOLIGHT). Otherwise, RM_WHACKED is returned. This routine is intended to be used from inside application callback code, either node callbacks or application-defined RMprimitive draw routines. @dend * ---------------------------------------------------- */ RMenum rmStateGetShader(const RMstate *s) { if (RM_ASSERT(s,"rmStateGetShader() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); return(s->shademodel); } /* * ---------------------------------------------------- * @Name rmStateGetPolygonDrawMode @pstart RMenum rmStateGetPolygonDrawMode(const RMstate *toQuery, RMenum *whichFaceReturn, RMenum *drawModeReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). RMenum *whichFaceReturn, *drawModeReturn - handles to caller-supplied RMenum's (result). A value of NULL is acceptable. @aend @dstart Use this routine to query the render-time values for the polygon draw mode. See rmNodeSetPolygonDrawMode() for more details about these parameters. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. If the caller specifies NULL for one of the return parameters, that value will not be queried. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetPolygonDrawMode(const RMstate *s, RMenum *whichFaceReturn, RMenum *drawModeReturn) { if (RM_ASSERT(s,"rmStateGetPolygonDrawMode() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (whichFaceReturn != NULL) *whichFaceReturn = s->poly_mode_face; if (drawModeReturn != NULL) *drawModeReturn = s->poly_mode_drawstyle; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetPolygonCullMode @pstart RMenum rmStateGetPolygonCullMode(const RMstate *toQuery, RMenum *cullModeReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). RMenum *cullModeReturn - handles to caller-supplied RMenum's (result). A value of NULL is acceptable. @aend @dstart Use this routine to query the render-time values for the polygon cull mode. See rmNodeSetPolygonCullMode() for more details about this parameter. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. If the caller specifies NULL for the return parameter, the polygon cull mode from the RMstate object will not be copied into caller-supplied memory. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetPolygonCullMode(const RMstate *s, RMenum *cullModeReturn) { if (RM_ASSERT(s,"rmStateGetPolygonCullMode() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (cullModeReturn != NULL) *cullModeReturn = s->cull_mode; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetFrontFace @pstart RMenum rmStateGetFrontFace(const RMstate *toQuery, RMenum *frontFaceReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). RMenum *frontFaceReturn - a handle to a caller-supplied RMenum (result). @aend @dstart Use this routine to query the render-time values for the polygon front face attribute. See rmNodeSetFrontFace() for more details about this parameter. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. If the caller specifies NULL for the return parameter, the polygon front face mode from the RMstate object will not be copied into caller-supplied memory. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetFrontFace(const RMstate *s, RMenum *frontFaceReturn) { if (RM_ASSERT(s,"rmStateGetFrontFace() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (frontFaceReturn != NULL) *frontFaceReturn = s->front_face; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetLineWidth @pstart RMenum rmStateGetLineWidth(const RMstate *toQuery, RMenum *lineWidthReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). RMenum *lineStyleReturn - a handle to a caller-supplied RMenum (result). @aend @dstart Use this routine to query the render-time values for the current line style attribute. See rmNodeSetLineWidth() for more details about this parameter. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. Note that an RM line width enumerator is returned, not the actual pixel width of the lines. If the caller specifies NULL for the return parameter, the line style attribute from the RMstate object will not be copied into caller-supplied memory. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetLineWidth(const RMstate *s, RMenum *lineWidthReturn) { if (RM_ASSERT(s,"rmStateGetLineWidth() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (lineWidthReturn != NULL) *lineWidthReturn = s->linewidth; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetLineStyle @pstart RMenum rmStateGetLineStyle(const RMstate *toQuery, RMenum *lineStyleReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). RMenum *lineStyleReturn - a handle to a caller-supplied RMenum (result). @aend @dstart Use this routine to query the render-time values for the current line style attribute. See rmNodeSetLineStyle() for more details about this parameter. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. If the caller specifies NULL for the return parameter, the line style attribute from the RMstate object will not be copied into caller-supplied memory. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetLineStyle(const RMstate *s, RMenum *lineStyleReturn) { if (RM_ASSERT(s,"rmStateGetLineStyle() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (lineStyleReturn != NULL) *lineStyleReturn = s->linestyle; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetPointSize @pstart RMenum rmStateGetPointSize(const RMstate *toQuery, float *sizeReturn) @pend @astart const RMstate *toQuery - a handle to an RMnode (input). float *sizeReturn - a handle to a caller-supplied float (result). @aend @dstart Use this routine to query the render-time values for the current point size attribute. See rmNodeSetPointSize() for more details about this parameter. This routine is intended to be used from inside an application callback that would be attached to an RMnode, to be invoked during a render-time traversal of the scene graph. If the caller specifies NULL for the return parameter, the point size attribute from the RMstate object will not be copied into caller-supplied memory. RM_CHILL is returned upon success. Upon failure, RM_WHACKED is returned, and caller supplied memory remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmStateGetPointSize(const RMstate *s, float *sizeReturn) { if (RM_ASSERT(s,"rmStateGetPointSize() error: the input RMstate object is NULL") == RM_WHACKED) return(RM_WHACKED); if (sizeReturn != NULL) *sizeReturn = s->pointsize; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmStateGetFrameNumber @pstart int rmStateGetFrameNumber(const RMstate *toQuery) @pend @astart const RMstate *toQuery - a handle to an RMstate object. @aend @dstart Use this routine to query the render-time frame number from the RMstate object "toQuery." This routine is intended to be used by application- supplied render- or view-traversal callback routines in order to implement operations that are a function of the current frame number. @dend * ---------------------------------------------------- */ int rmStateGetFrameNumber(const RMstate *toQuery) { if (RM_ASSERT(toQuery, "rmStateGetFrameNumber error(): the input RMstate object is NULL. The returned frame number is invalid. ") == RM_WHACKED) return(0); else return(toQuery->frameNumber); } /* PRIVATE */ void private_rmStateInit (const RMpipe *p, RMstate *s, RMenum rendermode, RMmatrix *model, RMmatrix *view, RMmatrix *proj, RMmatrix *texture) { memset(s, 0, sizeof(RMstate)); if (view != NULL) rmMatrixCopy(&(s->view), view); else rmMatrixIdentity(&(s->view)); if (model != NULL) rmMatrixCopy(&(s->model), model); else rmMatrixIdentity(&(s->model)); if (proj != NULL) rmMatrixCopy(&(s->projection), proj); else rmMatrixIdentity(&(s->projection)); if (texture != NULL) rmMatrixCopy(&(s->textureMatrix), texture); else rmMatrixIdentity(&(s->textureMatrix)); rmMatrixIdentity(&(s->pick)); rmMatrixInverse(&(s->projection), &(s->projection_inverse)); rmMatrixMultiply(&(s->model), &(s->view), &(s->modelView)); rmMatrixMultiply(&(s->modelView), &(s->projection), &(s->composite)); if (p != NULL) { float fw, fh; rmPipeGetWindowSize(p, &(s->w), &(s->h)); /* * in the RMstate structure, viewport settings are in pixel, * not NDC coordinates. */ /* * we assign the default viewport to take up the entire screen. * eventually, we want to be able to take into account any * existing viewport value that might be set. */ fw = (float)s->w; fh = (float)s->h; s->vp[0] = s->vp[1] = 0.0F; s->vp[2] = fw; s->vp[3] = fh; /* set the viewport matrix */ private_rmComputeViewportMatrix(s->vp, fw, fh, &(s->vpm)); s->aspect_ratio = fw/fh; s->frameNumber = p->frameNumber; } s->rendermode = rendermode; #if 0 /* is this necessary/correct here? */ s->colorMaterialActive = RM_FALSE; s->lightingActive = RM_FALSE; #endif } RMstateCache * private_rmStateCacheNew (void) { RMstateCache *t = malloc(sizeof(RMstateCache)); t->colorMaterialActive = RM_FALSE; t->lightingActive = RM_FALSE; t->texturingActive = RM_FALSE; return(t); } void private_rmStateCacheDelete(RMstateCache *t) { free((void *)t); } void private_rmStateCacheSync(const RMstate *s, RMstateCache *rsc) { /* check texturing */ if ((s->texture_mode != 0) && (rsc->texturingActive == RM_FALSE)) rsc->texturingActive = RM_TRUE; else if ((s->texture_mode == 0) && (rsc->texturingActive == RM_TRUE)) rsc->texturingActive = RM_FALSE; /* check lighting */ if ((s->lightingActive == RM_TRUE) && (rsc->lightingActive == RM_FALSE)) rsc->lightingActive = RM_TRUE; else if ((s->lightingActive == RM_FALSE) && (rsc->lightingActive == RM_TRUE)) rsc->lightingActive = RM_FALSE; /* check color material state */ if ((s->colorMaterialActive == RM_TRUE) && (rsc->colorMaterialActive == RM_FALSE)) rsc->colorMaterialActive = RM_TRUE; else if ((s->colorMaterialActive == RM_FALSE) && (rsc->colorMaterialActive == RM_TRUE)) rsc->colorMaterialActive = RM_FALSE; } void private_rmSyncStateToCache(RMstateCache *rsc, RMstate *s) { /* sync the RMstate to the values indicated in the rsc */ #if 0 /* check texturing */ if ((s->texture_mode != 0) && (rsc->texturingActive == RM_FALSE)) s->texturingActive = RM_TRUE; else if ((s->texture_mode == 0) && (rsc->texturingActive == RM_TRUE)) rsc->texturingActive = RM_FALSE; #endif /* check lighting */ if ((s->lightingActive == RM_TRUE) && (rsc->lightingActive == RM_FALSE)) s->lightingActive = RM_FALSE; else if ((s->lightingActive == RM_FALSE) && (rsc->lightingActive == RM_TRUE)) s->lightingActive = RM_TRUE; /* check color material state */ if ((s->colorMaterialActive == RM_TRUE) && (rsc->colorMaterialActive == RM_FALSE)) s->colorMaterialActive = RM_FALSE; else if ((s->colorMaterialActive == RM_FALSE) && (rsc->colorMaterialActive == RM_TRUE)) s->colorMaterialActive = RM_TRUE; } /* EOF */