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