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