1 /*
2 * Copyright (C) 1997-2005, R3vis Corporation.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18 *
19 * Original Contributor:
20 * Wes Bethel, R3vis Corporation, Marin County, California
21 * Additional Contributor(s):
22 *
23 * The OpenRM project is located at http://openrm.sourceforge.net/.
24 */
25 /*
26 * $Id: rmserial.c,v 1.9 2005/06/06 02:04:29 wes Exp $
27 * Version: $Name: OpenRM-1-6-0-2-RC2 $
28 * $Revision: 1.9 $
29 * $Log: rmserial.c,v $
30 * Revision 1.9 2005/06/06 02:04:29 wes
31 * Lots of small additions to clean up compiler warnings.
32 *
33 * Revision 1.8 2005/02/19 16:44:25 wes
34 * Distro sync and consolidation.
35 * Better RMstate initialization and memory management.
36 *
37 * Revision 1.7 2005/01/23 17:00:22 wes
38 * Copyright updated to 2005.
39 *
40 * Revision 1.6 2004/09/28 00:48:57 wes
41 * Added render state cache as a parameter to routines that may modify
42 * lighting state to fix a lighting state tracking problem.
43 *
44 * Revision 1.5 2004/06/22 05:01:58 wes
45 * Minor tweaks to support consistent state tracking. These changes
46 * were made as a result to changes in the main RMSG tree during a
47 * big PS bug fixing expedition.
48 *
49 * Revision 1.4 2004/01/16 16:48:35 wes
50 * Updated copyright line for 2004.
51 *
52 * Revision 1.3 2003/11/16 16:19:40 wes
53 * Removed "serial table" from picking operations. rmserial.c can probably
54 * be removed from the source tree, and rmpick.c needs to have a bunch
55 * of dead code surrounded by if 0's removed.
56 *
57 * Revision 1.2 2003/02/02 02:07:16 wes
58 * Updated copyright to 2003.
59 *
60 * Revision 1.1.1.1 2003/01/28 02:15:23 wes
61 * Manual rebuild of rm150 repository.
62 *
63 * Revision 1.11 2003/01/16 22:21:17 wes
64 * Updated all source files to reflect new organization of header files:
65 * all header files formerly located in include/rmaux, include/rmi, include/rmv
66 * are now located in include/rm.
67 *
68 * Revision 1.10 2002/12/04 14:50:33 wes
69 * Cleanup SGI compiles.
70 *
71 * Revision 1.9 2002/06/17 01:03:00 wes
72 * Replaced fixed-size table with one that is completely dynamic. No more
73 * realloc error messages.
74 *
75 * Revision 1.8 2002/04/30 19:33:49 wes
76 * Updated copyright dates.
77 *
78 * Revision 1.7 2001/05/26 14:37:49 wes
79 * Added RMnode parameter to serialization code used in picking - this
80 * will permit picking of scene graph subtrees that are disconnected
81 * from rmRootNode().
82 *
83 * Revision 1.6 2001/03/31 17:12:39 wes
84 * v1.4.0-alpha-2 checkin.
85 *
86 * Revision 1.5 2000/12/03 22:35:38 wes
87 * Mods for thread safety.
88 *
89 * Revision 1.4 2000/05/17 14:24:34 wes
90 * Fixed compiler warnings on private_rmStateInit().
91 *
92 * Revision 1.3 2000/05/14 23:41:29 wes
93 * Single parm change to RM state initialization (matrix stack control)
94 * during serialization.
95 *
96 * Revision 1.2 2000/04/20 16:29:47 wes
97 * Documentation additions/enhancements, some code rearragement.
98 *
99 * Revision 1.1.1.1 2000/02/28 21:29:40 wes
100 * OpenRM 1.2 Checkin
101 *
102 * Revision 1.1.1.1 2000/02/28 17:18:48 wes
103 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
104 *
105 */
106
107
108 #include <rm/rm.h>
109 #include "rmprivat.h"
110
111 /*
112 * this file contains a bunch of routines that are used to represent
113 * the scene graph (a tree) in a serialized format. at this time (Jan 2000)
114 * this is used for generating PostScript.
115 *
116 * there are no application-callable functions in this file.
117 */
118
119 /*
120 *
121 * Last Updated: Thu Mar 6 12:09:08 PST 1997
122 *
123 * TODO:
124 * 1. the serial table size is hard-coded. it would be better to do
125 * dynamic memory allocation. since the serialized table is used
126 * (ie, built and accessed) only when we enter selection or feedback
127 * rendering mode (to map tokens returned from OpenGL back to object
128 * handles), this is not really a time crucial step. the conclusion is
129 * that we can afford to spend a little extra time doing dynamic
130 * allocation.
131 *
132 * -> the hard-coded limit has been fixed as of 6/12/02. the thread-
133 * safety issues will be a relatively straightforward modification
134 * but will wait until there is sufficient popular demand.
135 *
136 * 2. thread-safety issues have not been considered in the building of
137 * this code.
138 *
139 * NOTE: dependancy upon object structure.
140 *
141 * when feedback mode in opengl is used, tokens are passed back to
142 * the application. we make special use of the passthrough token
143 * so as to identify the object, the primitive and the particular
144 * item in the primitive which is being rendered. the reason for
145 * this is so that later we can refer back to the original object
146 * if need be.
147 *
148 * when stuff is added to the serial table, we need:
149 * - a pointer to an rmNode
150 * - an integer identifying which primitive is being rendered
151 *
152 * the passthrough token which is generated will be a function of these 2.
153 */
154 #define SERIAL_TABLE_BASE_SIZE 2048
155 #define SERIAL_TABLE_REALLOC_SIZE 1024
156
157 static int serialized_size = 0; /* current size */
158 static int serialized_max_size = 0; /* max current size */
159 static RMSerialNodeList *serialized_list=NULL;
160
161 /* PRIVATE */
162 static void
private_rmAddToSerialTable(RMnode * r,int * n,int * totalNodesAccum,int * totalPrimsAccum)163 private_rmAddToSerialTable (RMnode *r, int *n,
164 int *totalNodesAccum,
165 int *totalPrimsAccum)
166 {
167 if (serialized_size + 1 >= serialized_max_size)
168 {
169 serialized_max_size += SERIAL_TABLE_REALLOC_SIZE;
170 serialized_list = (RMSerialNodeList *)realloc(serialized_list, sizeof(RMSerialNodeList)*serialized_max_size);
171
172 #if (DEBUG_LEVEL & DEBUG_TRACE)
173 printf(" private_rmAddToSerialTable realloc initiated. Old size = %d, new size = %d. \n", serialized_max_size - SERIAL_TABLE_REALLOC_SIZE, serialized_max_size);
174 #endif
175 }
176
177 serialized_list[*n].node = r;
178 serialized_list[*n].index = *n;
179 *n += 1;
180 serialized_size += 1;
181
182 *totalNodesAccum += 1;
183 *totalPrimsAccum += r->nprims;
184 }
185
186
187 /* PRIVATE */
188 static void
private_rmBuildSerial(RMnode * r,int * n,int * totalNodesAccum,int * totalPrimsAccum)189 private_rmBuildSerial (RMnode *r, int *n,
190 int *totalNodesAccum,
191 int *totalPrimsAccum)
192 {
193 int i;
194
195 /* add this node to the table */
196 private_rmAddToSerialTable(r, n, totalNodesAccum, totalPrimsAccum);
197
198 /* then, process all descendants */
199 for (i = 0; i < r->nchildren; i++)
200 private_rmBuildSerial(r->children[i], n, totalNodesAccum, totalPrimsAccum);
201
202 }
203
204
205 /* PRIVATE */
206 int
private_rmBuildSerializedList(RMnode * subTree,int * totalNodesReturn,int * totalPrimsReturn)207 private_rmBuildSerializedList (RMnode *subTree,
208 int *totalNodesReturn,
209 int *totalPrimsReturn)
210 {
211 /*
212 * modified 6/12/02 to compute and return the number of nodes and
213 * primitives detected while building of the "serial table".
214 */
215 int n;
216 RMnode *r;
217 int totalPrims=0, totalNodes=0;
218
219 /*
220 * initialize the serial table.
221 */
222 if (serialized_list != NULL)
223 {
224 free((void *)serialized_list);
225 serialized_size = serialized_max_size = 0;
226 }
227
228 serialized_list = (RMSerialNodeList *)(malloc(sizeof(RMSerialNodeList)*SERIAL_TABLE_BASE_SIZE));
229 serialized_max_size = SERIAL_TABLE_BASE_SIZE;
230 serialized_size = 0;
231
232 /* traverse tree, build serialized list. */
233 n = 0;
234 r = subTree;
235 private_rmBuildSerial(r, &n, &totalNodes, &totalPrims);
236
237 #if (DEBUG_LEVEL & DEBUG_TRACE)
238 printf(" private_BuildSerializedList reality check: serialized_size = %d, n = %d \n", serialized_size, n);
239 #endif
240
241 serialized_size = n;
242 *totalNodesReturn = totalNodes;
243 *totalPrimsReturn = totalPrims;
244 return 0;
245 }
246
247
248 /* PRIVATE */
249 int
private_rmIndexFromSerial(const RMnode * r)250 private_rmIndexFromSerial (const RMnode *r)
251 {
252 /* scan through the serialized list and return the index of the
253 * first entry containing "r". if we don't find such an entry,
254 * return -1.
255 */
256
257 int i;
258
259 for (i = 0; i < serialized_size; i++)
260 if (serialized_list[i].node == r)
261 return(i);
262
263 return(-1);
264 }
265
266
267 /* PRIVATE */
268 RMnode *
private_rmNodeFromSerial(int index)269 private_rmNodeFromSerial (int index)
270 {
271 /* scan through the serialized list and return the index of the
272 * first entry containing the index "index". if we don't find such an
273 * entry, return NULL.
274 */
275 int i;
276
277 for (i = 0; i < serialized_size; i++)
278 if (serialized_list[i].index == index)
279 return(serialized_list[i].node);
280
281 return(NULL);
282 }
283
284
285 #if 0
286 /* PRIVATE
287 *
288 * not needed till we do dynamic allocation for serial table
289 */
290 void
291 private_rmFreeSerializedList ()
292 {
293 /* free serialized list */
294
295 }
296 #endif
297
298
299 typedef struct
300 {
301 RMstate *s;
302 int indx;
303 } RMserialState;
304
305 /* really this is an inverse stack */
306 static RMserialState *rStateStack = NULL;
307 static int rStateStackDepth = 0;
308
309 /* PRIVATE */
310 RMserialState *
private_rmSerialStateNew()311 private_rmSerialStateNew ()
312 {
313 RMserialState *t;
314
315 t = (RMserialState *)malloc(sizeof(RMserialState));
316
317 if (RM_ASSERT(t,"rmSerialStateNew() unable to malloc a new state node ") == RM_WHACKED)
318 return(NULL);
319
320 t->indx = 0;
321 t->s = NULL;
322
323 return(t);
324 }
325
326 /* PRIVATE */
327 void
private_rmSerialStateInit(void)328 private_rmSerialStateInit(void)
329 {
330 if (rStateStack != NULL)
331 private_rmDeleteSerialState();
332
333 rStateStack = private_rmSerialStateNew();
334 rStateStackDepth = 0;
335 }
336
337 /* PRIVATE */
338 int
private_rmDeleteSerialState(void)339 private_rmDeleteSerialState (void)
340 {
341 int i;
342
343 for (i = 0; i < rStateStackDepth; i++)
344 free((void *)(rStateStack[i].s));
345
346 free((void *)(rStateStack));
347 rStateStack = NULL;
348 rStateStackDepth = 0;
349
350 return(RM_CHILL);
351 }
352
353
354 /* PRIVATE */
355 RMstate *
private_rmStateFromSerial(int indx)356 private_rmStateFromSerial (int indx)
357 {
358 /* return(rStateStack[indx-1].s); huh? why -1? */
359 return(rStateStack[indx].s);
360 }
361
362
363 /* PRIVATE */
364 int
private_pushSerialState(RMstate * s)365 private_pushSerialState (RMstate *s)
366 {
367 RMstate *t;
368 RMserialState *ts;
369
370 t = rmStateNew();
371 rmStateCopy(s, t);
372
373 rStateStack = realloc((void *)rStateStack, (sizeof(RMserialState) * (rStateStackDepth + 1)));
374 ts = rStateStack + rStateStackDepth;
375
376 ts->s = t;
377 ts->indx = rStateStackDepth;
378
379 rStateStackDepth++;
380
381 return(RM_CHILL);
382 }
383
384
385 /* PRIVATE */
386 int
private_rmBuildSerialState(RMpipe * p,RMnode * r,RMstate * last,int init)387 private_rmBuildSerialState (RMpipe *p,
388 RMnode *r,
389 RMstate *last,
390 int init)
391
392 {
393 int i, stateChange = 0;
394 RMstate *s = rmStateNew();
395
396 if (init == 1)
397 {
398 private_rmStateInit(p, s, (RMenum)GL_RENDER, NULL, NULL, NULL, NULL);
399 /* could do some checking to free up old stack.. */
400 rStateStackDepth = 0;
401 }
402
403 /* drag along the previous one? */
404 if (rStateStackDepth != 0)
405 rmStateCopy(last, s);
406
407 private_collectAndApplyMatrices (s, r, NULL, GL_RENDER,
408 &stateChange, RM_FALSE);
409 stateChange |= private_updateSceneParms(r, s, RM_FALSE, 0, NULL, NULL);
410
411 if (stateChange == 1) /* add to stack */
412 {
413 RMserialState *t;
414
415 rStateStack = realloc((void *)rStateStack, (sizeof(RMserialState) * (rStateStackDepth + 1)));
416 t = rStateStack + rStateStackDepth;
417
418 t->s = s;
419 t->indx = rStateStackDepth;
420
421 rStateStackDepth++;
422 }
423
424 /* then recurse */
425 for (i = 0; i < r->nchildren; i++)
426 private_rmBuildSerialState(p, r->children[i], s, 0);
427
428
429 if (stateChange == 0)
430 rmStateDelete(s);
431
432 return(RM_CHILL);
433 }
434 /* EOF */
435