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(¤tGLColor, &(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