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: rmogl.c,v 1.12 2005/06/26 19:00:12 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.12 $
29  * $Log: rmogl.c,v $
30  * Revision 1.12  2005/06/26 19:00:12  wes
31  * New routines for push/pop the OpenGL attrib stack. These contain lots
32  * of error checking code that can be activated via DEBUG_LEVEL in rmprivat.h.
33  *
34  * Revision 1.11  2005/06/08 18:32:47  wes
35  * Replaced APIENTRY with the well-defined GLAPIENTRY.
36  *
37  * Revision 1.10  2005/06/06 02:13:40  wes
38  * Updated private_rmGLGetProcAddr to convert the function name argument
39  * from type char * to GLbyte * (why use a ubyte for a function name??)
40  *
41  * Revision 1.9  2005/06/06 02:04:29  wes
42  * Lots of small additions to clean up compiler warnings.
43  *
44  * Revision 1.8  2005/03/16 16:45:14  wes
45  * Minor tweak to diagnostic output produced by my_glPopAttrib in debug mode.
46  *
47  * Revision 1.7  2005/02/19 16:28:54  wes
48  * Distro sync and consolidation.
49  * Fixes for a number of state tracking buglets.
50  *
51  * Revision 1.6  2005/01/23 17:08:25  wes
52  * Copyright updated to 2005.
53  * Updates to support access and use of extensions; multitexturing on all
54  * platforms, use of 3d texture extension to realize implementation of
55  * volume rendering and related functions on Windows platforms.
56  *
57  * Revision 1.5  2004/01/16 16:46:09  wes
58  * Updated copyright line for 2004.
59  *
60  * Revision 1.4  2003/03/16 21:56:16  wes
61  * Documentation updates.
62  *
63  * Revision 1.3  2003/02/14 00:18:23  wes
64  * Added new wrapper routine for glCallLists. In a CR implementation, it will
65  * use the RMprimitive's bounding box as the source for parms for the
66  * GL_OBJECT_BBOX_CR extension.
67  *
68  * Revision 1.2  2003/02/02 02:07:15  wes
69  * Updated copyright to 2003.
70  *
71  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
72  * Manual rebuild of rm150 repository.
73  *
74  * Revision 1.22  2003/01/27 05:04:42  wes
75  * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR
76  * platforms w/o too much disruption to existing apps.
77  *
78  * Revision 1.21  2003/01/16 22:21:17  wes
79  * Updated all source files to reflect new organization of header files:
80  * all header files formerly located in include/rmaux, include/rmi, include/rmv
81  * are now located in include/rm.
82  *
83  * Revision 1.20  2003/01/11 18:44:22  wes
84  * Added global control over whether or not display lists are used during
85  * rendering by adding the new RMpipe controls rmPipeSetDisplayListEnable()
86  * and rmPipeGetDisplayListEnable().
87  *
88  * Revision 1.19  2003/01/07 03:11:12  wes
89  * Removed some debug printf's inside the display list dispatch routine.
90  *
91  * Revision 1.18  2002/12/31 00:55:22  wes
92  *
93  * Various enhancements to support Chromium - achitecture-specific sections
94  * of RMpipe were cleaned up, etc.
95  *
96  * Revision 1.17  2002/11/27 00:44:19  wes
97  * Added code that honors the rmPrimitive's display list enable flag.
98  * If set to RM_FALSE, no display lists will be generated for a primitive.
99  *
100  * Revision 1.16  2002/09/05 15:07:08  wes
101  * Inside delete texture code, we no longer check for glIsTexture
102  * when a realloc of textureIDs is imminent. Saves a little time,
103  * and avoids a segfault.
104  *
105  * Revision 1.15  2002/08/29 22:20:32  wes
106  *
107  * Massive upgrade to accommodate dynamic object reallocation within
108  * the component manager, and within the context cache. Use the
109  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
110  * whenever a realloc occurs. With this upgrade, there are no
111  * OpenRM limits on the size of the scene graph. There will be external
112  * limits, such as the amount of RAM and the amount of space available
113  * to your OpenGL implementation.
114  *
115  * Revision 1.14  2002/06/02 15:15:34  wes
116  * Added RMstateCache code to help eliminate the number of state changes
117  * made during the render traversal. The RMstateCache tracks
118  * the actual OpenGL rendering state w/o the need for querying OpenGL
119  * directly, and  is queried by draw code that then decides if any
120  * real state changes are required given the configuration of data
121  * within an RMprimitive.
122  *
123  * Revision 1.13  2002/04/30 19:32:47  wes
124  * Updated copyright dates.
125  *
126  * Revision 1.12  2001/10/15 02:35:56  wes
127  * Vectors, bitmaps and sprites will never be subject to lighting
128  * when fogging is enabled. This was an error in the last checkin -
129  * OpenGL fogging is not dependant upon lighting.
130  *
131  * Revision 1.11  2001/10/15 01:32:19  wes
132  * Minor mods to support 4-byte alignment of framebuffer reads on Win32.
133  * Problem showed up in demo "pdb."
134  *
135  * Revision 1.9  2001/07/15 17:19:19  wes
136  * Added temporary code to routine that builds OpenGL display lists for
137  * RMprimitive objects. The new code will remove an old OpenGL display
138  * list before creating a new one.
139  *
140  * Revision 1.8  2001/06/03 20:48:45  wes
141  * No significant differences.
142  *
143  * Revision 1.7  2001/03/31 17:12:39  wes
144  * v1.4.0-alpha-2 checkin.
145  *
146  * Revision 1.6  2000/12/03 22:33:55  wes
147  * Mods for thread-safety.
148  *
149  * Revision 1.5  2000/10/03 11:40:50  wes
150  * Contributions from jdb - prototype and compile warning cleanups.
151  *
152  * Revision 1.4  2000/08/31 02:11:06  wes
153  * Tweaks to conditional compile code for local wrappers for
154  * glPush/PopAttib.
155  *
156  * Revision 1.3  2000/08/23 23:24:21  wes
157  * DO_LISTS define moved from rmogl.c to rmprivat.h. All display
158  * list code removed from rmBitmap (will be reinserted later).
159  *
160  * Revision 1.2  2000/04/20 16:29:47  wes
161  * Documentation additions/enhancements, some code rearragement.
162  *
163  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
164  * OpenRM 1.2 Checkin
165  *
166  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
167  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
168  *
169  */
170 
171 /* documentation of public routines is incomplete in this file. */
172 
173 
174 #include <rm/rm.h>
175 #include "rmprivat.h"
176 
177 /* PRIVATE */
178 RMenum
private_rmColorsEqual(RMcolor4D * c1,RMcolor4D * c2)179 private_rmColorsEqual(RMcolor4D *c1,
180 		      RMcolor4D *c2)
181 {
182 #define CEPS 0.001
183     float d1, d2, d3, d4;
184 
185     d1 = fabs(c1->r - c2->r);
186     d2 = fabs(c1->g - c2->g);
187     d3 = fabs(c1->b - c2->b);
188     d4 = fabs(c1->a - c2->a);
189 
190     if ((d1 > CEPS) || (d2 > CEPS) || (d3 > CEPS) || (d4 > CEPS))
191 	return RM_FALSE;
192     else
193 	return RM_TRUE;
194 }
195 
196 /* PRIVATE */
197 void
private_rmSetBackBuffer(RMpipe * p)198 private_rmSetBackBuffer (RMpipe *p)
199 {
200     RMenum cf = rmPipeGetChannelFormat(p);
201 
202     if ((cf == RM_MONO_CHANNEL) ||
203 	(cf == RM_REDBLUE_STEREO_CHANNEL) ||
204 	(cf == RM_BLUERED_STEREO_CHANNEL) ||
205 	(cf == RM_MBUF_STEREO_CHANNEL))
206 	glDrawBuffer(GL_BACK);
207 
208     else
209 	glDrawBuffer(GL_FRONT);
210 }
211 
212 
213 /* PRIVATE */
214 void
private_rmReadBytePixels(unsigned char * pixelbuf,int w,int h,int ncomponents,GLenum pixel_component,int bytesPerScanline)215 private_rmReadBytePixels (unsigned char *pixelbuf,
216 			  int w,
217 			  int h,
218 			  int ncomponents,
219 			  GLenum pixel_component,
220 			  int bytesPerScanline)
221 {
222     int j, offset = 0;
223     int nbytes_per_component;
224 
225     /* the following line of code reads the entire framebuffer.  it's
226        flipped in Y, so the loop below reads a row at a time. */
227 
228     nbytes_per_component = ncomponents * sizeof(unsigned char);
229 
230     offset = (h-1) * bytesPerScanline;
231 
232     for (j = 0; j < h; j++, offset -= (bytesPerScanline))
233     {
234 	/* grab a row... */
235 	glReadPixels(0, j, w, 1, pixel_component, GL_UNSIGNED_BYTE, (pixelbuf + offset));
236     }
237 }
238 
239 
240 /* PRIVATE  */
241 void
private_rmReadFloatPixels(float * pixelbuf,int w,int h,int ncomponents,GLenum pixel_component)242 private_rmReadFloatPixels (float *pixelbuf,
243 			   int w,
244 			   int h,
245 			   int ncomponents,
246 			   GLenum pixel_component)
247 {
248     int j, offset = 0;
249 
250     /* the following line of code reads the entire framebuffer.  it's
251        flipped in Y, so the loop below reads a row at a time. */
252 
253     offset = (w * h * ncomponents) - (w * ncomponents);
254     for (j=0; j < h; j++, offset -= (ncomponents * w))
255     {
256 	/* grab a row... */
257 	glReadPixels(0, j, w, 1, pixel_component, GL_FLOAT, (pixelbuf + offset));
258     }
259 }
260 
261 /* PRIVATE */
262 int
private_rmGLPushAttrib(RMpipe * p,const RMnode * r,GLuint imask)263 private_rmGLPushAttrib (RMpipe *p, const RMnode *r, GLuint imask)
264 {
265     /*
266      * returns 0 on success, non-zero when there's an error
267      */
268     int rval = 0;
269 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
270     /* debug */
271     int ival;
272 
273     glGetIntegerv(GL_ATTRIB_STACK_DEPTH, &ival);
274     rval = ival;
275 
276     if (r != NULL)
277 	fprintf(stderr, " before push attrib stack depth %d, <%s> \n", ival, r->object_info.name);
278     else
279 	fprintf(stderr, " before push attrib stack depth %d <no node> \n", ival);
280 #endif
281 
282     glPushAttrib(imask);
283 
284     p->localMaskStack[p->localMaskStackTop] = imask;
285     p->localMaskStackTop++;
286     if (p->localMaskStackTop > MAX_MASK_STACK_DEPTH)
287 	rmError(" private_rmGLPushAttrib mask stack overflow! ");
288 
289 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
290     rval |= rmGLGetError("after glPushAttrib()");
291 #endif
292 
293     return rval;
294 }
295 
296 /* PRIVATE */
297 int
private_rmGLPopAttrib(RMpipe * p,RMstate * s,RMstateCache * rsc)298 private_rmGLPopAttrib (RMpipe *p, RMstate *s, RMstateCache *rsc)
299 {
300     int rval = 0;
301 
302     glPopAttrib();
303 
304 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
305     rval = glGetError();
306 
307     if (rval != 0)
308     {
309 	char buf[128];
310 
311 	sprintf(buf, "%s OpenGL error code (hex): 0x%04x ", s, rstat);
312 	rmWarning(buf);
313     }
314 #endif
315 
316 
317     if (p->localMaskStack[p->localMaskStackTop] & (GL_ENABLE_BIT))
318     {
319 	/* synchronize lighting state */
320 	rsc->lightingActive = s->lightingActive; /* ?? */
321 	rsc->colorMaterialActive = s->colorMaterialActive; /* ?? */
322 
323 	/* todo: if rsc->colorMaterialActive is RM_TRUE, then the current
324 	 OpenGL color might not be the same as s->unlit_color. */
325     }
326     p->localMaskStackTop--;
327 
328     if (p->localMaskStackTop < 0)
329     {
330 	rmError(" private_rmGLPushAttrib mask stack underflow! Please file a bug report.");
331 	p->localMaskStackTop = 0; /* to keep from blowing up */
332     }
333 
334 #if 0
335 
336     /* debug code used to coerce correct lighting state during
337      state tracking debugging. Keeping it around for sentimental reasons */
338     {
339 	int oglLightingEnabled;
340 
341 	glFinish();
342 
343 	oglLightingEnabled = glIsEnabled(GL_LIGHTING);
344 
345 	if (oglLightingEnabled == GL_TRUE)
346 	{
347 	    rsc->lightingActive = s->lightingActive = RM_TRUE;
348 	}
349 	else
350 	{
351 	    rsc->lightingActive = s->lightingActive = RM_FALSE;
352 	}
353     }
354 #endif
355 
356     /*
357      * The following code doesn't always give reliable results: it
358      * sometimes gives a false positive error indication.
359      */
360 #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK)
361     {
362 	RMcolor4D c;
363 	int rD, gD, bD, aD;
364 	glGetFloatv(GL_CURRENT_COLOR, (GLfloat *)&c);
365 
366 	rD = (int)((s->unlit_color.r - c.r)*255.0F);
367 	gD = (int)((s->unlit_color.g - c.g)*255.0F);
368 	bD = (int)((s->unlit_color.b - c.b)*255.0F);
369 	aD = (int)((s->unlit_color.a - c.a)*255.0F);
370 
371 	if ((aD != 0) || (rD != 0) || (gD != 0) || (bD != 0))
372 	    rmWarning("private_rmGLPopAttrib - OpenGL current color != RMstate current color");
373 
374     }
375 #endif
376 
377     return rval;
378 }
379 
380 /*
381  * display list routines
382  *
383  * from inside each RMprimitive draw routine, we potentially call two
384  * routines. the first one will either invoke a display list that's
385  * already built, or will prepare to build one. at the end of the
386  * RMprimitive draw routine, we call a routine that finalizes the
387  * display list.
388  */
389 
390 /* PRIVATE  */
391 int
private_rmPrimitiveDisplayListBegin(RMpipe * pipe,RMprimitive * p)392 private_rmPrimitiveDisplayListBegin (RMpipe *pipe,
393 				     RMprimitive *p)
394 {
395     /*
396      * return values:
397      * 0 = this routine invoked a display list, caller does not need
398      *     to execute draw code
399      * 1 = caller needs to execute draw code as part of th<
400      *     display list build process. the caller must also call
401      *     private_rmPrimitiveDisplayListEnd() to cause the display list
402      *     to be finished.
403      * 2 = caller needs to execute draw code, we're not building a
404      *     display list
405      * -1 = an error of some type.
406      */
407 
408     int    stat = 2;
409     GLuint newlist = 0;
410 
411     RMcacheKey primKey, contextCacheKey;
412     int compListIndx;
413 
414     /*
415      * check to see if display listing is disabled for this primitive.
416      * if so, return "2" so that the caller will then invoke immediate
417      * mode draw code.
418      */
419     if ((pipe->displayListEnableBool == RM_FALSE) ||
420 	(private_rmPrimitiveGetDisplayListEnable(p) == RM_FALSE))
421 	return stat;
422 
423 #if DO_LISTS
424     primKey = private_rmPrimitiveGetCacheKey(p);
425     compListIndx = p->compListIndx;
426 
427     if (compListIndx >= pipe->contextCache->numPrimCacheKeys)
428     {
429 	int newSize;
430 	int oldSize = pipe->contextCache->numPrimCacheKeys;
431 	int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
432 	int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
433 
434 	newSize = numNewPages * NUM_ITEMS_PER_PAGE;
435 
436 	pipe->contextCache->primCacheKeys = (RMcacheKey *)realloc(pipe->contextCache->primCacheKeys, newSize * sizeof(RMcacheKey));
437 
438 	/* initialize new stuff to -1 */
439 
440 	memset((void *)(pipe->contextCache->primCacheKeys + oldSize),
441 	       0xFF, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(RMcacheKey));
442 
443 	pipe->contextCache->numPrimCacheKeys = newSize;
444 
445 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
446 	printf("private_rmPrimitiveDisplayListBegin() - reallocating contextCache->primCacheKeys; oldSize = %d, newSize = %d \n", oldSize, newSize);
447 #endif
448     }
449 
450     contextCacheKey = pipe->contextCache->primCacheKeys[compListIndx];
451 
452     /*
453      * compare primKey and contextCacheKey.
454      * if they are equal, the OpenGL display list is up to date
455      * wrt the contents of the RMprimitive. In this case, we can just
456      * invoke the display list and return.
457      *
458      * if not, then first we check to see if the old display list
459      * handle is a valid list, and if so, delete it. then, we begin
460      * construction of an OpenGL display list.
461      *
462      */
463 
464     if (primKey == contextCacheKey) /* call the display list */
465     {
466 	GLuint list;
467 
468 	/* error check */
469 	if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs)
470 	    /* this should never happen - the realloc should occur
471 	       before this branch of code is executed */
472 	    rmError("private_rmPrimitiveDisplayListBegin() error - the size of the primDisplayListIDs buffer is too small. \n");
473 	/** end debug code */
474 
475 	list = pipe->contextCache->primDisplayListIDs[compListIndx];
476 
477 #if 0
478 	fprintf(stderr," calling list %d \n", list);
479 	fflush(stderr);
480 #endif
481 /*	glCallList(list); */
482 
483 	private_glCallList(pipe, p, list);
484 
485 	stat = 0;
486     }
487     else
488     {
489 	/* error check */
490 	if (compListIndx >= pipe->contextCache->numPrimCacheKeys)
491 	    /* this should  never happen because we should have performed
492 	       any realloc before this chunk of code is executed. */
493 	    rmError("private_rmPrimitiveDisplayListBegin() error - the size of the primCacheKeys buffer is too small. \n");
494 	/** end debug code */
495 
496 	pipe->contextCache->primCacheKeys[compListIndx] = primKey;
497 
498 	/*
499 	 * 7/7/01 w.bethel
500 	 *
501 	 * by deleting the list here, we are inserting work in the
502 	 * critical path of rendering. this may not be a good idea
503 	 * in all circumstances.
504 	 *
505 	 * the way the component manager works, an rmPrimitiveDelete will
506 	 * move the newly deleted RMprimitive to the head of the alloc
507 	 * list, thereby increasing the liklihood that any old display
508 	 * list will be deleted the next time the RMprimitive is drawn.
509 	 * an alternate design strategy would be to construct a "to delete"
510 	 * list inside rmPrimitiveDelete which is later executed
511 	 * via an application-invoked synchronization function.
512 	 */
513 
514 	if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs)
515 	{
516 	    int newSize;
517 	    int oldSize = pipe->contextCache->numPrimDisplayListIDs;
518 	    int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
519 	    int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
520 
521 	    newSize = numNewPages * NUM_ITEMS_PER_PAGE;
522 
523 	    pipe->contextCache->primDisplayListIDs = (GLuint *)realloc(pipe->contextCache->primDisplayListIDs, newSize * sizeof(GLuint));
524 
525 	    /* initialize new stuff to -1 */
526 
527 	    memset((void *)(pipe->contextCache->primDisplayListIDs + oldSize),
528 		   0xFF, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(GLuint));
529 
530 	    pipe->contextCache->numPrimDisplayListIDs = newSize;
531 
532 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
533 	    printf("private_rmPrimitiveDisplayListBegin() - reallocating the primDisplayListIDs buffer, oldsize = %d, newSize = %d. \n", oldSize, newSize);
534 #endif
535 	}
536 
537 
538 	if (glIsList(pipe->contextCache->primDisplayListIDs[compListIndx]))
539 	    glDeleteLists(pipe->contextCache->primDisplayListIDs[compListIndx],1);
540 
541 	pipe->contextCache->primDisplayListIDs[compListIndx] = newlist = glGenLists(1);
542 	if (newlist != 0)
543 	{
544 	    glNewList(newlist, GL_COMPILE);
545 	    stat = 1;
546 	}
547 	else
548 	    stat = -1;		/* error */
549     }
550 #endif
551     return(stat);
552 }
553 
554 
555 /* PRIVATE  */
556 int
private_rmPrimitiveDisplayListEnd(RMpipe * pipe,RMprimitive * p,int needFinalize)557 private_rmPrimitiveDisplayListEnd (RMpipe *pipe,
558 				   RMprimitive *p,
559 				   int needFinalize)
560 {
561     /*
562      * when needFinalize != 0, we will assume that we need to
563      * conclude construction of a display list.
564      *
565      * needFinalize might be non-zero when a primitive executes
566      * it's own draw code rather than using a display list for
567      * app-specific reasons, and we don't want to conclude construction
568      * of a display list.
569      */
570     if (needFinalize == 1)
571     {
572 	GLuint list;
573 	int compListIndx = p->compListIndx;
574 
575 	/* 8/29/02 debug code */
576 	if (compListIndx >= pipe->contextCache->numPrimDisplayListIDs)
577 	    /* this should never happen - we should have performed the
578 	       realloc before this point */
579 	    printf(" private_rmPrimitiveDisplayListEnd() error - the size of the primDisplayListIDs buffer is too small. compListIndx = %d, numPrimDisplayListIDs = %d.\n",compListIndx, pipe->contextCache->numPrimDisplayListIDs);
580 
581 	list = pipe->contextCache->primDisplayListIDs[compListIndx];
582 
583 	glEndList();
584 #if 0
585 	fprintf(stderr," calling list %d \n", list);
586 	fflush(stderr);
587 	glCallList(list);
588 #endif
589 	private_glCallList(pipe, p, list);
590     }
591     return(1);
592 }
593 
594 /*
595  * PRIVATE: delete an OpenGL texture from a specific OpenGL context
596  */
597 void
private_rmOGLTextureDelete(RMtexture * toDelete,RMpipe * p)598 private_rmOGLTextureDelete(RMtexture *toDelete,
599 			   RMpipe *p)
600 {
601     int compListIndx;
602     GLuint *id;
603 
604     compListIndx = toDelete->compListIndx;
605 
606     if (compListIndx >= p->contextCache->numTextureIDs)
607     {
608 #if 0
609 	/*
610 	 * a realloc at this point is a quasi-error condition. "Quasi" because
611 	 * this code can be invoked on a texture that doesn't exist. This
612 	 * happens occasionally from private_rmManageTextureState() in
613 	 * rmframe.c.
614 	 */
615 	int newSize;
616 	int oldSize = p->contextCache->numTextureIDs;
617 	int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
618 	int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
619 
620 	newSize = numNewPages * NUM_ITEMS_PER_PAGE;
621 
622 	p->contextCache->textureIDs = (GLuint *)realloc(p->contextCache->textureIDs, newSize * sizeof(GLuint));
623 
624 	/* initialize new stuff to -1 */
625 	memset((void *)(p->contextCache->textureIDs + oldSize),
626 	       0x00, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(GLuint));
627 
628 	p->contextCache->numTextureIDs = newSize;
629 
630 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
631 	printf("private_rmOGLTextureDelete() - reallocating contextCache->textureIDs; oldSize = %d, newSize = %d \n", oldSize, newSize);
632 #endif
633 
634 #endif
635     }
636     else
637     {
638 	/* don't do a glIsTexture for something we know will obviously
639 	   not be loaded. */
640 
641 	id = p->contextCache->textureIDs;
642 	if (glIsTexture(*(id+compListIndx)) == GL_TRUE)
643 	    glDeleteTextures(1, id+compListIndx);
644 
645 	*(id+compListIndx) = 0;
646     }
647 /*    *(id+compListIndx) = 0; */
648 }
649 
650 void
private_lightingStateManip(RMprimitive * p,RMstate * s,RMstateCache * rsc,RMenum forceNormals)651 private_lightingStateManip(RMprimitive *p,
652 			   RMstate *s,
653 			   RMstateCache *rsc,
654 			   RMenum forceNormals)
655 {
656     /*
657      * 5/11/02
658      * lazy OpenGL state updates:
659      * 1. if lighting is enabled and we don't want it, turn if off
660      * 2. if lighting is off and we want it, turn it on.
661      *
662      * Assumption:  that *any* normals stored in the primitive implies
663      * that lighting should be enabled; absence of normals implies
664      * lighting should be disabled.
665      *
666      * control over each individual light source is controlled at the
667      * RMnode level; we are controlling whether or not lighting is
668      * active here, not the attribs of a specific light source.
669      *
670      * it is assumed we want lighting if:
671      * the RMprimitive has normal data OR forceNormals==RM_TRUE
672      *
673      */
674 
675     int nnormals = 0;
676 
677     /*  it would be nice to find a faster way to check for the presence
678      of normal data in the RMprimitive rather than have to poke around
679      in the blob pile. the easiest way would be to set a bit in the
680      RMprimitive when normals data is loaded up. */
681     private_rmGetBlobData(BLOB_NORMAL_INDEX, p, NULL, &nnormals, NULL, NULL);
682 
683     if (forceNormals == RM_TRUE)
684 	nnormals++;		/* make it non-zero */
685 
686     /* if lighting is off and we want it, turn it on */
687     if ((nnormals != 0) && (rsc->lightingActive == RM_FALSE))
688     {
689 	glEnable(GL_LIGHTING);
690 	s->lightingActive = RM_TRUE;
691 	rsc->lightingActive = RM_TRUE;
692     }
693 
694     /* if lighting is enabled and we don't want it, turn if off */
695     if ( ((s->shademodel == RM_SHADER_NOLIGHT) || (nnormals == 0)) &&
696 	 (rsc->lightingActive == RM_TRUE) )
697     {
698 	rsc->lightingActive = RM_FALSE;
699 	s->lightingActive = RM_FALSE;
700 	glDisable(GL_LIGHTING);
701     }
702 
703 #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK)
704     /*
705      * debug code to read current lighting state from OpenGL and
706      * compare it to the values in the state cache. You don't want
707      * this test enabled in production code because it will slow you
708      * down. Enable this code for debugging if you suspect lighting
709      * state problems.
710      */
711     {
712 	int oglLightingEnabled;
713 
714 	glFinish();
715 
716 	oglLightingEnabled = glIsEnabled(GL_LIGHTING);
717 
718 	if ((oglLightingEnabled == GL_TRUE) && (rsc->lightingActive != RM_TRUE))
719 	    rmError("private_lightingStateManip error: OpenGL lighting state != rm state");
720 	if ((oglLightingEnabled == GL_FALSE) && (rsc->lightingActive != RM_FALSE))
721 	    rmError("private_lightingStateManip error: OpenGL lighting state != rm state");
722     }
723 #endif
724 
725 }
726 
727 void
private_colorMaterialStateManip(RMprimitive * p,RMstate * s,RMstateCache * rsc)728 private_colorMaterialStateManip(RMprimitive *p,
729 				RMstate *s,
730 				RMstateCache *rsc)
731 {
732     /*
733      * 5/14/02
734      * lazy OpenGL state updates:
735      * 1. if colormaterial is enabled and we don't want it, turn if off
736      * 2. if colormaterial is off and we want it, turn it on.
737      *
738      * Assumption:  that *any* colors stored in the primitive requires
739      * use of glColorMaterial.
740      */
741 
742     int ncolors;
743 
744     /*  it would be nice to find a faster way to check for the presence
745      of color data in the RMprimitive rather than have to poke around
746      in the blob pile. the easiest way would be to set a bit in the
747      RMprimitive when color data is loaded up. */
748     private_rmGetBlobData(BLOB_COLOR_INDEX, p, NULL, &ncolors, NULL, NULL);
749 
750 #if (DEBUG_LEVEL & DEBUG_RSTATECACHECHECK)
751     /* debug code */
752     {
753 	int oglCMEnabled = glIsEnabled(GL_COLOR_MATERIAL);
754 
755 	if ((oglCMEnabled == GL_TRUE) && (rsc->colorMaterialActive != RM_TRUE))
756 	    rmError("private_colorMaterialStateManipNew error: OpenGL colormaterial state ON, != rm state = OFF");
757 	if ((oglCMEnabled == GL_FALSE) && (rsc->colorMaterialActive != RM_FALSE))
758 	    rmError("private_colorMaterialStateManipNew error: OpenGL colormaterial state OFF != rm state ON");
759     }
760 #endif
761 
762     /* if colormaterial is off and we want it, turn it on */
763     if ((ncolors != 0) && (rsc->colorMaterialActive == RM_FALSE))
764 	private_rmColorMaterial(s, rsc, RM_TRUE);
765 
766     /* if colormaterial is enabled and we don't want it, turn if off */
767     if (ncolors == 0)
768     {
769 	if (rsc->colorMaterialActive == RM_TRUE)
770 	    private_rmColorMaterial(s, rsc, RM_FALSE);
771     }
772 }
773 
774 void
private_rmColorMaterial(RMstate * s,RMstateCache * rsc,RMenum newVal)775 private_rmColorMaterial(RMstate *s,
776 			RMstateCache *rsc,
777 			RMenum newVal)
778 {
779     if (newVal == RM_TRUE)
780     {
781 	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
782 	glEnable(GL_COLOR_MATERIAL);
783 	rsc->colorMaterialActive = RM_TRUE;
784     }
785     else
786     {
787 	rsc->colorMaterialActive = RM_FALSE;
788 	glColor4fv((GLfloat *)&(s->unlit_color));
789 	glDisable(GL_COLOR_MATERIAL);
790     }
791 }
792 
793 void
private_textureStateManip(RMprimitive * p,RMstate * s,RMstateCache * rsc)794 private_textureStateManip(RMprimitive *p,
795 			  RMstate *s,
796 			  RMstateCache *rsc)
797 {
798     int ntc;
799     private_rmGetBlobData(BLOB_TC_INDEX, p, NULL, &ntc, NULL, NULL);
800 
801     /* if lighting is off and we want it, turn it on */
802     if ((ntc != 0) && (rsc->texturingActive == RM_FALSE))
803     {
804 	glEnable(s->texture_mode);
805 	rsc->texturingActive = RM_TRUE;
806     }
807 
808     /* if lighting is enabled and we don't want it, turn if off */
809     if ( ((ntc == 0)) && (rsc->texturingActive == RM_TRUE) )
810     {
811 	rsc->texturingActive = RM_FALSE;
812 	glDisable(s->texture_mode);
813     }
814 }
815 
816 /*
817  * PRIVATE: private_glCallList(). this is a wrapper function for
818  * glCallList. For CR applications, we issue a GL_OBJECT_BBOX_CR
819  * call, then call the list, then turn off the GL_OBJECT_BBOX_CR.
820  */
821 void
private_glCallList(RMpipe * pipe,RMprimitive * prim,GLuint listIndx)822 private_glCallList(RMpipe *pipe,
823 		   RMprimitive *prim,
824 		   GLuint listIndx)
825 {
826 #ifdef RM_CR
827     RMvertex3D bmin, bmax;
828     RMenum useBox;
829 
830     useBox = rmPrimitiveGetBoundingBox(prim,&bmin,&bmax);
831 
832     /* check for null crStuff - this can happen when the app doesn't call
833        rmPipeNew() using RM_PIPE_CR, but OpenRM is built using -DRM_CR */
834 #if 1
835     if ((pipe->crStuff != NULL) && (useBox == RM_CHILL))
836     {
837 	float fvec[6];
838 
839 	fvec[0] = bmin.x;
840 	fvec[1] = bmin.y;
841 	fvec[2] = bmin.z;
842 	fvec[3] = bmax.x;
843 	fvec[4] = bmax.y;
844 	fvec[5] = bmax.z;
845 	pipe->crStuff->glChromiumParametervCR(GL_OBJECT_BBOX_CR, GL_FLOAT, 6, (void *)fvec);
846 
847 #if (DEBUG_LEVEL & DEBUG_CR_BBOX)
848 	fprintf(stderr, "CR_BBOX: PE %d setting GL_OBJECT_BBOX_CR to (%g, %g, %g) - (%g, %g, %g) \n", pipe->myRank, fvec[0], fvec[1], fvec[2], fvec[3], fvec[4], fvec[5]);
849 	fflush(stderr);
850 #endif
851     }
852 #endif
853 
854 #endif
855 
856     glCallList(listIndx);
857 
858 #ifdef RM_CR
859     if ((pipe->crStuff != NULL) && (useBox == RM_CHILL))
860     {
861 	pipe->crStuff->glChromiumParametervCR(GL_DEFAULT_BBOX_CR, GL_FLOAT, 0, NULL);
862 #if (DEBUG_LEVEL & DEBUG_CR_BBOX)
863 	fprintf(stderr, "CR_BBOX: PE %d setting GL_DEFAULT_BBOX_CR \n", pipe->myRank);
864 	fflush(stderr);
865 #endif
866     }
867 #else
868     /* foil compiler warnings */
869     pipe = NULL;
870     prim = NULL;
871 #endif
872 }
873 
874 void *
private_rmGLGetProcAddr(const char * funcName)875 private_rmGLGetProcAddr(const char *funcName)
876 {
877 #ifdef RM_X
878     void (GLAPIENTRY *fptr)() = NULL;
879     GLubyte *newFName = (GLubyte *)malloc(sizeof(GLubyte)*(strlen(funcName)+1));
880     memcpy((void *)newFName, (void *)funcName, strlen(funcName));
881     newFName[strlen(funcName)] = '\0';
882 
883     fptr = glXGetProcAddressARB(newFName);
884     if (fptr == NULL)
885     {
886 	char buf[256];
887 	sprintf(buf, "private_rmGLGetProcAddress error: unable to find the routine named %s ", funcName);
888 	rmError(buf);
889     }
890     return fptr;
891 #endif
892 #ifdef RM_WIN
893     PROC func;
894 
895     func = wglGetProcAddress(funcName);
896     if (func == NULL)
897     {
898 	char buf[256];
899 	sprintf(buf, "private_rmGLGetProcAddress error: unable to find the routine named %s ", funcName);
900 	rmError(buf);
901     }
902 
903     return (void *)(func);
904 #endif
905 }
906 
907 /* PRIVATE */
908 int
private_glStateCheck(RMstate * s)909 private_glStateCheck(RMstate *s)
910 {
911     int rstat = 0; 		/* 0=OK, non-zero means error */
912 #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK)
913     /*
914      * Compare the contents of an RMstate with the current OpenGL state
915      * and report any differences. This is a debug routine that should
916      * not be used in production because it will slow things way down.
917      */
918 
919     /* shade model */
920     {
921 	GLint oglShadeModel;
922 	glGetIntegerv(GL_SHADE_MODEL, &oglShadeModel);
923 
924 	switch (oglShadeModel)
925         {
926 	case GL_SMOOTH:
927 	    if (s->shademodel != RM_SHADER_SMOOTH)
928 	    {
929 		rmError("private_glStateCheck - OpenGL shader == GL_SMOOTH, RM shader != RM_SHADER_SMOOTH ");
930 		rstat = 1;
931 	    }
932 	    break;
933 
934 	case GL_FLAT:
935 	    if ((s->shademodel != RM_SHADER_FLAT) && (s->shademodel != RM_SHADER_NOLIGHT))
936 	    {
937 		rmError("private_glStateCheck - OpenGL shader == GL_FLAT, RM shader != RM_SHADER_SMOOTH or RM_SHADER_NOLIGHT ");
938 		rstat = 1;
939 	    }
940 	    break;
941 	}
942     }
943 
944     /* lighting */
945     {
946 	GLint oglLightingEnabled;
947 	glGetIntegerv(GL_LIGHTING, &oglLightingEnabled);
948 
949 	if ((oglLightingEnabled == 1) && (s->lightingActive != RM_TRUE))
950 	{
951 	    rmError("private_glStateCheck - OpenGL lighting is enabled, but RM lighting is not. ");
952 	    rstat = 1;
953 	}
954 	else if ((oglLightingEnabled == 0) && (s->lightingActive == RM_TRUE))
955 	{
956 	    rmError("private_glStateCheck - OpenGL lighting is NOT enabled, but RM lighting is enabled. ");
957 	    rstat = 1;
958 	}
959     }
960 
961     /* color material */
962     {
963 	GLint oglColorMaterialEnabled;
964 	glGetIntegerv(GL_COLOR_MATERIAL, &oglColorMaterialEnabled);
965 
966 	if ((oglColorMaterialEnabled == 1) && (s->colorMaterialActive != RM_TRUE))
967 	{
968 	    rmError("private_glStateCheck - OpenGL COLOR_MATERIAL is enabled, but RM COLOR_MATERIAL is not. ");
969 	    rstat = 1;
970 	}
971 	else if ((oglColorMaterialEnabled == 0) && (s->colorMaterialActive == RM_TRUE))
972 	{
973 	    rmError("private_glStateCheck - OpenGL COLOR_MATERIAL is NOT enabled, but RM COLOR_MATERIAL is enabled. ");
974 	    rstat = 1;
975 	}
976     }
977 
978     /* current color */
979     {
980 	GLfloat c[4];
981 	RMcolor4D currentGLColor;
982 
983 	glGetFloatv(GL_CURRENT_COLOR, c);
984 	currentGLColor.r = c[0];
985 	currentGLColor.g = c[1];
986 	currentGLColor.b = c[2];
987 	currentGLColor.a = c[3];
988 
989 	if (private_rmColorsEqual(&currentGLColor, &(s->unlit_color)) == RM_FALSE)
990 	    rstat = 0;
991     }
992 
993 
994     if (rstat == 0)
995 	rmNotice("private_glStateCheck - OK. ");
996     else
997 	rmNotice("private_glStateCheck - not OK. ");
998 
999 #else
1000     s = NULL; 			/* foil compiler warning */
1001 #endif
1002 
1003     return rstat;
1004 }
1005 
1006 /* EOF */
1007