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: rmutil.c,v 1.11 2005/06/06 02:04:29 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.11 $
29  * $Log: rmutil.c,v $
30  * Revision 1.11  2005/06/06 02:04:29  wes
31  * Lots of small additions to clean up compiler warnings.
32  *
33  * Revision 1.10  2005/02/27 19:34:04  wes
34  * Added support for application supplied texture object IDs and display lists.
35  *
36  * Revision 1.9  2005/02/19 16:40:20  wes
37  * Distro sync and consolidation.
38  * Repairs to fix memory leak associated with repeated calls to rmPipeNew,
39  * rmPipeMakeCurrent, rmPipeClose.
40  *
41  * Revision 1.8  2005/01/23 17:00:22  wes
42  * Copyright updated to 2005.
43  *
44  * Revision 1.7  2004/01/16 16:49:13  wes
45  * Updated copyright line for 2004.
46  *
47  * Revision 1.6  2003/11/05 15:33:10  wes
48  * Removed rmStartTimer and rmElapsedTime calls; these have been replaced
49  * with a new family of rmTime() routines introduced in 1.5.1.
50  *
51  * Revision 1.5  2003/04/12 19:48:53  wes
52  * Bug fix in RM_SOFTWARE 3D image resize operations.
53  *
54  * Revision 1.4  2003/04/08 02:45:33  wes
55  * Implemented RM_SOFTWARE 3D image resizing (finally).
56  *
57  * Revision 1.3  2003/02/14 00:19:57  wes
58  * Memset the context cache to zero upon initialization. Avoids a bug caused
59  * by having garbage in uninitialized memory.
60  *
61  * Revision 1.2  2003/02/02 02:07:16  wes
62  * Updated copyright to 2003.
63  *
64  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
65  * Manual rebuild of rm150 repository.
66  *
67  * Revision 1.11  2003/01/16 22:21:17  wes
68  * Updated all source files to reflect new organization of header files:
69  * all header files formerly located in include/rmaux, include/rmi, include/rmv
70  * are now located in include/rm.
71  *
72  * Revision 1.10  2002/09/05 15:07:39  wes
73  * Changed "is a texture" test slightly.
74  *
75  * Revision 1.9  2002/08/29 22:20:32  wes
76  *
77  * Massive upgrade to accommodate dynamic object reallocation within
78  * the component manager, and within the context cache. Use the
79  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
80  * whenever a realloc occurs. With this upgrade, there are no
81  * OpenRM limits on the size of the scene graph. There will be external
82  * limits, such as the amount of RAM and the amount of space available
83  * to your OpenGL implementation.
84  *
85  * Revision 1.8  2002/08/17 15:14:36  wes
86  * Changed reference of RM_COMPONENT_POOL_SIZE from a #define to a
87  * global variable.
88  *
89  * Revision 1.7  2002/04/30 19:36:22  wes
90  * Updated copyright dates.
91  *
92  * Revision 1.6  2001/10/15 03:08:40  wes
93  * fix a compile warning.
94  *
95  * Revision 1.5  2001/07/15 17:20:23  wes
96  * Added private routines that manage retained mode resources by
97  * cleaning the context cache. These routines are draconian in approach,
98  * and should be made more selective in future releases.
99  *
100  * Revision 1.4  2001/03/31 17:12:39  wes
101  * v1.4.0-alpha-2 checkin.
102  *
103  * Revision 1.3  2000/12/03 22:35:38  wes
104  * Mods for thread safety.
105  *
106  * Revision 1.2  2000/04/20 16:29:47  wes
107  * Documentation additions/enhancements, some code rearragement.
108  *
109  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
110  * OpenRM 1.2 Checkin
111  *
112  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
113  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
114  *
115  */
116 
117 #include <rm/rm.h>
118 #include "rmprivat.h"
119 
120 #ifdef RM_X
121 #include <sys/types.h>
122 #include <sys/time.h>
123 #endif
124 
125 
126 /*
127  * static mutex to protect cache key from simultaneous access by
128  * multiple app threads. only one such mutex is needed, so keeping
129  * it around as a static variable is ok as far as thread-safety goes.
130  */
131 static RMmutex *cacheKeyMutex=NULL;
132 
133 /*
134  * ----------------------------------------------------
135  * @Name rmNearestPowerOfTwo
136  @pstart
137  int rmNearestPowerOfTwo (int n)
138  @pend
139 
140  @astart
141  int n - an integer value.
142  @aend
143 
144  @dstart
145 
146  This routine computes the integer that is the closest power of two to
147  the input integer "n". The algorithm works only for non-negative
148  input.
149 
150  This routine will come in handy if you have to scale an image so it's
151  size is an even power of two.
152 
153  @dend
154  * ----------------------------------------------------
155  */
156 int
rmNearestPowerOfTwo(int n)157 rmNearestPowerOfTwo (int n)
158 {
159     int nbits, j;
160 
161     j = n;
162     for (nbits = 0; j > 0;)
163     {
164 	j = j >> 1;
165 	nbits++;
166     }
167 
168     if (nbits != 0)
169 	nbits--;
170 
171     if ((1<<nbits) == n)
172 	return(n);
173     else
174     {
175 	int a, b, c;
176 
177 	a = (1 << (nbits + 1));	/* 2^j which is greater than n */
178 	b = a - n;
179 	c = a - (a >> 1);
180 	c = c>>1;
181 	if (b > c)
182 	    return(1 << nbits);
183 	else
184 	    return(1 << (nbits + 1));
185     }
186 }
187 
188 
189 /*
190  * ----------------------------------------------------
191  * @Name rmIntMagnitude
192  @pstart
193  int rmIntMagnitude (int m)
194  @pend
195 
196  @astart
197  int m - an integer value.
198  @aend
199 
200  @dstart
201 
202  This routine computes log2(m) for some integer m, and returns an
203  integer. It is not an exact log2() replacement. It is useful for
204  determining the position of the uppermost "on" bit in an integer.
205 
206  @dend
207  * ----------------------------------------------------
208  */
209 int
rmIntMagnitude(int m)210 rmIntMagnitude (int m)
211 {
212     int i = 0;
213 
214     while (m > 0)
215     {
216 	m = m >> 1;
217 	i++;
218     }
219     if (i == 0)
220 	return(0);
221     else
222 	return(i - 1);
223 }
224 
225 
226 /*
227  * ----------------------------------------------------
228  * @Name rmHSVtoRGB
229  @pstart
230  void rmHSVtoRGB (float hue,
231 	          float saturation,
232 		  float value,
233 		  float *redReturn,
234 		  float *greenReturn,
235 		  float *blueReturn)
236  @pend
237 
238  @astart
239 
240  float hue, saturation, value - floating point values in the range
241     [0..1] (input).
242 
243  float *redReturn, *greenReturn, *blueReturn - handles to floats. will
244     contain floats in the range [0..1] (return).
245  @aend
246 
247  @dstart
248 
249  Convert a three-component pixel from HSV space to RGB space. Input
250  hue is in the range 0..1, with 0 corresponding to 0 degrees on the
251  HSV circle, and 1.0 corresponding to 360 degrees on the HSV
252  circle. Saturation is in the range 0..1, where 0 is fully desaturated
253  and 1 is fully saturated.  Value, or brightness, is in the range
254  0..1. A brightness value of 0 is black (not very bright), and a value
255  of 1.0 is full brightness.
256 
257  The results of the conversion are placed into caller-supplied memory.
258  The return RGB values are also in the range 0..1, with 0 representing
259  "full off" and 1 representing "full on."
260 
261  @dend
262  * ----------------------------------------------------
263  */
264 void
rmHSVtoRGB(float h,float s,float v,float * r,float * g,float * b)265 rmHSVtoRGB (float h,
266 	    float s,
267 	    float v,
268 	    float *r,
269 	    float *g,
270 	    float *b)
271 {
272     int   i;
273     float f, p, q, t;
274     float tr = 0.0, tg = 0.0, tb = 0.0; /* inits satisfies gcc warning */
275     float ht;
276 
277     /* (h,s,v) in [0..1] --> (r,g,b) will be in [0..1] - Foley & VanDam */
278     ht = h;
279 
280     if (v == 0.0)
281     {
282 	tr=0.0;
283 	tg=0.0;
284 	tb=0.0;
285     }
286     else
287     {
288 	if (s == 0.0)
289 	{
290 	    tr = v;
291 	    tg = v;
292 	    tb = v;
293 	}
294 	else
295 	{
296 	    ht = ht * 6.0;
297 	    if (ht >= 6.0)
298 		ht = 0.0;
299 
300 	    i = ht;
301 	    f = ht - i;
302 	    p = v * (1.0 - s);
303 	    q = v * (1.0 - s*f);
304 	    t = v * (1.0 - (s * (1.0 - f)));
305 
306  	    if (i == 0)
307 	    {
308 		tr = v;
309 		tg = t;
310 		tb = p;
311 	    }
312 	    else if (i == 1)
313 	    {
314 		tr = q;
315 		tg = v;
316 		tb = p;
317 	    }
318 	    else if (i == 2)
319 	    {
320 		tr = p;
321 		tg = v;
322 		tb = t;
323 	    }
324 	    else if (i == 3)
325 	    {
326 		tr = p;
327 		tg = q;
328 		tb = v;
329 	    }
330 	    else if (i == 4)
331 	    {
332 		tr = t;
333 		tg = p;
334 		tb = v;
335 	    }
336 	    else if (i == 5)
337 	    {
338 		tr = v;
339 		tg = p;
340 		tb = q;
341 	    }
342 	}
343     }
344     *r = tr;
345     *g = tg;
346     *b = tb;
347 }
348 
349 
350 /*
351  * ----------------------------------------------------
352  * @Name rmRGBtoHSV
353  @pstart
354  void rmRGBtoHSV (float red,
355 	          float green,
356 		  float blue,
357 		  float *hueReturn,
358 		  float *saturationReturn,
359 		  float *valueReturn)
360  @pend
361 
362  @astart
363  float red, green, blue - floating point values in the range 0..1 that
364     represent a 3-component RGB pixel.
365 
366  float *hueReturn, *saturationReturn, *valueReturn - handles to floats
367     that will contain the HSV representation of the input RGB pixel
368     upon return. The return values are in the range 0..1 (result).
369  @aend
370 
371  @dstart
372 
373  Converts an RGB 3-tuple into HSV space.
374 
375  Output hue is in the range 0..1, with 0 corresponding to 0 degrees on
376  the HSV circle, and 1.0 corresponding to 360 degrees on the HSV
377  circle. Saturation is in the range 0..1, where 0 is fully desaturated
378  and 1 is fully saturated.  Value, or brightness, is in the range
379  0..1. A brightness value of 0 is black (not very bright), and a value
380  of 1.0 is full brightness.
381 
382  @dend
383  * ----------------------------------------------------
384  */
385 void
rmRGBtoHSV(float rr,float gg,float bb,float * hh,float * ss,float * vv)386 rmRGBtoHSV (float rr,
387 	    float gg,
388 	    float bb,
389 	    float *hh,		/* return: 0 <= h <= 1 */
390 	    float *ss,		/* return: 0 <= s <= 1 */
391 	    float *vv)		/* return: 0 <= v <= 1 */
392 {
393    double min, max, v, s, h, rc, gc, bc, r, g, b;
394 
395     /* (h,s,v) in [0..1] --> (r,g,b) will be in [0..1] - Foley & VanDam */
396     r = rr;
397     g = gg;
398     b = bb;
399 
400     max = RM_MAX(r, g);
401     max = RM_MAX(max, b);
402 
403     min = RM_MIN(r, g);
404     min = RM_MIN(min, b);
405 
406     v = max;
407 
408     if (max != 0.0)
409 	s = (max - min) / max;
410     else
411 	s = 0.0;
412 
413     if (s == 0)
414       /* h = UNDEFINED_HUE pick something */
415       h = 0.0;
416     else
417     {
418 	rc = (max - r) / (max - min);
419 	gc = (max - g) / (max - min);
420 	bc = (max - b) / (max - min);
421 	if (r == max)
422 	    h = bc - gc;
423 	else
424 	   if (g == max)
425 	      h = 2 + rc - bc;
426 	else
427 	   if (b == max)
428 	      h = 4 + gc - rc;
429 	h = h * 60;
430 	if (h < 0.0)
431 	    h = h + 360.0;
432     }
433     *hh = h / 360.0;
434     *ss = s;
435     *vv = v;
436 }
437 
438 
439 /*
440  * ----------------------------------------------------
441  * @Name rmUnionBoundingBoxes
442  @pstart
443  RMenum rmUnionBoundingBoxes (const RMvertex3D *s1min,
444 		              const RMvertex3D *s1max,
445 			      const RMvertex3D *s2min,
446 			      const RMvertex3D *s2max,
447 			      RMvertex3D *dmin,
448 			      RMvertex3D *dmax)
449  @pend
450 
451  @astart
452  const RMvertex3D *s1min, *s1max, *s2min, *s2max - handles to
453     RMvertex3D objects (input).
454 
455  RMvertex3D *dmin, *dmax - handles to RMvertex3D objects (modified).
456  @aend
457 
458  @dstart
459 
460  This routine performs a "union" operation of two, 3D boxes, returning
461  the minimum and maximum coordinates of the resulting box into
462  caller-supplied memory. Returns RM_CHILL upon success, or RM_WHACKED
463  upon failure.
464 
465  @dend
466  * ----------------------------------------------------
467  */
468 
469 RMenum
rmUnionBoundingBoxes(const RMvertex3D * s1min,const RMvertex3D * s1max,const RMvertex3D * s2min,const RMvertex3D * s2max,RMvertex3D * dmin,RMvertex3D * dmax)470 rmUnionBoundingBoxes (const RMvertex3D *s1min,
471 		      const RMvertex3D *s1max,
472 		      const RMvertex3D *s2min,
473 		      const RMvertex3D *s2max,
474 		      RMvertex3D *dmin,
475 		      RMvertex3D *dmax)
476 {
477     if ((s1min == NULL) || (s1max == NULL) || (s2min == NULL) || (s2max == NULL) || (dmin == NULL) || (dmax == NULL))
478     {
479 	rmError("rmUnionBoundingBoxes() error: one of the input parameters is NULL.");
480 	return(RM_WHACKED);
481     }
482     dmin->x = RM_MIN(s1min->x, s2min->x);
483     dmin->y = RM_MIN(s1min->y, s2min->y);
484     dmin->z = RM_MIN(s1min->z, s2min->z);
485 
486     dmax->x = RM_MAX(s1max->x, s2max->x);
487     dmax->y = RM_MAX(s1max->y, s2max->y);
488     dmax->z = RM_MAX(s1max->z, s2max->z);
489 
490     return(RM_CHILL);
491 }
492 
493 
494 /*
495  * ----------------------------------------------------
496  * @Name rmGLGetError
497  @pstart
498  int rmGLGetError (const char *string)
499  @pend
500 
501  @astart
502  const char *string - a handle to a string (input).
503  @aend
504 
505  @dstart
506 
507  This routine is a wrapper for the routine glGetError(), and is used
508  to obtain OpenGL error codes. If there are no errors, a value of zero
509  is returned by rmGLGetError(). Otherwise, the error code is returned
510  to the caller, and the error code, along with the message contained
511  in the parameter "string" is reported via rmWarning().  Refer to gl.h
512  in your OpenGL distribution for definitions of the OpenGL error
513  codes, as well as the man page for glGetError().
514 
515  This routine was used extensively for debugging during the
516  development of RM Scene Graph.
517 
518  @dend
519  * ----------------------------------------------------
520  */
521 int
rmGLGetError(const char * s)522 rmGLGetError (const char *s)
523 {
524     GLenum rstat = glGetError();
525 
526     while (rstat != GL_NO_ERROR)
527     {
528 	if (rstat != 0)
529 	{
530 	    char buf[128];
531 
532 	    sprintf(buf, "%s OpenGL error code (hex): 0x%04x ", s, rstat);
533 	    rmWarning(buf);
534 	}
535 	rstat = glGetError();
536     }
537     return(rstat);
538 }
539 
540 
541 /*
542  * ----------------------------------------------------
543  * @Name rmImageBuildMipmaps
544  @pstart
545  int rmImageBuildMipmaps (const RMimage *src,
546 		          RMimage ***mapsReturn,
547 			  RMenum hardwareEnum,
548 			  RMpipe *hwPipe)
549  @pend
550 
551  @astart
552  const RMimage *src - a handle to an RMimage object (input).
553 
554  RMimage ***mapsReturn - a pointer to an array of RMimage pointer (return).
555 
556  RMenum hardwareEnum - an RMenum value, may be either RM_HARDWARE or
557     RM_SOFTWARE (input).
558 
559  RMpipe *hwPipe - a handle to an RMpipe (input). A valid RMpipe handle
560     is required when RM_HARDWARE is requested via hardwareEnum. When
561     RM_SOFTWARE image resizing for mipmap generation is requested,
562     callers should specify NULL for the hwPipe parameter.
563  @aend
564 
565  @dstart
566 
567  This convenience routine will generate a full set of mipmaps given an
568  input image. The number of mipmaps generated is returned to the
569  caller. This value will be positive and non-zero upon success,
570  otherwise zero is returned.
571 
572  When RM_SOFTWARE is selected, RM will repeatedly call gluScaleImage
573  to produce the mipmaps, a software operation. When RM_HARDWARE is
574  set, the framebuffer itself is used to scale the image data. In some
575  cases, RM_HARDWARE will run faster by an order of magnitude than
576  RM_SOFTWARE.
577 
578  Inside this routine, an array of RMimage pointer is allocated. The
579  number of entries in this array is log2(max(width,height)) of the
580  input image, and is the number of mipmaps that will be
581  generated. Then, each of these N images is created using
582  RM_COPY_DATA, including the first image (which is a duplicate of the
583  input image). The second image will be 1/4 the size of the first, and
584  so forth down to a 1x1 image.
585 
586  At this time (January 2000), RM_HARDWARE occasionally has problems
587  with the pixel reads on some framebuffers (esp. nVidia cards under
588  Linux).
589 
590  At this time (January 2000), rmImageBuildMipmaps works ONLY on
591  RMimage objects containing a two-dimensional image. There is no
592  support at present for generating 3D mipmaps.
593 
594  At this time (January 2000), the scaled images are drawn to the
595  framebuffer for debugging purposes, regardless of whether or not
596  RM_SOFTWARE or RM_HARDWARE is specified by the caller.
597 
598  It is assumed that the input image is an even power of two in size.
599 
600  The following code snippet shows how to free the images returned by
601  rmImageBuildMipmaps.
602 
603  <pre>
604  RMimage  *source;
605  RMimage **dstMipmaps;
606  int       nMipmaps, i;
607 
608  ... stuff is assigned to source here (omitted) ...
609 
610  nMipmaps = rmImageBuildMipmaps(source, &dstMipmaps, RM_HARDWARE);
611 
612  .... do some stuff with the mipmaps (omitted) ...
613 
614  // delete the images
615  for (i = 0; i < nMipmaps; i++)
616      rmImageDelete(dstMipmaps[i]);
617  free((void *)dstMipmaps);
618  </pre>
619 
620  @dend
621  * ----------------------------------------------------
622  */
623 int
rmImageBuildMipmaps(const RMimage * src,RMimage *** maps_return,RMenum hardware_enum,RMpipe * hwPipe)624 rmImageBuildMipmaps (const RMimage *src,
625 		     RMimage ***maps_return,
626 		     RMenum hardware_enum,
627 		     RMpipe *hwPipe)
628 {
629     /* hack - right now, we can only compute mipmaps for 2D images */
630     int nmm;
631 
632     if ((RM_ASSERT(src, "rmImageBuildMipMaps() error: the input RMimage object is NULL") == RM_WHACKED) ||
633 	(RM_ASSERT(src, "rmImageBuildMipMaps() error: the input maps_return pointer is NULL") == RM_WHACKED))
634 	return(0);
635 
636     if ((hardware_enum == RM_HARDWARE) && (hwPipe == NULL))
637     {
638 	rmError("rmImageBuildMipmaps() error: a valid RMpipe must be specified when using RM_HARDWARE as the mipmap generation method. ");
639 	return(0);
640     }
641 
642     if (private_rmImageGetNDims(src) == 2)
643 	nmm = private_rmImage2DBuildMipmaps(src, maps_return, hardware_enum, hwPipe);
644     else
645     {
646 	rmWarning(" mipmap generation for 3D images is currently under development.");
647 	nmm = 0;
648     }
649 
650     return(nmm); /* number of mipmaps generated */
651 }
652 
653 
654 /* PRIVATE
655  *
656  * this internal routine is used to set up the view and projection
657  * matrices, and a simple viewing mode for the purpose of drawing
658  * image data into the framebuffer.
659  *
660  * October 2000 - rewrote to be thread safe.
661  */
662 void
private_rmInitInternalImagingPipeline(RMpipe * p)663 private_rmInitInternalImagingPipeline (RMpipe *p)
664 {
665     int     w, h;
666 
667     /*
668      * it may not be necessary to make the RMpipe "current", as the
669      * application should have made the pipe current already - however,
670      * we're taking a conservative approach. at worst, we incur the
671      * cost of a call to glxMakeCurrent or wglMakeCurrent.
672      */
673     rmPipeMakeCurrent(p);
674 
675     /*
676      * set matrix parameters for drawing images.
677      */
678     glMatrixMode(GL_MODELVIEW);
679     glLoadIdentity();
680     glMatrixMode(GL_PROJECTION);
681     glLoadIdentity();
682 
683     glPixelZoom((GLfloat)1.0, (GLfloat)1.0);
684 
685     glDisable(GL_DEPTH_TEST);
686     glDisable(GL_BLEND);
687 
688     rmPipeGetWindowSize(p, &w, &h);
689 
690     /* the glOrtho call needs some tweaking. */
691     glOrtho(0.0, (double)(w - 1), 0.0, (double)(h - 1), -1.0, 1.0);
692 
693     glViewport(0, 0, w, h);
694 
695     glReadBuffer(GL_FRONT);
696 }
697 
698 
699 /* PRIVATE */
700 /*
701  * 10/2000 - rewrote to be thread safe.
702  */
703 int
private_rmImage2DBuildMipmaps(const RMimage * img,RMimage *** maps_return,int filter_method,RMpipe * p)704 private_rmImage2DBuildMipmaps (const RMimage *img,
705 			       RMimage ***maps_return,
706 			       int filter_method,
707 			       RMpipe *p)
708 {
709     /*
710      * TODO:
711      *
712      * we need to make some checks if we're using hardware for scaling:
713      * 1. is the currently defined window large enough to handle our
714      *    imaging requirements?
715      * 2. if not, what do we do about it?
716      *    a. fall back onto software
717      *    b. resize the window to fit the problem? it may still be possible
718      *       to exceed resources on the display with large images which
719      *       won't fit into the window.
720      */
721     unsigned char *sdata;
722     int            w, h, sw, sh;
723     int            wmag, hmag;
724     int            i, count;
725     int            winw, winh;
726     RMimage      **tt, *t;
727     RMenum         rmformat, rmtype;
728     GLenum         format, ptype;
729 
730     rmPipeGetWindowSize(p, &winw, &winh);
731 
732     w = private_rmImageGetWidth(img);
733     h = private_rmImageGetHeight(img);
734 
735     sw = rmNearestPowerOfTwo(w);
736     sh = rmNearestPowerOfTwo(h);
737 
738     /* need to check if sw,sh exceed the size of the current window.
739      for now, we'll just report an error.  later we may want to take more
740      positive action, such as temporarily resizing the window for use
741      in imaging operations. */
742     {
743 /*	fprintf(stderr,"rmImage2DBuildMipaps: need to update code to use pipe for window dims. \n"); */
744 	if ((sw > winw) || (sh > winh))
745 	{
746 	    char buf[512];
747 	    sprintf(buf, "%s %d by %d", " The current window is not large enough to accomodate texture resizing in hardware. Either increase the size of the window or decrease the size of the texture (NOTE: later versions of RM will temporarily resize the window). Parts of the resized texture may appear 'blacked out.' We need a window of at least \n", sw, sh);
748 	    rmWarning(buf);
749 	}
750     }
751 
752     wmag = rmIntMagnitude(sw);
753     hmag = rmIntMagnitude(sh);
754 
755     /* figure out how many images to create */
756     count = RM_MAX(wmag, hmag) + 1;
757 
758     rmformat = private_rmImageGetFormat(img);
759     rmtype = private_rmImageGetType(img);
760 
761     tt = *maps_return = (RMimage **)malloc(sizeof(RMimage *)*count);
762 
763     private_rmInitInternalImagingPipeline(p);
764 
765     sdata = private_rmImageGetPixelData(img);
766 
767     format = private_rmImageGetOGLFormat(img);
768     ptype = private_rmImageGetOGLType(img);
769 
770     /*
771      * note: format as returned by that routine isn't exactly correct
772      * when the image type is one of the indexed types. for example, if
773      * we have raw scalars, as is the case when we have indexed images,
774      * that routine returns GL_RGB for RM_IMAGE_INDEXED_RGB. do we want
775      * blat out raw scalars as, say, luminance or try to do something else?
776      */
777     glDrawBuffer(GL_FRONT);	/* ?? we could put this into the back buffer and the user would never see it..*/
778 
779     /* this draws the original image. not needed, but cute */
780     glRasterPos2f(0.0,0.0);
781 
782     glDrawPixels(w, h, format, ptype, sdata);
783 
784     glFinish();
785 
786     for (i = 0; i < count; i++)
787     {
788 	unsigned char *dest_data;
789 	int            tw, th;
790 	int            status;
791 	float          xzoom, yzoom;
792 
793 	tw = RM_MAX((sw >> i), 1);
794 	th = RM_MAX((sh >> i), 1);
795 
796 	tt[i] = t = rmImageNew(2, tw, th, 1, rmformat, rmtype, RM_COPY_DATA);
797 
798 	if (i == 0)
799 	{
800 	    xzoom = (float)tw / (float)w;
801 	    yzoom = (float)th / (float)h;
802 	}
803 	else
804 	{
805 	    xzoom = 0.5;
806 	    yzoom = 0.5;
807 	}
808 
809 	{
810 	    unsigned char *image_data;
811 	    int            lastw, lasth;
812 
813 	    if (i == 0)
814 	    {
815 		/* draw the original image, but with zoom  */
816 		image_data = sdata;
817 		lastw = w;
818 		lasth = h;
819 	    }
820 	    else
821 	    {
822 		rmImageGetImageSize(tt[i - 1], NULL, &lastw, &lasth, NULL, NULL, NULL);
823 		image_data = private_rmImageGetPixelData(tt[i - 1]);
824 	    }
825 
826 	    dest_data = private_rmImageGetPixelData(t);
827 
828 	    if (filter_method == RM_HARDWARE)
829 	    {
830 		glPixelZoom((GLfloat)xzoom, (GLfloat)yzoom);
831 		glRasterPos2f(0.0, 0.0);
832 		glDrawPixels(lastw, lasth, format, ptype, (const void *)image_data);
833 		glFinish();
834 
835 		glReadBuffer(GL_FRONT);
836 
837 		if (format == GL_LUMINANCE)
838 	        {
839 		    glPixelTransferf(GL_RED_SCALE, (GLfloat)0.3);
840 		    glPixelTransferf(GL_RED_BIAS, (GLfloat)0.0);
841 		    glPixelTransferf(GL_GREEN_SCALE, (GLfloat)0.59);
842 		    glPixelTransferf(GL_GREEN_BIAS, (GLfloat)0.0);
843 		    glPixelTransferf(GL_BLUE_SCALE, (GLfloat)0.1);
844 		    glPixelTransferf(GL_BLUE_BIAS, (GLfloat)0.0);
845 		}
846 
847 		/* read the zoomed image back into a local buffer */
848 		glReadPixels(0, 0, tw, th, format, ptype, dest_data);
849 
850 		if (format == GL_LUMINANCE)
851 		{
852 		    glPixelTransferf(GL_RED_SCALE, (GLfloat)1.0);
853 		    glPixelTransferf(GL_GREEN_SCALE, (GLfloat)1.0);
854 		    glPixelTransferf(GL_BLUE_SCALE, (GLfloat)1.0);
855 		}
856 		glFinish();
857 
858 	    }
859 	    else
860 	    {
861 		/* this uses the glu software image scaler rather than  the hardware imaging pipe */
862 		status = gluScaleImage(format, w, h, ptype, (const void *)(sdata), tw, th, ptype, (void *)(dest_data));
863 	    }
864 	}
865 	glPixelZoom((GLfloat)1.0, (GLfloat)1.0);
866 
867 	glClear(GL_COLOR_BUFFER_BIT);
868 
869 	glRasterPos2f(0.0, 0.0);
870 	glDrawPixels(tw, th, format, ptype, dest_data);
871 
872 	glFinish();
873     }
874 
875     return(count);
876 }
877 
878 
879 /* PRIVATE
880  *
881  * here is the guts of the 3D mipmap generator. it's not wired
882  * in at this time, but has been used experimentally in the past.
883  *
884  * jan 2000 - i'm not sure what the status is of this routine at
885  * this time...it probably needs to be rewritten.
886  */
887 RMenum
private_rmImage3DResize(const RMimage * src,RMimage * dst,RMenum hardware_enum,RMpipe * hwPipe)888 private_rmImage3DResize (const RMimage *src,
889 			 RMimage *dst,
890 			 RMenum hardware_enum,
891 			 RMpipe *hwPipe)
892 {
893     /*
894      * 1. for each w x h slice of the source volume, use hardware to
895      *    rescale the image to new size.
896      * 2. read the pixels back from the framebuffer and dump them to
897      *    a temp area (file? memory?)
898      * 3. for each w x d slice of the intermediate volume, resize that
899      *    image to the new size.
900      * 4. read the pixels back from the framebuffer and stuff them
901      *    into "dst"
902      */
903 
904     /*
905      * this routine used to have "scale" and "bias" as input parms. why?
906      * todo: write software version.
907      */
908 
909     unsigned char *src_data, *sdata;
910     unsigned char *dest_data, *ddata;
911     unsigned char *intermed_space; /* hold intermediate step in memory..hope this machine can swap or has a bunch of memory */
912     unsigned char *idata;
913     unsigned char *wbuf;	/* images of size dest_width * source_depth and is used in pass2 processing */
914     unsigned char *lbuf;	/* images of size dst_width * dst_depth used to receive pass2 scaled data. */
915     int            i, stride;
916     int            sw, sh, sd;
917     int            dw, dh, dd;
918     float          scale = 1.0;
919     float          bias = 0.0;
920     float          xzoom, yzoom;
921     GLenum         glformat, ptype;
922 
923     if ((RM_ASSERT(src, "private_rmImage3DResize() error: source RMimage pointer is NULL") == RM_WHACKED) ||
924 	(RM_ASSERT(dst, "private_rmImage3DResize() error: dest RMimage pointer is NULL") == RM_WHACKED))
925 	return(RM_WHACKED);
926 
927 #if 0
928     /* this should now be working */
929     if (hardware_enum == RM_SOFTWARE)
930 	rmWarning("private_rmImage3DResize() warning: RM_SOFTWARE is not yet supported. using RM_HARDWARE for image resize.");
931 #endif
932 
933     rmImageGetImageSize(src, NULL, &sw, &sh, &sd, NULL, NULL);
934     rmImageGetImageSize(dst, NULL, &dw, &dh, &dd, NULL, NULL);
935 
936     /* check to see if currently-defined window, etc. can accomodate
937      the size of images that we're going to throw at it. */
938 
939     if (hardware_enum == RM_HARDWARE)
940     {
941 	private_rmInitInternalImagingPipeline(hwPipe);
942 	glDrawBuffer(GL_FRONT);	/* ?? we could put this into the back */
943     }
944 
945     /* loop over source depth */
946     src_data = private_rmImageGetPixelData(src);
947     stride = private_rmImageGetElements(src);
948     glformat = private_rmImageGetOGLFormat(src);
949     ptype = private_rmImageGetOGLType(src);
950 
951 #if 0
952     srcglformat = private_rmImageGetOGLFormat(src);
953     dstglformat = private_rmImageGetOGLFormat(dst);
954 #endif
955 
956     intermed_space = (unsigned char *)malloc(sizeof(unsigned char) * dw * dh * sd * stride);
957     wbuf = (unsigned char *)malloc(sizeof(unsigned char) * dw * sd * stride);
958     lbuf = (unsigned char *)malloc(sizeof(unsigned char) * dw * dd * stride);
959     if ((intermed_space == NULL) || (wbuf == NULL) || (lbuf == NULL))
960     {
961 	rmError(" private_rmImage3DResize..can't get memory for processing. aborting. \n");
962 	return(RM_WHACKED);
963     }
964 
965     if (stride == -1)
966     {
967 	rmError(" unknown image format in rmImage3DResize... aborting \n");
968 	return(RM_WHACKED);
969     }
970 
971     xzoom = (float)dw / (float)sw;
972     yzoom = (float)dh / (float)sh;
973 
974     for (i = 0; i < sd; i++)
975     {
976 	sdata = src_data + (i * stride * sw * sh);
977 	idata = intermed_space + (i * stride * dw * dh);
978 
979 	if (hardware_enum == RM_SOFTWARE)
980 	{
981 	    fake_gluScaleImage(glformat, sw, sh, ptype, sdata,
982 			       dw, dh, ptype, idata);
983 	}
984 	else
985 	{
986 	    glRasterPos2f(0.0, 0.0);
987 	    glPixelZoom((GLfloat)xzoom, (GLfloat)yzoom);
988 	    glDrawPixels(sw, sh, glformat, ptype, sdata);
989 
990 	    glReadBuffer(GL_FRONT);
991 
992 	    if (glformat == GL_LUMINANCE)
993 	    {
994 		glPixelTransferf(GL_RED_SCALE, (GLfloat)0.3 * scale);
995 		glPixelTransferf(GL_RED_BIAS, (GLfloat)bias);
996 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)0.59 * scale);
997 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)bias);
998 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)0.1 * scale);
999 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)bias);
1000 	    }
1001 	    else
1002 	    {
1003 		glPixelTransferf(GL_RED_SCALE, (GLfloat)scale);
1004 		glPixelTransferf(GL_RED_BIAS, (GLfloat)bias);
1005 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)scale);
1006 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)bias);
1007 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)scale);
1008 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)bias);
1009 	    }
1010 
1011 	    /* read the zoomed image back into a local buffer */
1012 	    glPixelZoom((GLfloat)1.0f, (GLfloat)1.0F);
1013 	    glReadPixels(0, 0, dw, dh, glformat, ptype, idata);
1014 
1015 	    if (glformat == GL_LUMINANCE)
1016 	    {
1017 		glPixelTransferf(GL_RED_SCALE, (GLfloat)1.0);
1018 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)1.0);
1019 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)1.0);
1020 
1021 		glPixelTransferf(GL_RED_BIAS, (GLfloat)0.0);
1022 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)0.0);
1023 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)0.0);
1024 	    }
1025 	} /* end RM_HARDWARE */
1026     }
1027 
1028     dest_data = private_rmImageGetPixelData(dst);
1029     src_data = intermed_space;
1030 
1031     /* done with pass 1.  now do pass 2. */
1032     xzoom = 1.0;
1033     yzoom = (float)dd / (float)sd;
1034 
1035     if (hardware_enum == RM_HARDWARE)
1036 	glPixelZoom((GLfloat)xzoom, (GLfloat)yzoom);
1037 
1038     for (i = 0; i < dh; i++)
1039     {
1040 	int            id, tstride, wbufstride;
1041 	unsigned char *wbuf2;
1042 
1043 	/* load up temp image from holding buffer */
1044 	sdata = src_data + (i * dw * stride);
1045 	tstride = dw * dh * stride;
1046 
1047 	wbuf2 = wbuf;
1048 	wbufstride = dw * stride;
1049 	for (id = 0; id < sd; id++)
1050         {
1051 	    memcpy((wbuf2), (sdata), (sizeof(unsigned char) * dw * stride));
1052 	    sdata += tstride;
1053 	    wbuf2 += wbufstride;
1054 	}
1055 
1056 	/* now that we have a 2d image (representing a w x d slice of the
1057 	 intermediate volume) blast it down the imaging pipeline */
1058 
1059 	if (hardware_enum == RM_SOFTWARE)
1060 	{
1061 	    fake_gluScaleImage(glformat, dw, sd, ptype, wbuf,
1062 			       dw, dd, ptype, lbuf);
1063 	}
1064 	else
1065 	{
1066 	    glPixelZoom((GLfloat)xzoom, (GLfloat)yzoom);
1067 	    glRasterPos2f(0.0, 0.0);
1068 	    glDrawPixels(dw, sd, glformat, ptype, wbuf);
1069 
1070 	    glReadBuffer(GL_FRONT);
1071 
1072 	    if (glformat == GL_LUMINANCE)
1073 	    {
1074 		glPixelTransferf(GL_RED_SCALE, (GLfloat)0.3 * scale);
1075 		glPixelTransferf(GL_RED_BIAS, (GLfloat)bias);
1076 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)0.59 * scale);
1077 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)bias);
1078 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)0.1 * scale);
1079 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)bias);
1080 	    }
1081 	    else
1082 	    {
1083 		glPixelTransferf(GL_RED_SCALE, (GLfloat)scale);
1084 		glPixelTransferf(GL_RED_BIAS, (GLfloat)bias);
1085 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)scale);
1086 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)bias);
1087 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)scale);
1088 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)bias);
1089 	    }
1090 
1091 	    /* read the zoomed image back into a local buffer. */
1092 	    glPixelZoom((GLfloat)1.0f, (GLfloat)1.0f);
1093 	    glReadPixels(0, 0, dw, dd, glformat, ptype, lbuf);
1094 
1095 	    if (glformat == GL_LUMINANCE)
1096 	    {
1097 		glPixelTransferf(GL_RED_SCALE, (GLfloat)1.0);
1098 		glPixelTransferf(GL_GREEN_SCALE, (GLfloat)1.0);
1099 		glPixelTransferf(GL_BLUE_SCALE, (GLfloat)1.0);
1100 
1101 		glPixelTransferf(GL_RED_BIAS, (GLfloat)0.0);
1102 		glPixelTransferf(GL_GREEN_BIAS, (GLfloat)0.0);
1103 		glPixelTransferf(GL_BLUE_BIAS, (GLfloat)0.0);
1104 	    }
1105 	} /* end RM_HARDWARE */
1106 
1107 	/* now, stuff from lbuf into the final volume buffer */
1108 	ddata = dest_data + (i * dw * stride);
1109 	tstride = dw * dh * stride;
1110 	wbufstride = dw * stride;
1111 	wbuf2 = lbuf;
1112 
1113 	for (id = 0; id < dd; id++)
1114 	{
1115 	    memcpy((void *)ddata, (void *)wbuf2, (sizeof(unsigned char) * dw * stride));
1116 	    ddata += tstride;
1117 	    wbuf2 += wbufstride;
1118 	}
1119     }
1120     free((void *)lbuf);
1121     free((void *)wbuf);
1122     free((void *)intermed_space);
1123 
1124     return(RM_CHILL);
1125 }
1126 
1127 /* PRIVATE */
1128 RMenum
private_rmInitCacheKeyMutex(void)1129 private_rmInitCacheKeyMutex(void)
1130 {
1131     cacheKeyMutex = rmMutexNew(RM_MUTEX_UNLOCK);
1132     if (cacheKeyMutex == NULL)
1133     {
1134 	rmError("private_rmInitCacheKeyMutex() error: problem initializing cache key mutex. cache keys are not guaranteed to be unique in the presence of multiple threads.");
1135 	return(RM_WHACKED);
1136     }
1137     return(RM_CHILL);
1138 }
1139 
1140 /* PRIVATE */
1141 RMenum
private_rmDestroyCacheKeyMutex(void)1142 private_rmDestroyCacheKeyMutex(void)
1143 {
1144     rmMutexDelete(cacheKeyMutex);
1145     return RM_CHILL;
1146 }
1147 
1148 /* PRIVATE */
1149 RMcacheKey
private_rmGetNewCacheKey(void)1150 private_rmGetNewCacheKey(void)
1151 {
1152     RMcacheKey rval;
1153     static unsigned int counter=0;
1154     /*
1155      * there's only one component manager, regardless of the
1156      * number of app threads. we get a cache key that is guaranteed
1157      * to be unique simply by protecting a counter with a mutex
1158      * to ensure caller access is serialized.
1159      */
1160 
1161     if (cacheKeyMutex != NULL)
1162 	rmMutexLock(cacheKeyMutex);
1163 
1164     rval = counter;
1165     counter++;
1166 
1167     if (cacheKeyMutex != NULL)
1168 	rmMutexUnlock(cacheKeyMutex);
1169 
1170     return(rval);
1171 }
1172 
1173 /* PRIVATE */
1174 RMenum
private_rmCacheInit(RMcontextCache ** toCreate)1175 private_rmCacheInit(RMcontextCache **toCreate)
1176 {
1177     RMcontextCache *c;
1178     int nPrims, nImgs, nTextures;
1179     int i;
1180 
1181     c = (RMcontextCache *)malloc(sizeof(RMcontextCache));
1182     memset(c, 0, sizeof(RMcontextCache));
1183 
1184     /* prims, images, textures & associated cache keys */
1185     nPrims = NUM_ITEMS_PER_PAGE;
1186     c->primDisplayListIDs = (GLuint *)malloc(sizeof(GLuint)*nPrims);
1187     c->primCacheKeys = (RMcacheKey *)malloc(sizeof(GLuint)*nPrims);
1188     c->numPrimDisplayListIDs = nPrims;
1189     c->numPrimCacheKeys = nPrims;
1190 
1191     for (i=0;i<nPrims;i++)
1192     {
1193 	c->primDisplayListIDs[i] = -1;
1194 	c->primCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1195     }
1196 
1197     nImgs = NUM_ITEMS_PER_PAGE;
1198     c->imgDisplayListIDs = (GLuint *)malloc(sizeof(GLuint)*nImgs);
1199     c->imgCacheKeys = (RMcacheKey *)malloc(sizeof(GLuint)*nImgs);
1200     c->numImgDisplayListIDs = nImgs;
1201     c->numImgCacheKeys = nImgs;
1202 
1203     for (i=0;i<nImgs;i++)
1204     {
1205 	c->imgDisplayListIDs[i] = -1;
1206 	c->imgCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1207     }
1208 
1209     nTextures = NUM_ITEMS_PER_PAGE;
1210     c->textureIDs = (GLuint *)malloc(sizeof(GLuint)*nTextures);
1211     c->textureIDCacheKeys = (RMcacheKey *)malloc(sizeof(GLuint)*nTextures);
1212     c->textureDataCacheKeys = (RMcacheKey *)malloc(sizeof(GLuint)*nTextures);
1213     c->numTextureIDs = nTextures;
1214     c->numTextureIDCacheKeys = nTextures;
1215     c->numTextureDataCacheKeys = nTextures;
1216 
1217     for (i=0;i<nTextures;i++)
1218     {
1219 	c->textureIDs[i] = -1;
1220 	c->textureIDCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1221 	c->textureDataCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1222     }
1223 
1224     /* font registry */
1225     c->pipeFontRegistry = private_rmFontRegistryNew();
1226 
1227     *toCreate = c;
1228     return (RM_CHILL);
1229 }
1230 
1231 /* PRIVATE */
1232 RMenum
private_rmCacheDelete(RMpipe * p,RMcontextCache * toDelete)1233 private_rmCacheDelete(RMpipe *p,
1234 		      RMcontextCache *toDelete)
1235 {
1236     RMcontextCache *c;
1237 
1238     c = toDelete;
1239 
1240     private_rmCacheDeleteAllPrimitiveDisplayLists(c);
1241     private_rmCacheDeleteQuadrics(c);
1242     private_rmCacheDeleteAllImageDisplayLists(c);
1243     private_rmCacheDeleteAllTextures(c);
1244 
1245     /* prims, images, textures & associated cache keys */
1246     free((void *)(c->primDisplayListIDs));
1247     free((void *)(c->primCacheKeys));
1248 
1249     free((void *)(c->imgDisplayListIDs));
1250     free((void *)(c->imgCacheKeys));
1251 
1252     free((void *)(c->textureIDs));
1253     free((void *)(c->textureIDCacheKeys));
1254     free((void *)(c->textureDataCacheKeys));
1255 
1256     /* font registry */
1257     private_rmFontRegistryDelete(p, c->pipeFontRegistry);
1258 
1259     free((void *)c);
1260     return (RM_CHILL);
1261 }
1262 
1263 /* PRIVATE */
1264 void
private_rmCacheFlush(RMcontextCache * toDelete)1265 private_rmCacheFlush(RMcontextCache *toDelete)
1266 {
1267     extern RMcompMgrHdr *global_RMimagePool, *global_RMprimitivePool;
1268     extern RMcompMgrHdr *global_RMtexturePool;
1269     RMcontextCache *c;
1270 
1271     int nPrims, nImages, nTextures,i;
1272 
1273     /*
1274      * we could store the number of active prims, images & textures
1275      * in the RMpipe, but don't since our goal is to effectively
1276      * hide the many-pipes/renderers to one scene graph metaphor.
1277      */
1278 
1279     /*
1280      * temp hack - we should traverse the pseudo linked list
1281      * in each RMcompMgrHdr structure to visit only RMprims,
1282      * RMimages and RMtextures that are resident in the scene graph.
1283      * what we do instead is charge through the entire pool of
1284      * all such objects.
1285      */
1286     nPrims = global_RMprimitivePool->currentPoolSize;
1287     nImages = global_RMimagePool->currentPoolSize;
1288     nTextures = global_RMtexturePool->currentPoolSize;
1289 
1290     /* first, release resources associated with any existing display
1291      lists or textures. */
1292 
1293     /*
1294      * Implementation/efficiency note: it may be the case that
1295      * some OpenGL implementations don't recycle display list/
1296      * texture IDs, in which case, it would be possible to "run out"
1297      * after some number of cache flushes/rebuilds. We may want
1298      * to modify our flush strategy by *not* deleting display
1299      * lists and textures, and simply rebuilding them the next
1300      * time the i'th RMprimitive, RMimage and RMtexture needs
1301      * to have retained mode structures rebuilt.
1302      */
1303 
1304     c = toDelete;
1305     if (RM_ASSERT(c,"private_rmCacheFlush() error: the input context cache is NULL!") == RM_WHACKED)
1306 	return;
1307 
1308 
1309     /*
1310      * each of these loops releases any OpenGL resources that might
1311      * be used. note that we're re-initializing the entries to
1312      * default values that mean "empty", then just throwing the
1313      * memory away a little bit later. gotta do something with
1314      * those gigahertz CPUs.
1315      */
1316     for (i=0;i<nPrims;i++)
1317     {
1318 	if (glIsList(c->primDisplayListIDs[i]) == GL_TRUE)
1319 	    glDeleteLists(c->primDisplayListIDs[i], 1);
1320 
1321 	c->primDisplayListIDs[i] = -1;
1322 	c->primCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1323     }
1324 
1325     for (i=0;i<nImages;i++)
1326     {
1327 	if (glIsList(c->imgDisplayListIDs[i]) == GL_TRUE)
1328 	    glDeleteLists(c->imgDisplayListIDs[i], 1);
1329 
1330 	c->imgDisplayListIDs[i] = -1;
1331 	c->imgCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1332     }
1333 
1334     for (i=0;i<nTextures;i++)
1335     {
1336 	if (glIsTexture(c->textureIDs[i]) == GL_TRUE)
1337 	    glDeleteTextures(1,&(c->textureIDs[i]));
1338 
1339 	c->textureIDs[i] = -1;
1340 	c->textureIDCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1341 	c->textureDataCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1342     }
1343 
1344     /* now, free up the memory associated with the cache keys */
1345     free((void *)c->primDisplayListIDs);
1346     free((void *)c->primCacheKeys);
1347 
1348     free((void *)c->imgDisplayListIDs);
1349     free((void *)c->imgCacheKeys);
1350 
1351     free((void *)c->textureIDs);
1352     free((void *)c->textureIDCacheKeys);
1353     free((void *)c->textureDataCacheKeys);
1354 
1355     free((void *)c);
1356 }
1357 
1358 /* PRIVATE */
1359 RMenum
private_rmCacheDeleteAllPrimitiveDisplayLists(RMcontextCache * c)1360 private_rmCacheDeleteAllPrimitiveDisplayLists(RMcontextCache *c)
1361 {
1362     int i;
1363     /*
1364      * this routine will delete all display lists associated with
1365      * RMprimitive's in the RMpipe's context cache.
1366      */
1367 
1368     /*
1369      * 7/4/01 w.bethel
1370      * the following code makes simplifying assumptions that
1371      * result in overkill:
1372      * 1. RM_COMPONENT_POOL_SIZE is the init size of the context
1373      *    cache, not the real size as the component mgr pool grows
1374      *    (which isn't yet implemented anyway).
1375      * 2. the following loop serially examines *all* primDisplayListIDs
1376      *    rather than looking at only a subset. this is more expensive than
1377      *    alternative approaches, but will do a more thorough job of
1378      *    cleansing display lists across potentially disconnected
1379      *    scene graph nodes.
1380      * 3. this routine assumes that you really want to blow away all
1381      *    the display lists owned by an RMpipe.
1382      *
1383      * 8/29/02 - cleaned up code to accommodate dynamic object reallocs.
1384      */
1385 
1386     for (i=0; i < c->numPrimDisplayListIDs; i++)
1387     {
1388 	GLuint list = c->primDisplayListIDs[i];
1389 
1390 	if ((list != (unsigned int)(-1)) && (glIsList(list)==GL_TRUE))
1391 	{
1392 	    glDeleteLists(list,1);
1393 	    c->primDisplayListIDs[i] = -1;
1394 	    c->primCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1395 	}
1396     }
1397     return RM_CHILL;
1398 }
1399 
1400 /* PRIVATE */
1401 RMenum
private_rmCacheDeleteAllTextures(RMcontextCache * c)1402 private_rmCacheDeleteAllTextures(RMcontextCache *c)
1403 {
1404     int i;
1405     /*
1406      * this routine will delete all texture object id's associated with
1407      * the RMpipe's context cache.
1408      */
1409 
1410     /*
1411      * 7/4/01 w.bethel
1412      * the following code makes simplifying assumptions that
1413      * result in overkill:
1414      * 1. RM_COMPONENT_POOL_SIZE is the init size of the context
1415      *    cache, not the real size as the component mgr pool grows
1416      *    (which isn't yet implemented anyway).
1417      * 2. the following loop serially examines *all* textureIDs
1418      *    rather than looking at only a subset. this is more expensive than
1419      *    alternative approaches, but will do a more thorough job of
1420      *    cleansing textures across potentially disconnected
1421      *    scene graph nodes.
1422      * 3. this routine assumes that you really want to blow away all
1423      *    the textures owned by an RMpipe.
1424      *
1425      * 8/29/02 - wes. cleaned up to accommodate dynamic object reallocs.
1426      */
1427 
1428     for (i=0; i < c->numTextureIDs; i++)
1429     {
1430 	GLuint objID = c->textureIDs[i];
1431 
1432 	if ((objID != (GLuint)(0)) && (glIsTexture(objID)==GL_TRUE))
1433 	{
1434 	    glDeleteTextures(1, &objID);
1435 	    c->textureIDs[i] = -1;
1436 	    c->textureIDCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1437 	    c->textureDataCacheKeys[i] = RM_MAKE_CACHEKEY(-1);
1438 	}
1439     }
1440     return RM_CHILL;
1441 }
1442 
1443 /* PRIVATE */
1444 RMenum
private_rmCacheDeleteAllImageDisplayLists(RMcontextCache * c)1445 private_rmCacheDeleteAllImageDisplayLists(RMcontextCache *c)
1446 {
1447     int i;
1448     /*
1449      * this routine will display list id's associated with
1450      * RMimages in the RMpipe's context cache.
1451      */
1452 
1453     /*
1454      * 7/4/01 w.bethel
1455      * the following code makes simplifying assumptions that
1456      * result in overkill:
1457      * 1. RM_COMPONENT_POOL_SIZE is the init size of the context
1458      *    cache, not the real size as the component mgr pool grows
1459      *    (which isn't yet implemented anyway).
1460      * 2. the following loop serially examines *all* RMimage display list ids
1461      *    rather than looking at only a subset. this is more expensive than
1462      *    alternative approaches, but will do a more thorough job of
1463      *    cleansing display list ids across potentially disconnected
1464      *    scene graph nodes.
1465      * 3. this routine assumes that you really want to blow away all
1466      *    the textures owned by an RMpipe.
1467      *
1468      * 8/29/02 - wes. updated to accommodate dynamic object reallocs.
1469      */
1470 
1471     for (i=0; i < c->numImgDisplayListIDs; i++)
1472     {
1473 	GLuint list = c->imgDisplayListIDs[i];
1474 
1475 	if ((list != (unsigned int)(-1)) && (glIsList(list)==GL_TRUE))
1476 	{
1477 	    glDeleteLists(list,1);
1478 	    c->imgDisplayListIDs[i] = RM_MAKE_CACHEKEY(-1);
1479 	    c->imgCacheKeys[i] = (RMcacheKey)(-1);
1480 	}
1481     }
1482     return RM_CHILL;
1483 }
1484 
1485 /* PRIVATE */
1486 int
private_rmCacheComputeNumberNewPages(int oldNItems,int numItemsPerPage,int newIndx)1487 private_rmCacheComputeNumberNewPages(int oldNItems,
1488 				     int numItemsPerPage,
1489 				     int newIndx)
1490 {
1491     /*
1492      * input: oldNItems - says how many items we have already,
1493      *        nItemsPerPage - number of items per page in realloc
1494      *        newIndx - index, or "item number" to meet or exceed.
1495      *
1496      * compute and return: number of pages, at newItemsPerPage, must be
1497      * allocated in order to accommodate an items positioned at "newIndx."
1498      */
1499     int i = oldNItems / numItemsPerPage;
1500     int newTop = oldNItems;
1501 
1502     while (newIndx >= newTop)
1503     {
1504 	newTop += numItemsPerPage;
1505 	i++;
1506     }
1507     return i; /* return a count of new pages needed */
1508 }
1509 
1510 /* EOF */
1511 
1512