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: rmcmpmgr.c,v 1.11 2005/06/15 02:10:40 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.11 $
29  * $Log: rmcmpmgr.c,v $
30  * Revision 1.11  2005/06/15 02:10:40  wes
31  * Added initial support for application-settable defaults. Apps
32  * will use rmSetEnum/rmGetEnum to set or get defaults that are RMenums.
33  * The first round of variables that can be set/get by apps are
34  * RMnode traversal masks assigned to new scene graph nodes by rmNodeNew.
35  *
36  * Revision 1.10  2005/06/06 02:04:29  wes
37  * Lots of small additions to clean up compiler warnings.
38  *
39  * Revision 1.9  2005/03/19 17:18:45  wes
40  * For RM_MARKERS2D primitives, add call to delete prim-specific data.
41  *
42  * Revision 1.8  2005/02/27 19:34:04  wes
43  * Added support for application supplied texture object IDs and display lists.
44  *
45  * Revision 1.7  2005/02/19 16:34:21  wes
46  * Distro sync and consolidation.
47  * Minor code rearrangement, remove dead code.
48  *
49  * Revision 1.6  2005/01/23 17:08:25  wes
50  * Copyright updated to 2005.
51  * Updates to support access and use of extensions; multitexturing on all
52  * platforms, use of 3d texture extension to realize implementation of
53  * volume rendering and related functions on Windows platforms.
54  *
55  * Revision 1.5  2004/01/16 16:43:24  wes
56  * Updated copyright line for 2004.
57  *
58  * Revision 1.4  2003/04/05 13:58:29  wes
59  * Fixed two memory leaks: free CM mutexes upon exit, and free the fbClear struct.
60  *
61  * Revision 1.3  2003/02/02 17:50:57  wes
62  * Added bounding boxes to RMprimitives, as a supplement to node-level bboxes.
63  * The RMprimitive level bboxes are needed for the retained-mode CR work.
64  *
65  * Revision 1.2  2003/02/02 02:07:15  wes
66  * Updated copyright to 2003.
67  *
68  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
69  * Manual rebuild of rm150 repository.
70  *
71  * Revision 1.9  2003/01/16 22:21:17  wes
72  * Updated all source files to reflect new organization of header files:
73  * all header files formerly located in include/rmaux, include/rmi, include/rmv
74  * are now located in include/rm.
75  *
76  * Revision 1.8  2002/09/17 14:20:03  wes
77  * Added new routine rmComponentManagerPrintStatus(). Added code inside
78  * private_rmDeleteComponentManager() that will free all pages of memory
79  * in the object pool - this is needed in conjunction with the new
80  * paging model.
81  *
82  * Revision 1.7  2002/09/05 15:05:03  wes
83  * more thorough debug info on realloc
84  *
85  * Revision 1.6  2002/08/29 22:20:32  wes
86  *
87  * Massive upgrade to accommodate dynamic object reallocation within
88  * the component manager, and within the context cache. Use the
89  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
90  * whenever a realloc occurs. With this upgrade, there are no
91  * OpenRM limits on the size of the scene graph. There will be external
92  * limits, such as the amount of RAM and the amount of space available
93  * to your OpenGL implementation.
94  *
95  * Revision 1.5  2002/08/19 00:54:27  wes
96  * Added API entries for new experiemental routines to get and set
97  * the size of the OpenRM component manager object pool.
98  *
99  * Revision 1.4  2002/04/30 19:30:20  wes
100  * rmImageDelete will automatically call rmImageSetVismap(img, NULL) to
101  * induce release of any memory associated with a vis colormap in an
102  * RMimage.
103  *
104  * Revision 1.3  2001/07/15 17:17:11  wes
105  * Added code to manage "normalizeNormals" render property - fixes a
106  * 4-byte memory leak.
107  *
108  * Revision 1.2  2001/03/31 17:12:38  wes
109  * v1.4.0-alpha-2 checkin.
110  *
111  * Revision 1.1  2000/12/03 22:32:59  wes
112  * Initial entry.
113  *
114  */
115 
116 #include <rm/rm.h>
117 #include "rmprivat.h"
118 
119 static RMcompList *private_rmInitComponentMetaList(int objCount);
120 static RMenum      private_rmReallocComponentMgrListAndPool(RMcompMgrHdr *h);
121 static void        private_rmComponentManagerStatus(void);
122 
123 
124 /*
125  * ----------------------------------------------------
126  * @Name rmComponentManagerPrintStatus
127  @pstart
128  void rmComponentManagerPrintStatus( void )
129  @pend
130 
131  @astart
132  none.
133  @aend
134 
135  @dstart
136 
137  Use this routine to display the current free/alloc status of objects
138  managed by the component manager. This routine will invoke rmNotice() to
139  display the number of allocated and free objects managed by the
140  component manager. This routine is useful in tracking down memory leaks
141  in applications.
142 
143  This routine is new, and experimental, in version 1.4.3. It may be
144  subsumed by more general utilities in the future.
145 
146  @dend
147  * ----------------------------------------------------
148  */
149 void
rmComponentManagerPrintStatus(void)150 rmComponentManagerPrintStatus(void)
151 {
152     private_rmComponentManagerStatus();
153 }
154 
155 
156 /* PRIVATE */
157 RMcompMgrHdr *
private_rmInitComponentManager(int objCount,int objSize)158 private_rmInitComponentManager(int objCount,
159 			       int objSize)
160 {
161     RMcompMgrHdr *t;
162 
163     t = (RMcompMgrHdr *)malloc(sizeof(RMcompMgrHdr));
164 
165     if (t == NULL)
166 	return(NULL);
167 
168     t->numPages = 1;
169 
170     t->objectPool = (void **)malloc(sizeof(void *));
171     t->objectPool[0] = (void *)malloc(objCount * objSize);
172 
173     t->metaListHead = private_rmInitComponentMetaList(objCount);
174 
175     t->numAlloc = 0;
176 
177     t->startFree = 0;
178     t->startAlloc = -1;
179 
180     t->numFree = objCount;
181     t->currentPoolSize = objCount;
182     t->componentSize = objSize;
183 
184     /* create a mutex in unlocked state */
185 
186     t->guard = rmMutexNew(RM_MUTEX_UNLOCK);
187 
188     return(t);
189 }
190 
191 /* PRIVATE */
192 static RMcompList *
private_rmInitComponentMetaList(int objCount)193 private_rmInitComponentMetaList(int objCount)
194 {
195     RMcompList *t;
196     int i;
197 
198     t = (RMcompList *)malloc(sizeof(RMcompList)*objCount);
199     if (t == NULL)
200 	return(NULL);
201 
202     for (i=0;i<objCount;i++)
203     {
204 	t[i].objIndx = i;
205 	t[i].myIndx = i;
206 	if (i==0)
207 	    t[i].prevIndx = -1;
208 	else
209 	    t[i].prevIndx = i-1;
210 
211 	if (i == objCount-1)
212 	    t[i].nextIndx = -1;
213 	else
214 	    t[i].nextIndx = i+1;
215     }
216     return(t);
217 }
218 
219 /* PRIVATE */
220 static RMenum
private_rmReallocComponentMgrListAndPool(RMcompMgrHdr * h)221 private_rmReallocComponentMgrListAndPool(RMcompMgrHdr *h)
222 {
223     /*
224      * 8/29/02 - wes. implementation of dynamic object pools.
225      * this routine will realloc the MetaList in a component manager,
226      * and will add a page of new memory to the objectPool.
227      */
228     RMcompList *oldList, *t;
229     int i;
230     int newSize;
231     int newPoolSize, oldPoolSize;
232 
233     /* first,  compute new size of alloc list  */
234     newSize = h->currentPoolSize * sizeof(RMcompList);
235     newSize += (NUM_ITEMS_PER_PAGE) * sizeof(RMcompList);
236 
237     oldList = h->metaListHead;
238     t = (RMcompList *)realloc((void *)oldList, newSize);
239 
240     if (t == NULL)
241 	return(RM_WHACKED);
242 
243     /* update the pointer in the header */
244     h->metaListHead = t;
245 
246     /*
247      * realloc succeeded if we're here. initialize the new hunk of
248      * memory.
249      */
250     oldPoolSize = h->currentPoolSize;
251     newPoolSize = oldPoolSize + NUM_ITEMS_PER_PAGE;
252 
253     /*
254      * initialize the new stuff. we don't need to adjust the "pointers"
255      * in any of the old stuff because we are maintaining two virtual
256      * lists within one pile of stuff. because we're here, we're out of
257      * free objects.
258      */
259     for (i=oldPoolSize; i < newPoolSize; i++)
260     {
261 	t[i].objIndx = i;
262 	t[i].myIndx = i;
263 
264 	if (i == oldPoolSize)
265 	    t[i].prevIndx = -1;
266 	else
267 	    t[i].prevIndx = i-1;
268 
269 	if (i == newPoolSize-1)
270 	    t[i].nextIndx = -1;
271 	else
272 	    t[i].nextIndx = i+1;
273     }
274 
275 
276     /*
277      * now, update counters in the RMcompMgrHdr to reflect new values.
278      */
279     h->numFree += NUM_ITEMS_PER_PAGE;
280     h->startFree = oldPoolSize;
281     h->currentPoolSize += NUM_ITEMS_PER_PAGE;
282 
283     /*
284      * OK - now we're done futzing with the alloc/free lists. now we
285      * need to actually increase the size of the objectPool. This is
286      * accomplished by adding another "page" of memory. we can't just
287      * blindly realloc the objectPool because the application probably
288      * has object pointers into that hunk of memory, and a realloc
289      * might (probably) causes memory to be moved around, and then the
290      * app's pointers would be stale. we use a paging scheme as a
291      * compromise..application performance isn't affected at all; we
292      * incur only a small amount of additional overhead when the
293      * application invokes a new/delete operation.
294      */
295 
296     h->objectPool = (void **)realloc(h->objectPool, sizeof(void *)*(h->numPages + 1));
297     h->objectPool[h->numPages] = (void *)malloc(NUM_ITEMS_PER_PAGE * h->componentSize);
298     memset(h->objectPool[h->numPages], 0, NUM_ITEMS_PER_PAGE * h->componentSize);
299 
300     h->numPages += 1;
301 
302     return RM_CHILL;
303 }
304 
305 /* PRIVATE */
306 static int
private_rmFreeToAlloc(RMcompMgrHdr * h,const char * msg)307 private_rmFreeToAlloc(RMcompMgrHdr *h, /* input - component mgr hdr */
308 		      const char *msg) /* message to bark upon error */
309 {
310     /*
311      * move an item from the head of the free list to the start
312      * of the alloc list. this routine will take care of all
313      * bookkeeping: updating counter of free and alloc pools,
314      * updating pointers in lists, etc.
315      *
316      * upon successful completion, the index of the moved
317      * entry is returned. upon failure, a -1 is returned. failure
318      * occurs when the list of free objects has been depleted.
319      */
320     int freeIndx;
321     RMcompList *firstFree;
322 
323     /*
324      * first, make sure we have exclusive use of this pool.
325      */
326     if (rmMutexLock(h->guard) == RM_WHACKED)
327     {
328 	/*
329 	 * if we arrive here, something is really, really wrong.
330 	 * the rmMutexLock() call is supposed to do a blocking wait
331 	 * and then grab the mutex once it's available. If we arrive
332 	 * here, then there's some type of fatal error deep in
333 	 * pthreads. To date, this branch of code has never been
334 	 * executed in millions of program runs (as far as I know).
335 	 */
336 	rmError(" problem locking mutex in component manager. \n");
337 	exit(-1);
338     }
339 
340     if (h->numAlloc+1 > h->currentPoolSize)
341     {
342 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
343 	printf("component manager execing realloc: %s. oldsize = %d ", msg,h->currentPoolSize);
344 #endif
345 	/* execute realloc on metalist */
346 	if (private_rmReallocComponentMgrListAndPool(h) != RM_CHILL)
347 	{
348 	    rmError(msg);
349 	    rmMutexUnlock(h->guard); /* wes 1/21/02 */
350 	    return(-1);
351 	}
352 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
353 	printf("newsize = %d \n", h->currentPoolSize);
354 	fflush(stdout);
355 #endif
356     }
357 
358     /* take top of free list */
359     /* don't need to update prevIndex in free list */
360     freeIndx = h->startFree;
361     firstFree = h->metaListHead + freeIndx;
362 
363     /* update the start of the free list.. */
364     h->startFree = firstFree->nextIndx;
365 
366     /* and the count of free items. */
367     h->numFree -= 1;
368 
369     /* update the alloc list. when we update the alloc list, we put
370      the newly alloc'ed item at the head of the list. it's next pointer
371      will be the old head of list, and it's prev pointer will be -1. */
372     {
373 	RMcompList *oldFirstAlloc, *newAlloc;
374 
375 	newAlloc = firstFree;
376 
377 	/* add the newly alloced one to the front of the free list */
378 	newAlloc->nextIndx = h->startAlloc;
379 	h->startAlloc = newAlloc->myIndx;
380 
381 	/* so there's no prev index */
382 	newAlloc->prevIndx = -1;
383 
384 	if (newAlloc->nextIndx != -1)
385         {
386 	    /* something was on the list, update it's prev pointer
387 	     to point to the newly added thing.*/
388 
389 	    oldFirstAlloc = h->metaListHead + newAlloc->nextIndx;
390 	    oldFirstAlloc->prevIndx = newAlloc->myIndx;
391 	}
392 	h->numAlloc += 1;
393     }
394 
395     rmMutexUnlock(h->guard);
396 
397     return (freeIndx);
398 }
399 
400 /* PRIVATE */
401 void
private_rmAllocToFree(RMcompMgrHdr * h,unsigned int indx)402 private_rmAllocToFree(RMcompMgrHdr *h, /* main component mgr to use */
403 		      unsigned int indx) /* index of item to move from alloc to free */
404 {
405     RMcompList *toFree;
406 
407     toFree = h->metaListHead;
408     toFree += indx;
409 
410     /* first, fix up the alloc list. */
411 
412     /* fix up "next" pointer of previous alloc list item */
413     if (toFree->prevIndx == -1) /* it's at the start of the list */
414     {
415 	h->startAlloc = toFree->nextIndx;
416     }
417     else
418     {
419 	RMcompList *prev;
420 	prev = h->metaListHead + toFree->prevIndx;
421 	prev->nextIndx = toFree->nextIndx;
422     }
423 
424     /* fix up "prev" pointer of next alloc item list */
425     if (toFree->nextIndx != -1)
426     {
427 	RMcompList *next;
428 	next = h->metaListHead + toFree->nextIndx;
429 	next->prevIndx = toFree->prevIndx;
430     }
431 
432     /* now, insert the toFree entry back into the free list - always
433      put it at the top of the free list (no prev pointers) */
434 
435     toFree->nextIndx = h->startFree;
436     h->startFree = toFree->myIndx;
437 
438     h->numAlloc -= 1;
439     h->numFree += 1;
440 
441 }
442 
443 /* PRIVATE */
444 RMimage *
private_rmImageNew(void)445 private_rmImageNew(void)
446 {
447     /*
448      *
449      */
450     extern RMcompMgrHdr *global_RMimagePool;
451     int freeIndx;
452     int pageNum, offset;
453     RMimage *t;
454 
455     if (RM_ASSERT(global_RMimagePool, "Please call rmInit() prior to creating RMimage objects. \n") == RM_WHACKED)
456 	return(NULL);
457 
458     freeIndx = private_rmFreeToAlloc(global_RMimagePool,"private_rmImageNew() - all RMimage objects have been used.");
459 
460     if (freeIndx == -1)
461 	return(NULL);
462 
463     pageNum = rmCompManagerGetPage(freeIndx);
464     offset = rmCompManagerGetOffset(freeIndx);
465 
466     /* return RMimage handle to caller */
467     t = (RMimage *)(global_RMimagePool->objectPool[pageNum]);
468     t += offset;
469     t->compListIndx = freeIndx;
470 
471 #if 0
472     /* pre-paging code */
473     t = (RMimage *)(global_RMimagePool->objectPool);
474     t += freeIndx;
475     t->compListIndx = freeIndx;
476 #endif
477 
478     return (t);
479 }
480 
481 /* PRIVATE */
482 RMenum
private_rmImageDelete(RMimage * r)483 private_rmImageDelete(RMimage *r)
484 {
485     extern RMcompMgrHdr *global_RMimagePool;
486     int indx;
487 
488     /* first, free up any pixel data associated with the RMimage object */
489 
490     if (private_rmImageGetCopyFlag(r) == RM_COPY_DATA)
491 	free((void *)(r->pixeldata));
492     else
493     {
494 	void (*appfunc)(void *);
495 
496 	appfunc = r->appfreefunc;
497 	if (appfunc != NULL)
498 	    (*appfunc)((void *)(r->pixeldata));
499     }
500 
501     /* assign a NULL vismap object to the RMimage - this will free any
502        pre-existing RMvisMap object that may be associated with the RMimage */
503     rmImageSetVismap(r, NULL);
504 
505     /* update the free list - the newly freed item goes to the
506        start of the free list */
507     indx = r->compListIndx;
508     /* validity checks on indx? */
509 
510     private_rmAllocToFree(global_RMimagePool, indx);
511 
512     return(RM_CHILL);
513 }
514 
515 
516 /* PRIVATE */
517 void
private_rmDeleteComponentManager(RMcompMgrHdr * t)518 private_rmDeleteComponentManager(RMcompMgrHdr *t)
519 {
520     int i;
521 
522     if (RM_ASSERT(t,"private_rmDeleteComponentManager error: the input RMcompMgrHdr is NULL! \n") == RM_WHACKED)
523 	return;
524 
525     for (i=0;i<t->numPages;i++)
526     {
527 	if ((t->objectPool[i]) == NULL)
528 	    rmWarning("private_rmDeleteComponentManager() warning: a page in the objectPool is unexpectedly not NULL!");
529 	else
530         {
531 	    free((void *)(t->objectPool[i]));
532 	    t->objectPool[i] = NULL;
533 	}
534     }
535 
536     rmMutexDelete(t->guard);
537 
538     free((void *)(t->objectPool));
539     free((void *)(t->metaListHead));
540     free((void *)t);
541 }
542 
543 /* PRIVATE */
544 RMnode *
private_rmNodeNew(void)545 private_rmNodeNew(void)
546 {
547     /*
548      *
549      */
550     extern RMcompMgrHdr *global_RMnodePool;
551     int freeIndx;
552     RMnode *t = NULL;
553 
554     if (RM_ASSERT(global_RMnodePool, "Please call rmInit() prior to creating RMnode objects. \n") == RM_WHACKED)
555 	return(NULL);
556 
557     freeIndx = private_rmFreeToAlloc(global_RMnodePool,"private_rmNodeNew() - all RMnode objects have been used.");
558 
559     if (freeIndx == -1)
560 	return(NULL);
561 
562     /* return RMnode handle to caller */
563 
564     {
565 	int pageNum = rmCompManagerGetPage(freeIndx);
566 	int offset = rmCompManagerGetOffset(freeIndx);
567 
568 	t = (RMnode *)(global_RMnodePool->objectPool[pageNum]);
569 	t += offset;
570 	t->compListIndx = freeIndx;
571     }
572 
573     return (t);
574 }
575 
576 /* PRIVATE */
577 RMenum
private_rmNodeDelete(RMnode * r)578 private_rmNodeDelete(RMnode *r)
579 {
580     extern RMcompMgrHdr *global_RMnodePool;
581     int indx;
582 
583     /* first, free up any data associated with the RMnode object */
584 
585     /* need: check to see if refcount is zero */
586     if (private_rmNodeGetRefcount(r) != 0)
587 	return(RM_WHACKED);
588 
589     if ((r->clientData) && (r->clientDataFreeFunc))
590     {
591 	void (*cfunc)();
592 
593 	cfunc = r->clientDataFreeFunc;
594 	(*cfunc)(r, rmNodeGetClientData(r));
595     }
596 
597     if (r->scene_parms != NULL) /* free up scene parms */
598     {
599 	int i;
600 
601 	if (r->scene_parms->viewport)
602 	    free((void *)(r->scene_parms->viewport));
603 
604 	if (r->scene_parms->camera3d)
605 	    rmCamera3DDelete(r->scene_parms->camera3d);
606 
607 	if (r->scene_parms->camera2d)
608 	    rmCamera2DDelete(r->scene_parms->camera2d);
609 
610 	if (r->scene_parms->haveAnyTextures == RM_TRUE)
611 	{
612 	    int i;
613 	    for (i=0; i <= RM_MAX_MULTITEXTURES; i++)
614 		if (r->scene_parms->textures[i] != NULL)
615 		    rmTextureDelete(r->scene_parms->textures[i],RM_TRUE);
616 	}
617 
618 	if (r->scene_parms->cp0 != NULL)
619 	    rmClipPlaneDelete(r->scene_parms->cp0);
620 
621 	if (r->scene_parms->cp1 != NULL)
622 	    rmClipPlaneDelete(r->scene_parms->cp1);
623 
624 	if (r->scene_parms->cp2 != NULL)
625 	    rmClipPlaneDelete(r->scene_parms->cp2);
626 
627 	if (r->scene_parms->cp3 != NULL)
628 	    rmClipPlaneDelete(r->scene_parms->cp3);
629 
630 	if (r->scene_parms->cp4 != NULL)
631 	    rmClipPlaneDelete(r->scene_parms->cp4);
632 
633 	if (r->scene_parms->cp5 != NULL)
634 	    rmClipPlaneDelete(r->scene_parms->cp5);
635 
636 	if (r->scene_parms->lmodel)
637 	    rmLightModelDelete(r->scene_parms->lmodel);
638 
639 	for (i = 0; i < RM_MAX_LIGHTS; i++)
640 	    if (r->scene_parms->lightSources[i] != NULL)
641 		rmLightDelete(r->scene_parms->lightSources[i]);
642 
643 	if (r->scene_parms->textProps != NULL)
644 	    rmTextPropsDelete(r->scene_parms->textProps);
645 
646 	free((void *)(r->scene_parms));
647     }
648     if (r->sprops != NULL) /* free up scene props */
649     {
650 	if (r->sprops->ambient_color != NULL)
651 	    free((void *)(r->sprops->ambient_color));
652 
653 	if (r->sprops->diffuse_color != NULL)
654 	    free((void *)(r->sprops->diffuse_color));
655 
656 	if (r->sprops->specular_color != NULL)
657 	    free((void *)(r->sprops->specular_color));
658 
659 	if (r->sprops->unlit_color != NULL)
660 	    free((void *)(r->sprops->unlit_color));
661 
662 	if (r->sprops->specular_exponent != NULL)
663 	    free((void *)(r->sprops->specular_exponent));
664 
665 	if (r->sprops->opacity != NULL)
666 	    free((void *)(r->sprops->opacity));
667 
668 	free((void *)(r->sprops));
669     }
670     if (r->rprops != NULL)	/* free up rendermode props */
671     {
672 	if (r->rprops->shademodel != NULL)
673 	    free((void *)(r->rprops->shademodel));
674 
675 	if (r->rprops->poly_mode_face)
676 	    free((void *)(r->rprops->poly_mode_face));
677 
678 	if (r->rprops->poly_mode_drawstyle)
679 	    free((void *)(r->rprops->poly_mode_drawstyle));
680 
681 	if (r->rprops->cull_mode)
682 	    free((void *)(r->rprops->cull_mode));
683 
684 	if (r->rprops->front_face)
685 	    free((void *)(r->rprops->front_face));
686 
687 	if (r->rprops->pointsize)
688 	    free((void *)(r->rprops->pointsize));
689 
690 	if (r->rprops->linewidth)
691 	    free((void *)(r->rprops->linewidth));
692 
693 	if (r->rprops->linestyle)
694 	    free((void *)(r->rprops->linestyle));
695 
696 	if (r->rprops->normalizeNormals)
697 	    free((void *)(r->rprops->normalizeNormals));
698 
699 	free((void *)(r->rprops));
700     }
701 
702     if (r->fbClear != NULL)
703     {
704 	if (r->fbClear->bgColor)
705 	    free((void *)(r->fbClear->bgColor));
706 
707 	if (r->fbClear->bgImageTile)
708 	    rmImageDelete(r->fbClear->bgImageTile);
709 
710 	if (r->fbClear->depthValue != NULL)
711 	    free((void *)(r->fbClear->depthValue));
712 
713 	if (r->fbClear->depthImage != NULL)
714 	    rmImageDelete(r->fbClear->depthImage);
715 
716 	free((void *)(r->fbClear));
717     }
718 
719     if (r->transforms != NULL)
720     {
721 	void private_rmNodeTransformsDelete(internals_RMtransformationStruct *t);
722 
723 	private_rmNodeTransformsDelete(r->transforms);
724     }
725     {
726 	int nprims, i;
727 
728 	/* now delete all the prims */
729 	nprims = rmNodeGetNumPrims(r);
730 	for (i=0; i < nprims; i++)
731 	    rmPrimitiveDelete((RMprimitive *)rmNodeGetPrimitive(r, i));
732 	free((void *)r->prims);
733     }
734     if (r->children)
735 	free((void *)r->children);
736 
737     /* update the free list - the newly freed item goes to the
738        start of the free list */
739     indx = r->compListIndx;
740     /* validity checks on indx? */
741 
742     private_rmAllocToFree(global_RMnodePool, indx);
743 
744     return(RM_CHILL);
745 }
746 
747 /* PRIVATE */
748 RMprimitive *
private_rmPrimitiveNew(void)749 private_rmPrimitiveNew(void)
750 {
751     /*
752      *
753      */
754     extern RMcompMgrHdr *global_RMprimitivePool;
755     int freeIndx;
756     RMprimitive *t;
757 
758     if (RM_ASSERT(global_RMprimitivePool, "Please call rmInit() prior to creating RMprimitive objects. \n") == RM_WHACKED)
759 	return(NULL);
760 
761     freeIndx = private_rmFreeToAlloc(global_RMprimitivePool,"private_rmPrimitiveNew() - all RMprimitive objects have been used.");
762 
763     if (freeIndx == -1)
764 	return(NULL);
765 
766     /* return RMprimitive handle to caller */
767     {
768 	int pageNum = rmCompManagerGetPage(freeIndx);
769 	int offset = rmCompManagerGetOffset(freeIndx);
770 
771 	t = (RMprimitive *)(global_RMprimitivePool->objectPool[pageNum]);
772 	t += offset;
773 	t->compListIndx = freeIndx;
774     }
775 
776     t->cacheKey = t->utilCacheKey = RM_CACHEKEY_UNINITIALIZED_VALUE;
777 
778     return (t);
779 }
780 
781 /* PRIVATE */
782 RMenum
private_rmPrimitiveDelete(RMprimitive * r)783 private_rmPrimitiveDelete(RMprimitive *r)
784 {
785     extern RMcompMgrHdr *global_RMprimitivePool;
786     int indx;
787 
788     /* first, free up any data associated with the RMprimitive object */
789 
790     if ((r->clientData) && (r->clientDataFreeFunc))
791     {
792 	void (*cfunc)();
793 
794 	cfunc = r->clientDataFreeFunc;
795 	(*cfunc)(r, rmPrimitiveGetClientData(r));
796     }
797 
798     /* delete the bbox, if present */
799     if (r->bmin)
800 	free((void *)(r->bmin));
801 
802     if (r->bmax)
803 	free((void *)(r->bmax));
804 
805     /* free all blobs */
806     {
807 	int                  i;
808 	void               (*freefunc)();
809 	RMprimitiveDataBlob *b;
810 
811 	for (i = 0; i < RM_MAXBLOBS_PER_PRIMITIVE; i++)
812         {
813 	    b = &(r->blobs[i]);
814 
815 	    if (b->appfreefunc != NULL)
816 	    {
817 		freefunc = b->appfreefunc;
818 		(*freefunc)(b->ptr);
819 	    }
820 	    else
821 		if (b->ptr != NULL)
822 		    free(b->ptr);
823 	}
824     }
825 
826     /* now free the weird stuff that's wedged into the cracks.. */
827     if ((r->type == RM_BITMAP) || (r->type == RM_INDEXED_BITMAP))
828     {
829         int        i;
830 	RMbitmap **bmp_list, *bmp;
831 
832 	bmp_list = (RMbitmap **)(r->p1);
833 
834 	/* flags1 is unsigned */
835 	for (i = 0; i < (int)(r->flags1); i++)
836 	{
837 	    bmp = bmp_list[i];
838 	    rmBitmapDelete(bmp);
839 	}
840 	free((void *)bmp_list);
841     }
842     else if ((r->type == RM_TEXT) || (r->type == RM_INDEXED_TEXT))
843     {
844 	int          nstrings, i;
845 	RMtextPrim *tp;
846 
847 	tp = (RMtextPrim *)(r->p1);
848 	nstrings = r->flags1;
849 
850 	for (i = 0; i < nstrings; i++)
851 	    free((void *)(tp[i].string));
852 
853 	free((void *)(r->p1));
854     }
855     else if (r->type == RM_SPRITE)
856     {
857 	if (r->p1)
858 	{
859 	    int      i, n;
860 	    RMimage *img, **sprite_list;
861 
862 	    private_rmPrimitiveGetItem(r, RM_PRIMITIVE_SPRITES, &n, (void **)&sprite_list);
863 
864 	    for (i = 0; i < n; i++)
865 	    {
866 		img = sprite_list[i];
867 		rmImageDelete(img);
868 	    }
869 
870 	    free((void *)(r->p1));
871 	    r->flags1 = 0;
872 	}
873     }
874     else if (r->type == RM_OCTMESH)
875     {
876 	/* free octmesh-specific stuff */
877 	private_rmOctmeshPrimitiveFree(r);
878     }
879     else if (r->type == RM_MARKERS2D) /* thanks Alex, 3/2005 */
880     {
881 	if (r->p1)
882 	    rmInternalMarker2DDelete(r->p1);
883     }
884 
885     /* delete blobs */
886     free((void *)r->blobs);
887 
888     /* update the free list - the newly freed item goes to the
889        start of the free list */
890     indx = r->compListIndx;
891     /* validity checks on indx? */
892 
893     private_rmAllocToFree(global_RMprimitivePool, indx);
894 
895     return(RM_CHILL);
896 }
897 
898 /* PRIVATE */
899 RMtexture *
private_rmTextureNew(void)900 private_rmTextureNew(void)
901 {
902     /*
903      *
904      */
905     extern RMcompMgrHdr *global_RMtexturePool;
906     int freeIndx;
907     RMtexture *t;
908 
909     if (RM_ASSERT(global_RMtexturePool, "Please call rmInit() prior to creating RMtexture objects. \n") == RM_WHACKED)
910 	return(NULL);
911 
912     freeIndx = private_rmFreeToAlloc(global_RMtexturePool,"private_rmTextureNew() - all RMtexture objects have been used.");
913 
914     if (freeIndx == -1)
915 	return(NULL);
916 
917     /* return RMtexture handle to caller */
918     {
919 	int pageNum = rmCompManagerGetPage(freeIndx);
920 	int offset = rmCompManagerGetOffset(freeIndx);
921 
922 	t = (RMtexture *)(global_RMtexturePool->objectPool[pageNum]);
923 	t += offset;
924 	t->compListIndx = freeIndx;
925     }
926 
927     return (t);
928 }
929 
930 /* PRIVATE */
931 RMenum
private_rmTextureDelete(RMtexture * r)932 private_rmTextureDelete(RMtexture *r)
933 {
934     extern RMcompMgrHdr *global_RMtexturePool;
935     int indx;
936 
937     /* update the free list - the newly freed item goes to the
938        start of the free list */
939     indx = r->compListIndx;
940     /* validity checks on indx? */
941 
942     private_rmAllocToFree(global_RMtexturePool, indx);
943 
944     return(RM_CHILL);
945 }
946 
947 /* PRIVATE */
948 void
private_rmPrimitiveSetCacheKey(RMprimitive * p)949 private_rmPrimitiveSetCacheKey(RMprimitive *p)
950 {
951     /* we could put a mutex here to force serial access. 10/2000 */
952     p->cacheKey = private_rmGetNewCacheKey();
953 }
954 
955 /* PRIVATE */
956 void
private_rmTextureSetIDCacheKey(RMtexture * t)957 private_rmTextureSetIDCacheKey(RMtexture *t)
958 {
959     /* we could put a mutex here to force serial access. 10/2000 */
960     t->cacheKeyID = private_rmGetNewCacheKey();
961 }
962 
963 /* PRIVATE */
964 void
private_rmTextureSetDataCacheKey(RMtexture * t)965 private_rmTextureSetDataCacheKey(RMtexture *t)
966 {
967     /* we could put a mutex here to force serial access. 10/2000 */
968     t->cacheKeyData = private_rmGetNewCacheKey();
969 }
970 
971 /* PRIVATE */
972 RMtextProps *
private_rmTextPropsNew(void)973 private_rmTextPropsNew(void)
974 {
975     /*
976      *
977      */
978     extern RMcompMgrHdr *global_RMtextPropsPool;
979     int freeIndx;
980     RMtextProps *t;
981 
982     if (RM_ASSERT(global_RMtextPropsPool, "Please call rmInit() prior to creating RMtextProps objects. \n") == RM_WHACKED)
983 	return(NULL);
984 
985     freeIndx = private_rmFreeToAlloc(global_RMtextPropsPool,"private_rmTextPropsNew() - all RMtextProps objects have been used.");
986 
987     if (freeIndx == -1)
988 	return(NULL);
989 
990     /* return RMtextProps handle to caller */
991 
992     {
993 	int pageNum = rmCompManagerGetPage(freeIndx);
994 	int offset = rmCompManagerGetOffset(freeIndx);
995 
996 	t = (RMtextProps *)(global_RMtextPropsPool->objectPool[pageNum]);
997 	t += offset;
998 	t->compListIndx = freeIndx;
999     }
1000 #if 0
1001     t = (RMtextProps *)(global_RMtextPropsPool->objectPool);
1002     t += freeIndx;
1003     t->compListIndx = freeIndx;
1004 #endif
1005     return (t);
1006 }
1007 
1008 /* PRIVATE */
1009 RMenum
private_rmTextPropsDelete(RMtextProps * r)1010 private_rmTextPropsDelete(RMtextProps *r)
1011 {
1012     extern RMcompMgrHdr *global_RMtextPropsPool;
1013     int indx;
1014 
1015     /* update the free list - the newly freed item goes to the
1016        start of the free list */
1017     indx = r->compListIndx;
1018     /* validity checks on indx? */
1019 
1020     private_rmAllocToFree(global_RMtextPropsPool, indx);
1021 
1022     return(RM_CHILL);
1023 }
1024 
1025 /* PRIVATE */
1026 void
private_rmComponentManagerStatus(void)1027 private_rmComponentManagerStatus(void)
1028 {
1029     extern RMcompMgrHdr *global_RMimagePool;
1030     extern RMcompMgrHdr *global_RMprimitivePool;
1031     extern RMcompMgrHdr *global_RMnodePool;
1032     extern RMcompMgrHdr *global_RMtexturePool;
1033     extern RMcompMgrHdr *global_RMtextPropsPool;
1034     RMcompMgrHdr *t;
1035 
1036     char buf[2048], buf2[256];
1037 
1038     sprintf(buf,"\tComponent Manager Status \n");
1039     strcat(buf,"\t\tAlloc \tFree \tPoolSize \n");
1040 
1041     t = global_RMimagePool;
1042     sprintf(buf2,"RMimages\t%d \t%d \t%d \n",t->numAlloc, t->numFree, t->currentPoolSize);
1043     strcat(buf, buf2);
1044 
1045     t = global_RMprimitivePool;
1046     sprintf(buf2,"RMprimitives\t%d \t%d \t%d \n",t->numAlloc, t->numFree, t->currentPoolSize);
1047     strcat(buf, buf2);
1048 
1049     t = global_RMnodePool;
1050     sprintf(buf2,"RMnodes  \t%d \t%d \t%d \n",t->numAlloc, t->numFree, t->currentPoolSize);
1051     strcat(buf, buf2);
1052 
1053     t = global_RMtexturePool;
1054     sprintf(buf2,"RMtextures\t%d \t%d \t%d \n",t->numAlloc, t->numFree, t->currentPoolSize);
1055     strcat(buf, buf2);
1056 
1057     t = global_RMtextPropsPool;
1058     sprintf(buf2,"RMtextProps\t%d \t%d \t%d \n",t->numAlloc, t->numFree, t->currentPoolSize);
1059     strcat(buf, buf2);
1060 
1061     rmNotice(buf);
1062 }
1063 /* EOF */
1064