/* * 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: rmserial.c,v 1.9 2005/06/06 02:04:29 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.9 $ * $Log: rmserial.c,v $ * Revision 1.9 2005/06/06 02:04:29 wes * Lots of small additions to clean up compiler warnings. * * Revision 1.8 2005/02/19 16:44:25 wes * Distro sync and consolidation. * Better RMstate initialization and memory management. * * Revision 1.7 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.6 2004/09/28 00:48:57 wes * Added render state cache as a parameter to routines that may modify * lighting state to fix a lighting state tracking problem. * * Revision 1.5 2004/06/22 05:01:58 wes * Minor tweaks to support consistent state tracking. These changes * were made as a result to changes in the main RMSG tree during a * big PS bug fixing expedition. * * Revision 1.4 2004/01/16 16:48:35 wes * Updated copyright line for 2004. * * Revision 1.3 2003/11/16 16:19:40 wes * Removed "serial table" from picking operations. rmserial.c can probably * be removed from the source tree, and rmpick.c needs to have a bunch * of dead code surrounded by if 0's removed. * * Revision 1.2 2003/02/02 02:07:16 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.11 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.10 2002/12/04 14:50:33 wes * Cleanup SGI compiles. * * Revision 1.9 2002/06/17 01:03:00 wes * Replaced fixed-size table with one that is completely dynamic. No more * realloc error messages. * * Revision 1.8 2002/04/30 19:33:49 wes * Updated copyright dates. * * Revision 1.7 2001/05/26 14:37:49 wes * Added RMnode parameter to serialization code used in picking - this * will permit picking of scene graph subtrees that are disconnected * from rmRootNode(). * * Revision 1.6 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.5 2000/12/03 22:35:38 wes * Mods for thread safety. * * Revision 1.4 2000/05/17 14:24:34 wes * Fixed compiler warnings on private_rmStateInit(). * * Revision 1.3 2000/05/14 23:41:29 wes * Single parm change to RM state initialization (matrix stack control) * during serialization. * * 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. * */ #include #include "rmprivat.h" /* * this file contains a bunch of routines that are used to represent * the scene graph (a tree) in a serialized format. at this time (Jan 2000) * this is used for generating PostScript. * * there are no application-callable functions in this file. */ /* * * Last Updated: Thu Mar 6 12:09:08 PST 1997 * * TODO: * 1. the serial table size is hard-coded. it would be better to do * dynamic memory allocation. since the serialized table is used * (ie, built and accessed) only when we enter selection or feedback * rendering mode (to map tokens returned from OpenGL back to object * handles), this is not really a time crucial step. the conclusion is * that we can afford to spend a little extra time doing dynamic * allocation. * * -> the hard-coded limit has been fixed as of 6/12/02. the thread- * safety issues will be a relatively straightforward modification * but will wait until there is sufficient popular demand. * * 2. thread-safety issues have not been considered in the building of * this code. * * NOTE: dependancy upon object structure. * * when feedback mode in opengl is used, tokens are passed back to * the application. we make special use of the passthrough token * so as to identify the object, the primitive and the particular * item in the primitive which is being rendered. the reason for * this is so that later we can refer back to the original object * if need be. * * when stuff is added to the serial table, we need: * - a pointer to an rmNode * - an integer identifying which primitive is being rendered * * the passthrough token which is generated will be a function of these 2. */ #define SERIAL_TABLE_BASE_SIZE 2048 #define SERIAL_TABLE_REALLOC_SIZE 1024 static int serialized_size = 0; /* current size */ static int serialized_max_size = 0; /* max current size */ static RMSerialNodeList *serialized_list=NULL; /* PRIVATE */ static void private_rmAddToSerialTable (RMnode *r, int *n, int *totalNodesAccum, int *totalPrimsAccum) { if (serialized_size + 1 >= serialized_max_size) { serialized_max_size += SERIAL_TABLE_REALLOC_SIZE; serialized_list = (RMSerialNodeList *)realloc(serialized_list, sizeof(RMSerialNodeList)*serialized_max_size); #if (DEBUG_LEVEL & DEBUG_TRACE) printf(" private_rmAddToSerialTable realloc initiated. Old size = %d, new size = %d. \n", serialized_max_size - SERIAL_TABLE_REALLOC_SIZE, serialized_max_size); #endif } serialized_list[*n].node = r; serialized_list[*n].index = *n; *n += 1; serialized_size += 1; *totalNodesAccum += 1; *totalPrimsAccum += r->nprims; } /* PRIVATE */ static void private_rmBuildSerial (RMnode *r, int *n, int *totalNodesAccum, int *totalPrimsAccum) { int i; /* add this node to the table */ private_rmAddToSerialTable(r, n, totalNodesAccum, totalPrimsAccum); /* then, process all descendants */ for (i = 0; i < r->nchildren; i++) private_rmBuildSerial(r->children[i], n, totalNodesAccum, totalPrimsAccum); } /* PRIVATE */ int private_rmBuildSerializedList (RMnode *subTree, int *totalNodesReturn, int *totalPrimsReturn) { /* * modified 6/12/02 to compute and return the number of nodes and * primitives detected while building of the "serial table". */ int n; RMnode *r; int totalPrims=0, totalNodes=0; /* * initialize the serial table. */ if (serialized_list != NULL) { free((void *)serialized_list); serialized_size = serialized_max_size = 0; } serialized_list = (RMSerialNodeList *)(malloc(sizeof(RMSerialNodeList)*SERIAL_TABLE_BASE_SIZE)); serialized_max_size = SERIAL_TABLE_BASE_SIZE; serialized_size = 0; /* traverse tree, build serialized list. */ n = 0; r = subTree; private_rmBuildSerial(r, &n, &totalNodes, &totalPrims); #if (DEBUG_LEVEL & DEBUG_TRACE) printf(" private_BuildSerializedList reality check: serialized_size = %d, n = %d \n", serialized_size, n); #endif serialized_size = n; *totalNodesReturn = totalNodes; *totalPrimsReturn = totalPrims; return 0; } /* PRIVATE */ int private_rmIndexFromSerial (const RMnode *r) { /* scan through the serialized list and return the index of the * first entry containing "r". if we don't find such an entry, * return -1. */ int i; for (i = 0; i < serialized_size; i++) if (serialized_list[i].node == r) return(i); return(-1); } /* PRIVATE */ RMnode * private_rmNodeFromSerial (int index) { /* scan through the serialized list and return the index of the * first entry containing the index "index". if we don't find such an * entry, return NULL. */ int i; for (i = 0; i < serialized_size; i++) if (serialized_list[i].index == index) return(serialized_list[i].node); return(NULL); } #if 0 /* PRIVATE * * not needed till we do dynamic allocation for serial table */ void private_rmFreeSerializedList () { /* free serialized list */ } #endif typedef struct { RMstate *s; int indx; } RMserialState; /* really this is an inverse stack */ static RMserialState *rStateStack = NULL; static int rStateStackDepth = 0; /* PRIVATE */ RMserialState * private_rmSerialStateNew () { RMserialState *t; t = (RMserialState *)malloc(sizeof(RMserialState)); if (RM_ASSERT(t,"rmSerialStateNew() unable to malloc a new state node ") == RM_WHACKED) return(NULL); t->indx = 0; t->s = NULL; return(t); } /* PRIVATE */ void private_rmSerialStateInit(void) { if (rStateStack != NULL) private_rmDeleteSerialState(); rStateStack = private_rmSerialStateNew(); rStateStackDepth = 0; } /* PRIVATE */ int private_rmDeleteSerialState (void) { int i; for (i = 0; i < rStateStackDepth; i++) free((void *)(rStateStack[i].s)); free((void *)(rStateStack)); rStateStack = NULL; rStateStackDepth = 0; return(RM_CHILL); } /* PRIVATE */ RMstate * private_rmStateFromSerial (int indx) { /* return(rStateStack[indx-1].s); huh? why -1? */ return(rStateStack[indx].s); } /* PRIVATE */ int private_pushSerialState (RMstate *s) { RMstate *t; RMserialState *ts; t = rmStateNew(); rmStateCopy(s, t); rStateStack = realloc((void *)rStateStack, (sizeof(RMserialState) * (rStateStackDepth + 1))); ts = rStateStack + rStateStackDepth; ts->s = t; ts->indx = rStateStackDepth; rStateStackDepth++; return(RM_CHILL); } /* PRIVATE */ int private_rmBuildSerialState (RMpipe *p, RMnode *r, RMstate *last, int init) { int i, stateChange = 0; RMstate *s = rmStateNew(); if (init == 1) { private_rmStateInit(p, s, (RMenum)GL_RENDER, NULL, NULL, NULL, NULL); /* could do some checking to free up old stack.. */ rStateStackDepth = 0; } /* drag along the previous one? */ if (rStateStackDepth != 0) rmStateCopy(last, s); private_collectAndApplyMatrices (s, r, NULL, GL_RENDER, &stateChange, RM_FALSE); stateChange |= private_updateSceneParms(r, s, RM_FALSE, 0, NULL, NULL); if (stateChange == 1) /* add to stack */ { RMserialState *t; rStateStack = realloc((void *)rStateStack, (sizeof(RMserialState) * (rStateStackDepth + 1))); t = rStateStack + rStateStackDepth; t->s = s; t->indx = rStateStackDepth; rStateStackDepth++; } /* then recurse */ for (i = 0; i < r->nchildren; i++) private_rmBuildSerialState(p, r->children[i], s, 0); if (stateChange == 0) rmStateDelete(s); return(RM_CHILL); } /* EOF */