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: rmframe.c,v 1.23 2005/06/26 19:01:07 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.23 $
29  * $Log: rmframe.c,v $
30  * Revision 1.23  2005/06/26 19:01:07  wes
31  * Use new routines for push/pop the OpenGL attrib stack. Streamline
32  * operations so that the same calls to update scene parms, etc. are made
33  * here as in the multi-stage draw code.
34  *
35  * Revision 1.22  2005/06/09 00:45:29  wes
36  * More compiler warning fixes turned up by Windows build.
37  *
38  * Revision 1.21  2005/06/06 02:04:29  wes
39  * Lots of small additions to clean up compiler warnings.
40  *
41  * Revision 1.20  2005/05/28 16:25:05  wes
42  * Added early termination tests based upon status of the pick enable
43  * attribute of RMnode's when doing picks.
44  *
45  * Revision 1.19  2005/05/06 16:33:13  wes
46  * Add texture state/env settings for 1D textures.
47  *
48  * Revision 1.18  2005/04/27 03:33:39  wes
49  * Multitexturing support.
50  *
51  * Revision 1.17  2005/02/27 19:34:04  wes
52  * Added support for application supplied texture object IDs and display lists.
53  *
54  * Revision 1.16  2005/02/24 16:26:51  wes
55  * Fixed problem whereby the red channel in red/blue anaglyph wasn't
56  * being rendered in the RM_PIPE_SERIAL processing mode.
57  *
58  * Revision 1.15  2005/02/24 16:17:25  wes
59  * Added support for fbClears to be set at the RMpipe level. Apps can
60  * still set them at the RMnode level if desired for fine-grained control.
61  *
62  * Revision 1.14  2005/02/19 16:28:54  wes
63  * Distro sync and consolidation.
64  * Fixes for a number of state tracking buglets.
65  *
66  * Revision 1.13  2005/01/23 17:08:25  wes
67  * Copyright updated to 2005.
68  * Updates to support access and use of extensions; multitexturing on all
69  * platforms, use of 3d texture extension to realize implementation of
70  * volume rendering and related functions on Windows platforms.
71  *
72  * Revision 1.12  2004/09/28 00:48:57  wes
73  * Added render state cache as a parameter to routines that may modify
74  * lighting state to fix a lighting state tracking problem.
75  *
76  * Revision 1.11  2004/06/22 05:01:58  wes
77  * Minor tweaks to support consistent state tracking. These changes
78  * were made as a result to changes in the main RMSG tree during a
79  * big PS bug fixing expedition.
80  *
81  * Revision 1.10  2004/03/27 17:14:01  wes
82  * Remove gratuitous glColor4fv(unlitColor) inside updateSceneParms
83  *
84  * Revision 1.9  2004/03/10 01:46:01  wes
85  * Enabled activation of OpenGL's light attenuation attributes. They were
86  * already in RM as scene parms, we just had to enable them in OpenGL.
87  *
88  * Revision 1.8  2004/01/16 16:56:02  wes
89  *
90  * Rearranged calls within rendering routines so that:
91  * (1) the time synchronization for constant-rate rendering happens after
92  * the actual rendering, but right before SwapBuffers;
93  * (2) the user-assignable routines for grabbing frambuffer pixels are
94  * relocated to after the SwapBuffers - they were located before in
95  * the previous version.
96  *
97  * These changes are expected to have the following benefits:
98  * (1) frame sync is more stable when associated with SwapBuffers rather
99  * than having it placed immediately before when rendering starts;
100  * (2) We have removed an embedded glFinish() call; SwapBuffers always
101  * implies a glFlush(), and in some implementations, also implies
102  * a glFinish(). The oddball here in terms of execution behavior is
103  * software Mesa. The only detrimental impact will be on timing rendering
104  * as you must explicitly insert your own glFinish() to ensure that
105  * timings are accurate. We are looking at this for the next rev of OpenRM.
106  *
107  * Revision 1.7  2003/12/01 02:13:05  wes
108  * Additions to support constant frame-rate rendering on both Unix and Win32.
109  *
110  * Revision 1.6  2003/11/05 15:27:43  wes
111  * Added a gratuitous glFinish() inside rmFrame() to force a flush after
112  * the final swapbuffers. The addition is needed for accurate timing.
113  * There are probably some other glFinish'es sprinkled throughout the
114  * rendering code that can be removed (as per D. Leech at Sun Micro, who
115  * points out these additional glFinish()'s are probably not necessary
116  * and also have an adverse impact on performance).
117  *
118  * Revision 1.5  2003/07/23 13:32:28  wes
119  * Win32: problems with offscreen rendering appeared with new context
120  * initialization code sequence (1.5.0). Minor repairs needed to fix the bug.
121  *
122  * Revision 1.4  2003/04/12 21:00:53  wes
123  * Removed debug statements used during CR development.
124  *
125  * Revision 1.3  2003/02/14 00:17:01  wes
126  * Remove dead code.
127  *
128  * Revision 1.2  2003/02/02 02:07:15  wes
129  * Updated copyright to 2003.
130  *
131  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
132  * Manual rebuild of rm150 repository.
133  *
134  * Revision 1.32  2003/01/27 05:04:42  wes
135  * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR
136  * platforms w/o too much disruption to existing apps.
137  *
138  * Revision 1.31  2003/01/20 05:39:49  wes
139  * Rewrote texture state handling code.
140  *
141  * Revision 1.30  2003/01/16 22:21:17  wes
142  * Updated all source files to reflect new organization of header files:
143  * all header files formerly located in include/rmaux, include/rmi, include/rmv
144  * are now located in include/rm.
145  *
146  * Revision 1.29  2003/01/12 23:50:06  wes
147  * Minor adjustments to texturing environment controls to fix problems with
148  * the texture environment not being set correctly.
149  *
150  * Revision 1.28  2002/12/31 00:55:22  wes
151  *
152  * Various enhancements to support Chromium - achitecture-specific sections
153  * of RMpipe were cleaned up, etc.
154  *
155  * Revision 1.27  2002/12/04 14:50:33  wes
156  * Cleanup SGI compiles.
157  *
158  * Revision 1.26  2002/11/14 15:32:33  wes
159  * Rearrange texture calls during port to CR. No net changes in performance.
160  *
161  * Revision 1.25  2002/09/05 15:05:20  wes
162  * Fixed minor problems with realloc code for textures in the
163  * context cache.
164  *
165  * Revision 1.24  2002/08/29 22:20:32  wes
166  *
167  * Massive upgrade to accommodate dynamic object reallocation within
168  * the component manager, and within the context cache. Use the
169  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
170  * whenever a realloc occurs. With this upgrade, there are no
171  * OpenRM limits on the size of the scene graph. There will be external
172  * limits, such as the amount of RAM and the amount of space available
173  * to your OpenGL implementation.
174  *
175  * Revision 1.23  2002/06/30 21:40:32  wes
176  * Diddling with glColorMask in some of the older serial rendering code.
177  * No changes to multistage stuff.
178  *
179  * Revision 1.22  2002/06/17 00:57:41  wes
180  * Removed rmSubtreeFrame. Replaced internal calls to rmSubtreeFrame with
181  * rmFrame.
182  *
183  * Revision 1.21  2002/06/02 15:15:34  wes
184  * Added RMstateCache code to help eliminate the number of state changes
185  * made during the render traversal. The RMstateCache tracks
186  * the actual OpenGL rendering state w/o the need for querying OpenGL
187  * directly, and  is queried by draw code that then decides if any
188  * real state changes are required given the configuration of data
189  * within an RMprimitive.
190  *
191  * Revision 1.20  2002/04/30 19:31:39  wes
192  * Updated copyright dates.
193  *
194  * Revision 1.19  2001/10/15 01:32:19  wes
195  * Minor mods to support 4-byte alignment of framebuffer reads on Win32.
196  * Problem showed up in demo "pdb."
197  *
198  * Revision 1.17  2001/07/15 16:26:39  wes
199  *
200  * Added missing RM_CULL_NONE code to polygon cull modes scene parms update.
201  *
202  * Revision 1.16  2001/06/03 20:45:46  wes
203  * Removed unused vars to clean up compile warnings.
204  *
205  * Revision 1.15  2001/05/26 14:34:06  wes
206  * Added spotlight parameters, fixed bug in matrix multiplication order
207  * when doing picking.
208  *
209  * Revision 1.14  2001/03/31 17:12:38  wes
210  * v1.4.0-alpha-2 checkin.
211  *
212  * Revision 1.13  2000/12/05 03:04:20  wes
213  * Removed now-unnecessary glBindTexture(Glenum, 0) (that formerly
214  * disabled textures). We're relying on proper functioning of the
215  * OpenGL attribute stack to turn on and off texturing. This call
216  * was formerly necessary because texture downloads to OpenGL occured
217  * at the time RMtextures were assigned to RMnodes. Textures are now
218  * downloaded at render-time.
219  *
220  * Revision 1.12  2000/12/03 22:35:19  wes
221  * Mods for thread-safety.
222  *
223  * Revision 1.11  2000/08/30 02:06:41  wes
224  * Removed glLoadMatrixf()s from private_setClipPlanes(). These lines
225  * of OpenGL matrix stack manipulation were leftover from a long time ago.
226  *
227  * Revision 1.10  2000/08/28 01:36:53  wes
228  * Prototype mods to clean up compile errors.
229  *
230  * Revision 1.9  2000/08/23 23:26:28  wes
231  * Fixed a typo.
232  *
233  * Revision 1.8  2000/08/19 14:59:00  wes
234  * Added initMatrixStackBool to anaglyph and multibuffered stereo methods.
235  *
236  * Revision 1.7  2000/07/20 18:55:35  wes
237  * Removed glViewport() call from inside private_rmSubTreeFrame.
238  * Added calls to fully set the texture env. scene parms, if present
239  * inside private_updateSceneParms(). Thanks to Matt S. of VRCO
240  * for turning up the glViewport problem.
241  *
242  * Revision 1.6  2000/05/17 14:22:39  wes
243  * Fixed compile warnings on private_rmStateInit.
244  *
245  * Revision 1.5  2000/05/14 23:37:11  wes
246  * Added control via RMpipe attribute to how OpenGL matrix stack
247  * is initialized or used during rendering.
248  *
249  * Revision 1.4  2000/04/27 03:13:22  wes
250  * Minor state management adjustments.
251  *
252  * Revision 1.3  2000/04/20 16:29:47  wes
253  * Documentation additions/enhancements, some code rearragement.
254  *
255  * Revision 1.2  2000/02/29 23:43:53  wes
256  * Compile warning cleanups.
257  *
258  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
259  * OpenRM 1.2 Checkin
260  *
261  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
262  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
263  *
264  */
265 
266 
267 #include <rm/rm.h>
268 #include "rmprivat.h"
269 #include "rmprivatps.h"
270 #include "rmmultis.h"
271 
272 /* PRIVATE declarations */
273 static void render_tree (RMpipe *renderPipe, RMnode *r,int (*filterfunc)(RMnode *),void (*perobj_func)(const RMnode *), void (*perprim_func)(RMnode *, int), void (*precam_func)(void), int (*perchannel_func)(RMnode *), void (*perstate_func)(RMstate *, int), RMenum backgroundSceneEnable, GLenum rendermode, RMstate *parent_state, int *nthState, RMenum initMatrixStack, RMstateCache *rsc);
274 static void private_rmMonoRender(RMnode *t, RMpipe *p);
275 static void private_rmRedBlueRender(RMnode *t, RMpipe *p);
276 static void private_rmBlueRedRender(RMnode *t, RMpipe *p);
277 static void private_rmMbufStereoRender(RMnode *t, RMpipe *p);
278 static void private_rmPipeMultiStageSerial(RMnode *n, RMpipe *p);
279 static void private_rmPipeMultiStageParallel(RMnode *n, RMpipe *p);
280 static void private_rmPipeMultiStageViewParallel(RMnode *n, RMpipe *p);
281 
282 /*
283  * ----------------------------------------------------
284  * @Name rmFrame
285  @pstart
286  void rmFrame (RMpipe *drawOnPipe, RMnode *subTreeToDraw)
287  @pend
288 
289  @astart
290  RMpipe *drawOnPipe - (input) a handle to an RMpipe.
291  RMnode *subTreeToDraw - a handle to an RMnode (input).
292  @aend
293 
294  @dstart
295 
296  Render the scene graph starting at the subtree rooted at "inputNode"
297  on the "drawOnPipe."
298 
299  @dend
300  * ----------------------------------------------------
301  */
rmFrame(RMpipe * drawOnPipe,RMnode * subTreeToDraw)302 void rmFrame (RMpipe *drawOnPipe,
303 	      RMnode *subTreeToDraw)
304 {
305     int frameRate = rmPipeGetFrameRate(drawOnPipe);
306 
307     if (drawOnPipe == NULL)
308 	return;
309 
310     if (frameRate > 0)
311 	private_rmPipeFPSStart(drawOnPipe);
312 
313     /* invoke the rendering function for this pipe on a scene graph */
314     (drawOnPipe->channel_render_func)(subTreeToDraw, drawOnPipe);
315 
316     /* 11/1/03 added glFinish() for accurate timings.  */
317     /* glFinish(); */
318 
319     if (frameRate > 0)
320 	private_rmPipeFPSEnd(drawOnPipe);
321 
322     /* increment frame number */
323     drawOnPipe->frameNumber += 1;
324 }
325 
326 
327 /* PRIVATE */
328 void
private_rmSetChannelRenderFunc(RMpipe * p)329 private_rmSetChannelRenderFunc (RMpipe *p)
330 {
331     /*
332      * modified 1/21/2001 - the "channel renderfunc" is now a
333      * function of 1) the channel display format, and 2) the
334      * processing mode of the RMpipe.
335      */
336     RMenum pmode = rmPipeGetProcessingMode(p);
337 
338     if (pmode == RM_PIPE_SERIAL)
339     {
340 	switch (rmPipeGetChannelFormat(p))
341 	{
342 	case RM_MONO_CHANNEL:
343 	case RM_OFFSCREEN_MONO_CHANNEL:
344 	    p->channel_render_func = private_rmMonoRender;
345 	    break;
346 
347 	case RM_REDBLUE_STEREO_CHANNEL:
348 	case RM_OFFSCREEN_REDBLUE_STEREO_CHANNEL:
349 	    p->channel_render_func = private_rmRedBlueRender;
350 	    break;
351 
352 	case RM_BLUERED_STEREO_CHANNEL:
353 	case RM_OFFSCREEN_BLUERED_STEREO_CHANNEL:
354 	    p->channel_render_func = private_rmBlueRedRender;
355 	    break;
356 
357 	case RM_MBUF_STEREO_CHANNEL:
358 	    p->channel_render_func = private_rmMbufStereoRender;
359 	    break;
360 
361 	default:
362 	    rmError(" undefined channel format for rendering.");
363 	    exit(1);
364 	}
365     }
366     else if (pmode == RM_PIPE_MULTISTAGE)	/* processing mode != RM_PIPE_SERIAL */
367 	p->channel_render_func = private_rmPipeMultiStageSerial;
368     else if (pmode == RM_PIPE_MULTISTAGE_PARALLEL)
369 	p->channel_render_func = private_rmPipeMultiStageParallel;
370     else if (pmode == RM_PIPE_MULTISTAGE_VIEW_PARALLEL)
371 	p->channel_render_func = private_rmPipeMultiStageViewParallel;
372     else
373 	rmError("private_rmPipeSetChannelRenderFunc(): bogus processing mode. \n");
374 }
375 
376 
377 /* PRIVATE */
378 int
private_rmTrueFilterfunc(RMnode * r)379 private_rmTrueFilterfunc (RMnode *r)
380 {
381     r = NULL; 			/* foil compile warning */
382     return(1);
383 }
384 
385 
386 /* PRIVATE */
387 int
private_rmFalseFilterfunc(RMnode * r)388 private_rmFalseFilterfunc (RMnode *r)
389 {
390     r = NULL; 			/* foil compile warning */
391     return(0);
392 }
393 
394 
395 /* PRIVATE */
396 int
left_channel_filterfunc(RMnode * r)397 left_channel_filterfunc (RMnode *r)
398 {
399     RMenum stat = private_rmNodeGetTraversalMaskChannel(r);
400 
401     if ((stat == RM_ALL_CHANNELS) || (stat == RM_LEFT_CHANNEL))
402 	return(1);
403     else
404 	return(0);
405 }
406 
407 
408 /* PRIVATE */
409 int
right_channel_filterfunc(RMnode * r)410 right_channel_filterfunc (RMnode *r)
411 {
412     RMenum stat = private_rmNodeGetTraversalMaskChannel(r);
413 
414     if ((stat == RM_ALL_CHANNELS) || (stat == RM_RIGHT_CHANNEL))
415 	return(1);
416     else
417 	return(0);
418 }
419 
420 
421 /* PRIVATE */
422 int
opaque_and_3d_filterfunc(RMnode * r)423 opaque_and_3d_filterfunc (RMnode *r)
424 {
425     /* this filterfunc will return 1 if the node "r" has 3D locations and is op
426 aque */
427 
428     RMenum vdims, opacity;
429 
430     vdims = private_rmNodeGetTraversalMaskDims(r);
431     opacity = private_rmNodeGetTraversalMaskOpacity(r);
432 
433     if (((vdims == RM_RENDERPASS_3D) || (vdims == RM_RENDERPASS_ALL)) &&
434 	((opacity == RM_RENDERPASS_OPAQUE) || (opacity == RM_RENDERPASS_ALL)))
435 	return(1);
436     else
437 	return(0);
438 }
439 
440 
441 /* PRIVATE */
442 int
transparent_and_3d_filterfunc(RMnode * r)443 transparent_and_3d_filterfunc (RMnode *r)
444 {
445     /* this filterfunc will return 1 if the node "r" has 3D locations and any part of the object is transparent */
446     RMenum vdims, opacity;
447 
448     vdims = private_rmNodeGetTraversalMaskDims(r);
449     opacity = private_rmNodeGetTraversalMaskOpacity(r);
450 
451     if (((vdims == RM_RENDERPASS_3D) || (vdims == RM_RENDERPASS_ALL)) &&
452 	((opacity == RM_RENDERPASS_TRANSPARENT) || (opacity == RM_RENDERPASS_ALL)))
453 	return(1);
454     else
455 	return(0);
456 }
457 
458 
459 /* PRIVATE */
460 int
only_2d_filterfunc(RMnode * r)461 only_2d_filterfunc (RMnode *r)
462 {
463     RMenum vdims;
464 
465     vdims = private_rmNodeGetRenderpassDims(r);
466     /*opacity = private_rmNodeGetRenderpassOpacity(r);*/
467 
468     if ((vdims == RM_RENDERPASS_2D) || (vdims == RM_RENDERPASS_ALL))
469 	return(1);
470     else
471 	return(0);
472 }
473 
474 
475 /* PRIVATE */
476 void
private_postRenderBarrierFunc(RMpipe * p)477 private_postRenderBarrierFunc (RMpipe *p)
478 {
479     if (p->postRenderBarrierFunc != NULL)
480 	(*(p->postRenderBarrierFunc))(p);
481 }
482 
483 
484 /* PRIVATE */
485 void
private_postRenderImageFuncs(RMpipe * p,GLenum whichBuffer)486 private_postRenderImageFuncs (RMpipe *p,
487 			      GLenum whichBuffer)
488 {
489     if (p->postrenderfunc != NULL)
490 	private_rmPostRender(whichBuffer,p);
491 
492     if (p->postrender_depthbufferfunc != NULL)
493 	private_rmPostRenderDepthBuffer(whichBuffer, p);
494 }
495 
496 
497 /* PRIVATE */
498 void
private_postRenderSwapBuffersFunc(RMpipe * p)499 private_postRenderSwapBuffersFunc (RMpipe *p)
500 {
501     /* 12/26/02 wes */
502     rmPipeSwapBuffers(p);
503 }
504 
505 
506 /* PRIVATE */
507 static void
private_rmMonoRender(RMnode * t,RMpipe * p)508 private_rmMonoRender (RMnode *t,
509 		      RMpipe *p)
510 {
511     RMenum render3DOpaqueEnable;
512     RMenum render3DTransparentEnable;
513     RMenum render2DOpaqueEnable;
514     RMenum initMatrixStackBool;
515 
516     /* assume rendermode == GL_RENDER and that we have a double-buffered visual */
517     private_rmSetBackBuffer(p);
518 
519     initMatrixStackBool = rmPipeGetInitMatrixStackMode(p);
520 
521     rmPipeGetRenderPassEnable(p, &render3DOpaqueEnable, &render3DTransparentEnable, &render2DOpaqueEnable);
522     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, NULL, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
523 
524     private_postRenderBarrierFunc(p);
525 
526     if (p->timeSyncFunc != NULL)
527 	(*(p->timeSyncFunc))(p);
528 
529     private_postRenderSwapBuffersFunc(p);
530 
531     private_postRenderImageFuncs(p, GL_FRONT);
532 }
533 
534 /* PRIVATE */
535 static void
private_rmBlueRedRender(RMnode * t,RMpipe * p)536 private_rmBlueRedRender (RMnode *t,
537 			 RMpipe *p)
538 {
539     RMenum render3DOpaqueEnable = RM_TRUE;
540     RMenum render3DTransparentEnable = RM_TRUE;
541     RMenum render2DOpaqueEnable = RM_TRUE;
542     RMenum initMatrixStackBool = rmPipeGetInitMatrixStackMode(p);
543 
544     /* left channel in green/blue, right channel in red */
545     rmPipeGetRenderPassEnable(p, &render3DOpaqueEnable, &render3DTransparentEnable, &render2DOpaqueEnable);
546 
547     /* assume rendermode == GL_RENDER and that we have a double-buffered visual */
548     private_rmSetBackBuffer(p);
549 
550     /* draw the left channel (green and blue) */
551     glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
552     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, left_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
553 
554     /* draw the right channel (red) */
555     glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
556     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, right_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
557 
558     /* restore color mask and do functions */
559     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
560 
561     private_postRenderBarrierFunc(p);
562 
563     if (p->timeSyncFunc != NULL)
564 	(*(p->timeSyncFunc))(p);
565 
566     private_postRenderSwapBuffersFunc(p);
567 
568     private_postRenderImageFuncs(p, GL_FRONT);
569 }
570 
571 
572 /* PRIVATE */
573 static void
private_rmRedBlueRender(RMnode * t,RMpipe * p)574 private_rmRedBlueRender (RMnode *t,
575 			 RMpipe *p)
576 {
577     RMenum render3DOpaqueEnable = RM_TRUE;
578     RMenum render3DTransparentEnable = RM_TRUE;
579     RMenum render2DOpaqueEnable = RM_TRUE;
580     RMenum initMatrixStackBool = rmPipeGetInitMatrixStackMode(p);
581 
582     /* left channel in red, right channel in green/blue */
583     rmPipeGetRenderPassEnable(p, &render3DOpaqueEnable, &render3DTransparentEnable, &render2DOpaqueEnable);
584 
585     /* assume rendermode == GL_RENDER and that we have a double-buffered visual */
586     private_rmSetBackBuffer(p);
587 
588     /* draw the left channel (red) */
589     glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
590     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, left_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
591 
592     /* draw the right channel */
593     glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
594     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, right_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
595 
596     /* restore color mask and do functions */
597     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
598     private_postRenderBarrierFunc(p);
599 
600     if (p->timeSyncFunc != NULL)
601 	(*(p->timeSyncFunc))(p);
602 
603     private_postRenderSwapBuffersFunc(p);
604 
605     private_postRenderImageFuncs(p, GL_FRONT);
606 }
607 
608 
609 /* PRIVATE */
610 static void
private_rmMbufStereoRender(RMnode * t,RMpipe * p)611 private_rmMbufStereoRender (RMnode *t,
612 			    RMpipe *p)
613 {
614     RMenum render3DOpaqueEnable = RM_TRUE;
615     RMenum render3DTransparentEnable = RM_TRUE;
616     RMenum render2DOpaqueEnable = RM_TRUE;
617     RMenum initMatrixStackBool = rmPipeGetInitMatrixStackMode(p);
618 
619     rmPipeGetRenderPassEnable(p, &render3DOpaqueEnable, &render3DTransparentEnable, &render2DOpaqueEnable);
620 
621     /* assume rendermode == GL_RENDER and that we have a  double-buffered visual */
622 
623     /* draw the left channel */
624     glDrawBuffer(GL_BACK_LEFT);
625     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, left_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
626 
627     /* draw the right channel */
628     glDrawBuffer(GL_BACK_RIGHT);
629     private_rmSubTreeFrame(p, t, GL_RENDER, NULL, NULL, right_channel_filterfunc, NULL, render3DOpaqueEnable, render3DTransparentEnable, render2DOpaqueEnable,initMatrixStackBool);
630 
631     /* restore color mask and do functions */
632     private_postRenderBarrierFunc(p);
633 
634     if (p->timeSyncFunc != NULL)
635 	(*(p->timeSyncFunc))(p);
636 
637     private_postRenderSwapBuffersFunc(p);
638 
639     private_postRenderImageFuncs(p, GL_FRONT_LEFT);
640     private_postRenderImageFuncs(p, GL_FRONT_RIGHT);
641 }
642 
643 
644 static int frameNum=0;
645 /* PRIVATE */
646 void
private_rmSubTreeFrame(RMpipe * renderPipe,RMnode * user_root,GLenum renderMode,void (* perobj_func)(const RMnode *),void (* perprim_func)(RMnode *,int),int (* perchannel_func)(RMnode *),void (* perstate_func)(RMstate *,int),RMenum render3DOpaque,RMenum render3DTransparent,RMenum render2D,RMenum initMatrixStack)647 private_rmSubTreeFrame (RMpipe *renderPipe,
648 		        RMnode *user_root,
649 		        GLenum renderMode,
650 		        void (*perobj_func)(const RMnode *),
651 		        void (*perprim_func)(RMnode *, int),
652 		        int (*perchannel_func)(RMnode *),
653 		        void (*perstate_func)(RMstate *, int),
654 		        RMenum render3DOpaque,
655 		        RMenum render3DTransparent,
656 		        RMenum render2D,
657 			RMenum initMatrixStack)
658 {
659     /*
660      * this routine is the shepherd which manages all activities required
661      * when a new frame is to be rendered.
662      */
663     int     nthState = 0;
664     RMenum  this_channel;
665     RMpipe *p;
666     RMstate rm_state;
667     RMenum backgroundSceneEnable;
668     RMmatrix initModel, initProjection, initTexture;
669     RMstateCache *rsc = private_rmStateCacheNew();
670 
671     /*
672      * Policy note (Feb 2000):
673      *
674      * RMnode scene parameters fall into two classes: "background" operations
675      * and non-background operations. Background operations include
676      * background clear color and image tiles (framebuffer clears) and
677      * background depth values and depth image tiles.
678      *
679      * At this time, the order of multipass rendering is:
680      * 1. render 3D opaque objects
681      * 2. render transparent 3d objects
682      * 3. render 2D objects (we assume 2D stuff is opaque at this time;
683      *    there is no 2d transparent render pass).
684      *
685      * We use a policy that background operations are enabled in stages
686      * 1 & 3, but disabled in stage 2. Designers should be aware of this
687      * policy when building scene graphs.
688      *
689      * A common error would be to assign a background clear color to
690      * rmRootNode() - rmRootNode is processed in all rendering passes
691      * (unless explicitly modified by the application). Therefore, if
692      * the scene graph contains 3D objects, they will not be visible because
693      * the framebuffer would be cleared twice - once during the
694      * opaque 3d pass, and again during the 2D pass.
695      *
696      * A reasonable strategy for developers is to assign background clears,
697      * cameras and viewports within a single scene graph node. That will
698      * prevent a number of application-level scene graph errors.
699      */
700 
701     p = renderPipe;
702 
703     if (user_root == NULL)
704 	return;
705 
706     if (initMatrixStack == RM_TRUE) /* we own OpenGL matrix stack */
707     {
708 	glMatrixMode(GL_PROJECTION);
709 	glLoadIdentity();
710 
711 	glMatrixMode(GL_MODELVIEW);
712 	glLoadIdentity();
713 
714 	private_rmStateInit(p, &rm_state, (RMenum) renderMode, NULL, NULL,
715 			    NULL, NULL);
716     }
717     else   /* load init matrix values from the OpenGL matrix stack */
718     {
719 	glGetFloatv(GL_MODELVIEW_MATRIX,&(initModel.m[0][0]));
720 	glGetFloatv(GL_PROJECTION_MATRIX,&(initProjection.m[0][0]));
721 	glGetFloatv(GL_TEXTURE_MATRIX,&(initTexture.m[0][0]));
722 
723 	private_rmStateInit(p, &rm_state, (RMenum) renderMode,
724 			    &initModel,
725 			    NULL,
726 			    &initProjection,
727 			    &initTexture);
728     }
729 
730     if (perchannel_func == NULL)
731 	this_channel = RM_ALL_CHANNELS;
732     else
733     {
734 	if (perchannel_func == left_channel_filterfunc)
735 	    this_channel = RM_LEFT_CHANNEL;
736 	else
737 	{
738 	    if (perchannel_func == right_channel_filterfunc)
739 		this_channel = RM_RIGHT_CHANNEL;
740 	    else
741 		this_channel = RM_ALL_CHANNELS;
742 	}
743     }
744 
745     /* RMpipe level fbclears? */
746     if ((p->fbClearNode != NULL) && (p->fbClearNode->fbClear != NULL))
747     {
748 	glDisable(GL_BLEND);	/* make sure it's turned off */
749 	glDisable(GL_DEPTH_TEST);
750 	glDepthMask(GL_TRUE);
751 	glDisable(GL_LIGHTING);
752 
753 	private_fbClear(p->fbClearNode->fbClear, &rm_state, RM_TRUE, RM_TRUE);
754     }
755 
756 
757 #if DO_TIME
758     rmStartTimer();
759 #endif
760 
761     /* render 3D, opaque objects */
762     if (render3DOpaque == RM_TRUE)
763     {
764 	RMstate s;
765 
766 	backgroundSceneEnable = RM_TRUE;
767 
768 
769 	if (initMatrixStack == RM_TRUE)
770 	{
771 	    glMatrixMode(GL_PROJECTION);
772 	    glLoadIdentity();
773 	    glMatrixMode(GL_MODELVIEW);
774 	    glLoadIdentity();
775 	}
776 
777 	glDisable(GL_BLEND);	/* make sure it's turned off */
778 	glEnable(GL_DEPTH_TEST);
779 	glDepthMask(GL_TRUE);
780 
781 	memcpy((void *)&s, (void *)&rm_state, sizeof(RMstate));
782 
783 	s.renderpass = RM_RENDERPASS_OPAQUE;
784 	s.which_channel = this_channel;
785 	s.renderPassDims = RM_RENDERPASS_3D; /* 8/8/04 */
786 
787 	/* 5/11/02 - make sure actual state is same as in RMstate */
788 	private_rmColorMaterial(&s, rsc, RM_FALSE); /* turn off color material */
789 	glDisable(GL_LIGHTING);
790 	s.lightingActive = RM_FALSE;
791 	rsc->lightingActive = RM_FALSE;
792 
793 	render_tree(renderPipe, user_root, opaque_and_3d_filterfunc, perobj_func, perprim_func, NULL, perchannel_func, perstate_func, backgroundSceneEnable, renderMode, &s, &nthState, initMatrixStack, rsc);
794     }
795 
796     /* render 3D, transparent objects */
797     if (render3DTransparent == RM_TRUE)
798     {
799 	RMstate s;
800 
801 
802 	if (initMatrixStack == RM_TRUE)
803 	{
804 	    glMatrixMode(GL_PROJECTION);
805 	    glLoadIdentity();
806 	    glMatrixMode(GL_MODELVIEW);
807 	    glLoadIdentity();
808 	}
809 	memcpy((void *)&s, (void *)&rm_state, sizeof(RMstate));
810 
811 	s.renderpass = RM_RENDERPASS_TRANSPARENT;
812 	s.which_channel = this_channel;
813 	s.renderPassDims = RM_RENDERPASS_3D; /* 8/8/04 */
814 
815 	/* goes here or somewhere else? */
816 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
817 	glEnable(GL_BLEND);
818 
819 	glEnable(GL_DEPTH_TEST);
820 	glDepthMask(GL_FALSE);
821 
822 	/* 5/11/02 - make sure actual state is same as in RMstate */
823 	private_rmColorMaterial(&s, rsc, RM_FALSE); /* turn off color material */
824 	glDisable(GL_LIGHTING);
825 	s.lightingActive = RM_FALSE;
826 	rsc->lightingActive = RM_FALSE;
827 
828 	backgroundSceneEnable = RM_FALSE; /* may no longer be necessary: 9/11/04 */
829 
830 	render_tree(renderPipe, user_root, transparent_and_3d_filterfunc, perobj_func, perprim_func, NULL, perchannel_func, perstate_func, backgroundSceneEnable, renderMode, &s, &nthState, initMatrixStack, rsc);
831 
832 	glDisable(GL_BLEND);	/* make sure it's turned off */
833     }
834 
835     /* render 2D stuff on top of the 3D scene */
836     if (render2D == RM_TRUE)
837     {
838 	RMstate s;
839 
840 
841 	if (initMatrixStack == RM_TRUE)
842 	{
843 	    glMatrixMode(GL_PROJECTION);
844 	    glLoadIdentity();
845 	    glMatrixMode(GL_MODELVIEW);
846 	    glLoadIdentity();
847 	}
848 	memcpy((void *)&s, (void *)&rm_state, sizeof(RMstate));
849 
850 	s.renderpass = RM_RENDERPASS_OPAQUE;
851 	s.which_channel = this_channel;
852 	s.renderPassDims = RM_RENDERPASS_2D; /* 8/8/04 */
853 
854 	glDisable(GL_DEPTH_TEST);
855 	/* 5/11/02 - make sure actual state is same as in RMstate */
856 	private_rmColorMaterial(&s, rsc, RM_FALSE); /* turn off color material */
857 	glDisable(GL_LIGHTING);
858 	s.lightingActive = RM_FALSE;
859 	rsc->lightingActive = RM_FALSE;
860 
861 	backgroundSceneEnable = RM_TRUE; /* may no longer be necessary 9/11/04 */
862 
863 	render_tree(renderPipe, user_root, only_2d_filterfunc, perobj_func, perprim_func, NULL, perchannel_func, perstate_func, backgroundSceneEnable, renderMode, &s, &nthState, initMatrixStack, rsc);
864     }
865 
866 #if DO_TIME
867     glFinish();			/* needed for accurate network timing */
868     rmElapsedTime(" RM rendering time ");
869 #endif
870 
871     private_rmStateCacheDelete(rsc);
872     frameNum++;
873 }
874 
875 
876 /* PRIVATE
877  *
878  * private_setViewport - an internal routine used to create a viewport
879  * in OpenGL from RM-style scene parameters.
880  */
881 int
private_setViewport(const RMnode * r,RMstate * s,int push_attrib_enable,RMenum applyGL)882 private_setViewport (const RMnode *r,
883 		     RMstate *s,
884 		     int push_attrib_enable,
885 		     RMenum applyGL)
886 {
887     int   doScissor = 1;
888     GLint x, y, w, h;
889 
890     /*
891      * do we need the scissor test? if the viewport is anything but
892      * a full-window, then we do need the scissor test.
893      */
894     if ((r->scene_parms->viewport[0] == 0.0F) && (r->scene_parms->viewport[1] == 0.0F) &&
895 	(r->scene_parms->viewport[2] == 1.0F) && (r->scene_parms->viewport[3] == 1.0F))
896 	doScissor = 0;
897 
898     x = r->scene_parms->viewport[0] * s->w;
899     y = r->scene_parms->viewport[1] * s->h;
900     w = r->scene_parms->viewport[2] * s->w - x;
901     h = r->scene_parms->viewport[3] * s->h - y;
902 
903     if (applyGL == RM_TRUE)
904     {
905 	glViewport(x, y, w, h);
906 
907 	if (doScissor == 1)
908 	{
909 	    glEnable(GL_SCISSOR_TEST);
910 	    glScissor(x, y, w, h);
911 	}
912 	else
913 	    glDisable(GL_SCISSOR_TEST);
914 
915     }
916 
917     /* now update the RMstate */
918 #if 0
919     memcpy((void *)(s->vp), (void *)r->scene_parms->viewport, sizeof(float)*4);
920 #endif
921 
922     s->vp[0] = x;
923     s->vp[1] = y;
924     s->vp[2] = w;
925     s->vp[3] = h;
926 
927     private_rmComputeViewportMatrix(s->vp, (float)w, (float)h, &(s->vpm));
928 
929 #if 0
930     s->vpm.m[0][0] = s->vp[0] * 0.5F;
931     s->vpm.m[1][1] = s->vp[1] * 0.5F;
932     s->vpm.m[3][0] = s->vpm.m[0][0];
933     s->vpm.m[3][1] = s->vpm.m[1][1];
934 #endif
935 
936     push_attrib_enable = 1; /* needed for state tracking */
937 
938     return(push_attrib_enable);
939 }
940 
941 
942 /* PRIVATE */
943 void
private_computeStereoOffset(RMcamera3D * c,RMenum whichChannel,RMcamera3D * r)944 private_computeStereoOffset (RMcamera3D *c,
945 			     RMenum whichChannel,
946 			     RMcamera3D *r)
947 {
948     float       focaldelta;
949     double      mag_eye_at;
950     double      delta;
951     RMvertex3D  eye_at;
952     RMvertex3D  eye_at_cross_up;
953     RMvertex3D *local_up;
954     RMvertex3D  local_eye, local_at;
955 
956     *r = *c;
957 
958     focaldelta = rmCamera3DGetFocalDistance (c);
959 
960     eye_at.x = c->eye.x - c->at.x;
961     eye_at.y = c->eye.y - c->at.y;
962     eye_at.z = c->eye.z - c->at.z;
963 
964     rmVertex3DMagNormalize(&eye_at, &mag_eye_at);
965 
966     /* assume the up vector is normalized */
967     local_up = &c->up;
968     rmVertex3DCross(&eye_at, local_up, &eye_at_cross_up);
969 
970     delta = sin(RM_DEGREES_TO_RADIANS(rmCamera3DGetEyeSeparation(c) * 0.5));
971     delta *= mag_eye_at;
972 
973     if (whichChannel == RM_LEFT_CHANNEL)
974     {
975 	local_eye.x = c->eye.x - (delta * eye_at_cross_up.x);
976 	local_eye.y = c->eye.y - (delta * eye_at_cross_up.y);
977 	local_eye.z = c->eye.z - (delta * eye_at_cross_up.z);
978     }
979     else
980     {
981 	local_eye.x = c->eye.x + (delta * eye_at_cross_up.x);
982 	local_eye.y = c->eye.y + (delta * eye_at_cross_up.y);
983 	local_eye.z = c->eye.z + (delta * eye_at_cross_up.z);
984     }
985 
986     local_at.x = c->eye.x - (eye_at.x * mag_eye_at * focaldelta);
987     local_at.y = c->eye.y - (eye_at.y * mag_eye_at * focaldelta);
988     local_at.z = c->eye.z - (eye_at.z * mag_eye_at * focaldelta);
989 
990     r->eye = local_eye;
991     r->at = local_at;
992 }
993 
994 
995 #define RM_FARZ 0.99999
996 
997 /* PRIVATE */
998 void
private_drawCameraPickableQuad(void (* perobj_func)(const RMnode *),RMnode * n)999 private_drawCameraPickableQuad (void (*perobj_func)(const RMnode *),
1000 			        RMnode *n)
1001 {
1002     /* this block of code draws the pickable background quad */
1003     if (perobj_func != NULL)
1004 	(*perobj_func)(n);
1005 
1006     glMatrixMode(GL_PROJECTION);
1007 
1008     glOrtho((GLfloat)(-1.0), (GLfloat)(1.0), (GLfloat)(-1.0), (GLfloat)(1.0), (GLfloat)(1.0), (GLfloat)(-1.0));
1009 
1010     glMatrixMode(GL_MODELVIEW);
1011     glPushMatrix();
1012     glLoadIdentity();
1013 
1014     glBegin(GL_QUADS);
1015 
1016 #if 0
1017     glColor3f(0.3F, 0.3F, 0.3F); /* color used in debugging */
1018 #endif
1019     glVertex3f(-1.0, -1.0, RM_FARZ);
1020     glVertex3f(1.0, -1.0, RM_FARZ);
1021     glVertex3f(1.0, 1.0, RM_FARZ);
1022     glVertex3f(-1.0, 1.0, RM_FARZ);
1023 
1024     glEnd();
1025     glPopMatrix();
1026 }
1027 
1028 
1029 #define MODELVIEW_MATRIX_CHANGED	1
1030 #define PROJECTION_MATRIX_CHANGED	2
1031 #define TEXTURE_MATRIX_CHANGED		4
1032 
1033 /* PRIVATE */
1034 int
private_collectAndApplyMatrices(RMstate * rState,RMnode * n,void (* perObjFunc)(const RMnode *),GLenum renderMode,int * pushedAttribsReturn,RMenum applyGL)1035 private_collectAndApplyMatrices (RMstate *rState,
1036 				 RMnode *n,
1037 				 void (*perObjFunc)(const RMnode *),
1038 				 GLenum renderMode,
1039 				 int *pushedAttribsReturn,
1040 				 RMenum applyGL)
1041 {
1042     int      viewMatrixChange = 0;
1043     int      modelMatrixChange = 0;
1044     int      textureMatrixChange = 0;
1045     int      pushedAttribs = 0;
1046     int      returnStatus = 0;
1047     RMmatrix model, view, proj, pick;
1048     RMmatrix oglModelView;
1049 
1050     /*
1051      * this routine will determine what changes to the matrix stack,
1052      * if any, are dictated by parms at this node. if any changes
1053      * are needed, this routine will accumulate transformations
1054      * and do a glLoadMatrixf() on the proper matrix stack.
1055      *
1056      * note that RM maintains separate view, model & projection
1057      * matrices in the RMstate object.
1058      *
1059      * the return value from this routine is the bitwise OR of the following:
1060      * MODELVIEW_MATRIX_CHANGED,PROJECTION_MATRIX_CHANGED  and
1061      * TEXTURE_MATRIX_CHANGED. each of these bits indicates which of
1062      * corresponding OpenGL matrix stacks was modified by this routine. a
1063      * return value of zero means that no matrix stacks were modified.
1064      *
1065      * at this time (feb 2000), all OpenGL state management is
1066      * done using glPushAttrib()/glPopAttrib(). this is a costly
1067      * operation, so in the future, a performance enhancement will be
1068      * to do something more efficient.
1069      *
1070      * in the future, we want to cache the matrix associated with
1071      * 2D/3D cameras so we don't have to recompute it on each frame.
1072      *
1073      * the viewport is processed here, rather than later, because the
1074      * camera routines have occasion to use the current viewport.
1075      *
1076      */
1077 
1078     if (n->scene_parms && n->scene_parms->viewport)	/* do viewport */
1079 	pushedAttribs = private_setViewport(n, rState, pushedAttribs, applyGL);
1080 
1081     if (n->scene_parms && n->scene_parms->camera3d)
1082     {
1083 	RMcamera3D tmp;
1084 
1085 	if ((rState->which_channel != RM_ALL_CHANNELS) && (rmCamera3DGetStereo(n->scene_parms->camera3d) == RM_TRUE))
1086 	{
1087 	    /*
1088 	     * for binocular stereo, we compute a new camera model for
1089 	     * the left or right eye, then use that modified camera in
1090 	     * the derivation of a view matrix.
1091 	     */
1092 	    private_computeStereoOffset(n->scene_parms->camera3d, rState->which_channel, &tmp);
1093 	}
1094 	else
1095 	    tmp = *(n->scene_parms->camera3d);
1096 
1097 	rmCamera3DComputeViewMatrix(&tmp, &view, &proj);
1098 
1099 	if (renderMode == GL_SELECT)
1100 	{
1101 	    private_rmComputePickMatrix(rState, &pick);
1102 	    rState->pick = pick;
1103 	    private_drawCameraPickableQuad(perObjFunc, n);
1104 	}
1105 
1106 	/* nested view matrices are permissible, but weird. transformations
1107 	 occur such that child transformations apply first. */
1108 	rmMatrixMultiply(&view, &(rState->view), &view);
1109 	rState->view = view;
1110 
1111 	rmMatrixMultiply(&(rState->projection), &proj, &(rState->projection));
1112 	viewMatrixChange = 1;
1113     }
1114     else if (n->scene_parms && n->scene_parms->camera2d)
1115     {
1116 
1117 	rmCamera2DComputeViewMatrix(n->scene_parms->camera2d, &view);
1118 	rState->view = view;
1119 
1120 	if (renderMode == GL_SELECT)
1121 	{
1122 	    private_rmComputePickMatrix(rState, &pick);
1123 	    rState->pick = pick;
1124 	    private_drawCameraPickableQuad(perObjFunc, n);
1125 	}
1126 	rmMatrixIdentity(&proj);
1127 	rState->projection = proj;
1128 	viewMatrixChange = 1;
1129     }
1130 
1131     if ((n->transforms != NULL) && (n->transforms->transform_mode != RM_TRANSFORM_IGNORE))
1132     {
1133 	rmNodeGetCompositeModelMatrix(n, &model);
1134 
1135 	/* texture and model matrix transformations accumulate - child transformations are applied first */
1136 	if (n->transforms->transform_mode == RM_TRANSFORM_TEXTURE)
1137 	{
1138 	    rmMatrixMultiply(&model, &(rState->textureMatrix), &model);
1139 	    rState->textureMatrix = model;
1140 	    textureMatrixChange = 1;
1141 	}
1142 	else
1143 	{
1144 	    rmMatrixMultiply(&model, &(rState->model), &model);
1145 	    rState->model = model;
1146 	    modelMatrixChange = 1;
1147 	}
1148     }
1149 
1150     /* now apply the matrices to the RMstate object - load the matrices into OpenGL */
1151     if (textureMatrixChange == 1)
1152     {
1153 	if (applyGL == RM_TRUE)
1154 	{
1155 	    glMatrixMode(GL_TEXTURE);
1156 	    glLoadMatrixf(&(model.m[0][0]));
1157 
1158 	    glMatrixMode(GL_MODELVIEW);
1159 	}
1160 	returnStatus = TEXTURE_MATRIX_CHANGED;
1161     }
1162     else if (modelMatrixChange==1 || viewMatrixChange == 1)
1163     {
1164 	RMmatrix m;
1165 
1166 	returnStatus = MODELVIEW_MATRIX_CHANGED;
1167 	rmMatrixMultiply(&(rState->model), &(rState->view), &oglModelView);
1168 
1169 	if (viewMatrixChange == 1)
1170 	{
1171 	    rmMatrixMultiply(&(rState->projection), &(rState->pick), &m);
1172 
1173 	    if (applyGL == RM_TRUE)
1174 	    {
1175 		glMatrixMode(GL_PROJECTION);
1176 		glLoadMatrixf(&(m.m[0][0]));
1177 	    }
1178 	    returnStatus |= PROJECTION_MATRIX_CHANGED;
1179 	}
1180 
1181 	if (applyGL == RM_TRUE)
1182 	{
1183 	    glMatrixMode(GL_MODELVIEW);
1184 	    glLoadMatrixf(&(oglModelView.m[0][0]));
1185 	}
1186 	rState->modelView = oglModelView;
1187 	rmMatrixMultiply(&(rState->modelView), &(rState->projection), &(rState->composite));
1188     }
1189 
1190     /* leave this routine in glMatrixMode(GL_MODELVIEW) */
1191     if (pushedAttribs == 1)
1192        rState->attrib_stack_depth++;
1193 
1194     *pushedAttribsReturn = pushedAttribs;
1195 
1196     return(returnStatus);
1197 }
1198 
1199 static int
private_invokeSerialCallbacks(RMnode * r,int (* afunc)(const RMnode *,const RMstate *),int (* bfunc)(const RMnode *,const RMstate *),RMstate * s,RMenum honorStatus)1200 private_invokeSerialCallbacks(RMnode *r,
1201 			      int (*afunc)(const RMnode *, const RMstate *),
1202 			      int (*bfunc)(const RMnode *, const RMstate *),
1203 			      RMstate *s,
1204 			      RMenum honorStatus)
1205 {
1206     int rstat=1;
1207 
1208     /*
1209      * serial view+render traversal pre/post callbacks:
1210      *
1211      * afunc represents the view traversal callback, and bfunc represents
1212      * the render traversal callback.
1213      *
1214      * if afunc returns <= 0 AND honorStatus == RM_TRUE, return immediately (including status).
1215      * if bfunc, then compute it's status.
1216      * return the status;
1217      *
1218      * honorStatus is used since the returnstatus from the postcallback
1219      * function is supposed to be ignored.
1220      */
1221 
1222     if (afunc != NULL)
1223     {
1224 	/* do we need to set a value in parent state to say this
1225 	 is the view traversal? */
1226 	rstat = (*afunc)(r, (const RMstate *)s);
1227 	if ((rstat <= 0) && (honorStatus == RM_TRUE))
1228 	    return(rstat);
1229     }
1230 
1231     if (bfunc != NULL)
1232 	/* do we need to set a value in parent state to say this
1233 	 is the draw traversal? */
1234 	rstat = (*bfunc)(r, (const RMstate *)s);
1235 
1236     return(rstat);
1237 }
1238 
1239 /* PRIVATE
1240  *
1241  * render_tree() is the main rendering workhorse. it does a recursive traversal
1242  * of the scene graph, processes the multipass filtering functions, node
1243  * callbacks and invokes draw routines for each primitive.
1244  *
1245  * higher-level routines are used to invoke this routine, setting the node
1246  * filter functions and other initialization parameters.
1247  */
1248 static void
render_tree(RMpipe * renderPipe,RMnode * r,int (* filterfunc)(RMnode *),void (* perobj_func)(const RMnode *),void (* perprim_func)(RMnode *,int),void (* precam_func)(void),int (* perchannel_func)(RMnode *),void (* perstate_func)(RMstate *,int),RMenum backgroundSceneEnable,GLenum rendermode,RMstate * parent_state,int * nthState,RMenum initMatrixStack,RMstateCache * rsc)1249 render_tree (RMpipe *renderPipe,
1250 	     RMnode *r,
1251 	     int (*filterfunc)(RMnode *), /* used to filter objects for rendering */
1252 	     void (*perobj_func)(const RMnode *),
1253 	     void (*perprim_func)(RMnode *, int),
1254 	     void (*precam_func)(void),
1255 	     int (*perchannel_func)(RMnode *),
1256 	     void (*perstate_func)(RMstate *, int),
1257 	     RMenum backgroundSceneEnable,
1258 	     GLenum rendermode,
1259 	     RMstate *parent_state,
1260 	     int *nthState,
1261 	     RMenum initMatrixStack,
1262 	     RMstateCache *rsc)
1263 {
1264     int          status;
1265     RMenum       display_status;
1266     int          i;
1267     int          pushed_attribs=0;
1268     int          newMatrices=0;
1269     int        (*channelfunc)();
1270     RMprimitive *p;
1271     RMstate      local_state;
1272 
1273     /* pre traversals for both view and draw are processed here - this is
1274      serial rendering code. the view traversal funcs are called first,
1275      followed by the rendering traversal routine. */
1276 
1277     if ((r->viewPretraverseCallback != NULL) || (r->renderPretraverseCallback != NULL))
1278     {
1279 	int   rstat;
1280 	rstat = private_invokeSerialCallbacks(r, r->viewPretraverseCallback, r->renderPretraverseCallback, parent_state, RM_TRUE);
1281 
1282 	/*
1283 	 * when the pretraverse routine returns something <= 0, skip
1284 	 * any further processing of this node, except we need to call
1285 	 * the post-traversal routine, if defined.
1286 	 */
1287 	if (((r->renderPosttraverseCallback != NULL) || (r->viewPosttraverseCallback)) && (rstat <= 0))
1288 	{
1289 	    rstat = private_invokeSerialCallbacks(r, r->viewPosttraverseCallback, r->renderPosttraverseCallback, parent_state, RM_FALSE);
1290 	}
1291 	if (rstat <= 0)
1292 	    return;
1293     }
1294     if (perchannel_func == NULL)
1295 	channelfunc = private_rmTrueFilterfunc;
1296     else
1297 	channelfunc = perchannel_func;
1298 
1299     /* early termination tests  */
1300 
1301     display_status = rmNodeGetTraverseEnable(r);
1302 
1303     status = (display_status == RM_TRUE) && ((*filterfunc)(r))
1304 	&& (*channelfunc)(r);
1305 
1306     if (status != 0)
1307     {
1308 	/* if doing a pick... */
1309 	if (rendermode == GL_SELECT)
1310 	{
1311 	    /* make sure the node's pick enable attribute is set */
1312 	    RMenum pickEnable = rmNodeGetPickEnable(r);
1313 	    if (pickEnable == RM_FALSE)
1314 		status = 0; 	/* early termination */
1315 	}
1316     }
1317 
1318     /*
1319      * at this point, if status == 0, the node will not be
1320      * displayed because it did not pass the filtering tests.
1321      * before returning, we need to invoke the post-traversal
1322      * function, if any.
1323      */
1324     if (status == 0)
1325     {
1326 	private_invokeSerialCallbacks(r, r->viewPosttraverseCallback, r->renderPosttraverseCallback, parent_state, RM_FALSE);
1327 	return;
1328     }
1329 
1330     /* use a special routine here to see if we need to make
1331      any changes to the rendering state, and if this node includes any
1332      changes to the current scene parms. */
1333     local_state = *parent_state;
1334 
1335     newMatrices = private_collectAndApplyMatrices(&local_state, r, perobj_func, rendermode, &pushed_attribs, RM_TRUE);
1336 
1337 #if 0
1338     /* the following shows a divergence in processing paths in the
1339        RM_PIPE_SERIAL vs. RM_PIPE_MULTISTAGE* code bases. we need to
1340        unify these divergent paths in a future version of the code. */
1341     {
1342 	/* debug test. */
1343 	int t1 =  ((r->scene_parms != NULL) || (r->rprops != NULL) || (r->sprops != NULL));
1344 	int t2 = (private_rmNodeGetAttribMask(r) != 0);
1345 
1346 	if (t2 && !t1)
1347 	    printf(" rmframe: odd truth test! \n");
1348     }
1349 #endif
1350 
1351     /* honor scene parms, if any */
1352     if ((r->scene_parms != NULL) || (r->rprops != NULL) || (r->sprops != NULL))
1353     {
1354 	/* starting in RM 1.6.0, we're using the same call sequence
1355 	 for updating the OpenGL and local state, including pushattrib.
1356 	 This code still needs more cleanup but appears to be functioning
1357 	 correctly in all available test cases.
1358 	*/
1359 	extern int mtUpdateSceneParms (const RMnode *r, RMstate *rState, RMpipe *renderPipe, RMstateCache *rsc);
1360 	extern void mtUpdateRenderProps(const RMnode *r, RMstate *rState, RMstateCache *rsc);
1361 	extern void mtUpdateSurfaceProps(const RMnode *r, RMstate *rState);
1362 
1363 	if (private_rmNodeGetAttribMask(r) != 0)
1364 	{
1365 	    private_rmGLPushAttrib(renderPipe, r, private_rmNodeGetAttribMask(r));
1366 	    pushed_attribs = 1;
1367 	}
1368 
1369 	if (r->scene_parms != NULL)
1370 	    mtUpdateSceneParms(r, &local_state, renderPipe, rsc);
1371 
1372 	if (r->rprops != NULL)
1373 	    mtUpdateRenderProps(r, &local_state, rsc);
1374 
1375 	if (r->sprops != NULL)
1376 	    mtUpdateSurfaceProps(r, &local_state);
1377 
1378 	private_rmStateCacheSync(&local_state, rsc);
1379 
1380 	if (perstate_func != 0 && pushed_attribs != 0)
1381 	    (*perstate_func)(&local_state, *nthState);
1382 
1383 	if (pushed_attribs != 0)
1384 	{
1385 	    *nthState += 1;
1386 	    /*	    private_rmStateCacheSync(&local_state, rsc); used during dev/debug  */
1387 	}
1388     }
1389 
1390 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
1391     if (pushed_attribs)
1392     {
1393 	char buf[128];
1394 	sprintf(buf," render_tree post-attrib-update:%s ",r->object_info.name);
1395 	private_rmLightStateConsistencyCheck(buf, &local_state, rsc);
1396     }
1397 #endif
1398 
1399     /* xeq any fb/db clears, if requested */
1400     if (r->fbClear != NULL)
1401     {
1402 	private_fbClear(r->fbClear, &local_state, RM_TRUE, backgroundSceneEnable);
1403 
1404     }
1405 
1406     if (r->nchildren == 0) /* a leaf node */
1407     {
1408 	/* filterfunc() is called on a per-node basis to selectively
1409 	 not render certain nodes.  for example, we might want to render
1410 	 only 3d, opaque nodes in one pass, then 3d transparent nodes
1411 	 in a later pass.   here's where that filtering gets done. */
1412 
1413 	if ((display_status == RM_TRUE) && ((*filterfunc)(r))
1414 	    && (*channelfunc)(r))
1415 	{
1416 	    int nprims = 0;
1417 	    nprims = rmNodeGetNumPrims(r);
1418 
1419 	    for (i = 0; i < nprims; i++)
1420 	    {
1421 	        void (*renderfunc)  OGLPRIMPARMLIST() ;
1422 
1423 		if (perprim_func)
1424 		    (*perprim_func)(r, i);
1425 
1426 		p = r->prims[i]; /* bad, use API!! */
1427 
1428 		if (p != NULL)
1429 		{
1430 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
1431 		    {
1432 			char buf[128];
1433 			sprintf(buf," render_tree pre-render:%s ",r->object_info.name);
1434 			private_rmLightStateConsistencyCheck(buf, &local_state, rsc);
1435 		    }
1436 #endif
1437 		    renderfunc = p->renderfunc;
1438 		    (*renderfunc)(p, r, &local_state, renderPipe, rsc);
1439 
1440 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
1441 		    {
1442 			char buf[128];
1443 
1444 			sprintf(buf, " after prim draw routine %s ", r->object_info.name);
1445 			rmGLGetError(buf);
1446 			sprintf(buf," render_tree post-render:%s ",r->object_info.name);
1447 			private_rmLightStateConsistencyCheck(buf, &local_state, rsc);
1448 		    }
1449 #endif
1450 		}
1451 	    } /* loop over prims */
1452 	} /* passes filter test */
1453     } /* a leaf node */
1454     else /* walk the tree */
1455     {
1456 	RMenum  status;
1457         RMnode *c;
1458 
1459 	/* walk the subtree iff traverse-enable is true */
1460 
1461 	status = rmNodeGetTraverseEnable(r);
1462 
1463 	if (status == RM_TRUE)
1464 	{
1465 	    if (r->viewSwitchCallback != NULL)
1466 	    {
1467 		int   indx, status;
1468 		int (*afunc)(const RMnode *, const RMstate *);
1469 
1470 		afunc = r->viewSwitchCallback;
1471 		indx = (*afunc)(r, &local_state);
1472 		status = ((indx >= 0) && (indx < r->nchildren));
1473 
1474 		/* if the switch callback returns something less than zero, depth traversal is discontinued */
1475 		if (status == 1)
1476 		{
1477 		    c = r->children[indx];
1478 
1479 		    if (RM_ASSERT(c, "NULL child error: the index returned by the switch callback function indexes a NULL child.\n") == RM_CHILL)
1480 			render_tree(renderPipe, c, filterfunc, perobj_func, perprim_func, precam_func, perchannel_func, perstate_func, backgroundSceneEnable, rendermode, &local_state, nthState, initMatrixStack, rsc);
1481 /*			private_rmStateCacheSync(&local_state, rsc); used during dev/debug */
1482 		}
1483 	    }
1484 	    else
1485 	    {
1486 		for (i = 0; i < r->nchildren; i++)
1487 		{
1488 		    c = r->children[i];
1489 		    render_tree(renderPipe, c, filterfunc, perobj_func, perprim_func, precam_func, perchannel_func, perstate_func, backgroundSceneEnable, rendermode, &local_state, nthState, initMatrixStack, rsc);
1490 
1491 /*			private_rmStateCacheSync(&local_state, rsc); used during dev/debug */
1492 		}
1493 	    }
1494 	}
1495     }
1496 
1497     if (pushed_attribs)
1498     {
1499 	private_rmGLPopAttrib(renderPipe, parent_state, rsc);
1500 
1501 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
1502 	{
1503 	    char buf[128];
1504 
1505 	    sprintf(buf," render_tree post-popattrib:%s ",r->object_info.name);
1506 	    private_rmLightStateConsistencyCheck(buf, parent_state, rsc);
1507 	}
1508 #endif
1509     }
1510     if (newMatrices != 0)
1511     {
1512 	if (newMatrices & TEXTURE_MATRIX_CHANGED)
1513         {
1514 	    glMatrixMode(GL_TEXTURE);
1515 	    glLoadMatrixf(&(parent_state->textureMatrix.m[0][0]));
1516 	}
1517 	if (newMatrices & PROJECTION_MATRIX_CHANGED)
1518 	{
1519 	    glMatrixMode(GL_PROJECTION);
1520 	    glLoadMatrixf(&(parent_state->projection.m[0][0]));
1521 	}
1522 	if (newMatrices & MODELVIEW_MATRIX_CHANGED)
1523         {
1524 	    glMatrixMode(GL_MODELVIEW);
1525 	    glLoadMatrixf(&(parent_state->modelView.m[0][0]));
1526 	}
1527     }
1528 
1529    if ((r->viewPosttraverseCallback != NULL) || (r->renderPosttraverseCallback != NULL))
1530    {
1531 	private_invokeSerialCallbacks(r, r->viewPosttraverseCallback, r->renderPosttraverseCallback, &local_state, RM_FALSE);
1532     }
1533 }
1534 
1535 
1536 /* PRIVATE
1537  *
1538  * dumplight: internal routine that creates a light source in OpenGL
1539  * from an RMlight object.
1540  */
1541 static void
dumplight(GLenum lightno,RMlight * l)1542 dumplight (GLenum lightno,
1543 	   RMlight *l)
1544 {
1545     GLfloat pos[4];
1546 
1547     glEnable(lightno);
1548     glLightfv(lightno, GL_AMBIENT, (GLfloat *)&(l->ambientLightColor));
1549     glLightfv(lightno, GL_DIFFUSE, (GLfloat *)&(l->diffuseLightColor));
1550     glLightfv(lightno, GL_SPECULAR, (GLfloat *)&(l->specularLightColor));
1551 
1552     memcpy(pos, &(l->lightXYZ), sizeof(RMvertex3D));
1553 
1554     if (l->ltype == RM_LIGHT_DIRECTIONAL)
1555 	pos[3] = 0.0F;
1556     else
1557 	pos[3] = 1.0F;
1558 
1559     glLightfv(lightno, GL_POSITION, pos);
1560 
1561     /* todo: spot parms, attenuation */
1562     if (l->ltype == RM_LIGHT_SPOT)
1563     {
1564 	glLightf(lightno, GL_SPOT_CUTOFF, l->spotCutoff);
1565 	glLightfv(lightno, GL_SPOT_DIRECTION, (float *)&(l->spotDirection));
1566 	glLightf(lightno, GL_SPOT_EXPONENT, l->spotExponent);
1567     }
1568 
1569     glLightf(lightno, GL_CONSTANT_ATTENUATION, l->constantAttenuation);
1570     glLightf(lightno, GL_LINEAR_ATTENUATION, l->linearAttenuation);
1571     glLightf(lightno, GL_QUADRATIC_ATTENUATION, l->quadraticAttenuation);
1572 }
1573 
1574 
1575 /* PRIVATE
1576  *
1577  * process_scene_lights: an internal routine used to activate OpenGL
1578  * lights given RM-style light source scene parameters.
1579  */
1580 int
process_scene_lights(const RMnode * r,int push_attrib_enable,RMstate * s,RMenum applyGL,RMstateCache * rsc)1581 process_scene_lights (const RMnode *r,
1582 		      int push_attrib_enable,
1583 		      RMstate *s,
1584 		      RMenum applyGL,
1585 		      RMstateCache *rsc)
1586 {
1587     int i;
1588 
1589     /*
1590      * 8/8/04 - if we're doing a 2D render traversal, skip doing the
1591      * lights.
1592      */
1593     if ((s->renderPassDims == RM_RENDERPASS_2D) ||
1594 	(r->scene_parms == NULL))
1595 	return 0;
1596 
1597     /* we assume that r->scene_parms is valid. */
1598     for (i = 0; i < RM_MAX_LIGHTS; i++)
1599     {
1600 	RMlight *l = r->scene_parms->lightSources[i];
1601 	if ((l != NULL) && (l->enabled == RM_TRUE))
1602 	{
1603 	    if (applyGL == RM_TRUE)
1604 	    {
1605 		/* 8/8/04 - do a conditional activation to reduce the number
1606 		 of redundant state changes. */
1607 		if (s->lightingActive != RM_TRUE)
1608 		    glEnable(GL_LIGHTING);
1609 
1610 		s->lightingActive = RM_TRUE;
1611 		if (rsc != NULL)
1612 		    rsc->lightingActive = RM_TRUE;
1613 
1614 		dumplight(GL_LIGHT0 + i, l);
1615 	    }
1616 	    /* now update the render state. */
1617 	    s->lightSources[i] = l;
1618 	}
1619     }
1620 
1621     if (r->scene_parms->lmodel != NULL)
1622     {
1623 	int           localview;
1624 	int           twoside;
1625 	RMlightModel *lm = r->scene_parms->lmodel;
1626 
1627 	localview = (lm->localViewerEnable == RM_TRUE) ? 1 : 0;
1628 	twoside = (lm->twoSideEnable == RM_TRUE) ? 1 : 0;
1629 
1630 	if (applyGL == RM_TRUE)
1631 	{
1632 	    glLightModelfv (GL_LIGHT_MODEL_AMBIENT, (GLfloat *)&(lm->globalAmbient));
1633 	    glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, localview);
1634 	    glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, twoside);
1635 	}
1636 
1637 	/* update the render state */
1638 	s->lmodel = lm;
1639     }
1640     return(push_attrib_enable);
1641 }
1642 
1643 
1644 /* PRIVATE
1645  *
1646  * private_setBackgroundTile - an internal routine that draws a
1647  * background image into the framebuffer. if the image is smaller than
1648  * the viewport, it is tiled across the entire viewport, starting at
1649  * the upper-left corner of the window. if the tile does not evenly
1650  * fill the viewport, the "ragged" edges are on the right and bottom
1651  * of the viewport.
1652  */
1653 int
private_setBackgroundTile(const internals_RMfbClear * fbClear,RMstate * s,int push_attrib_enable,RMenum applyGL)1654 private_setBackgroundTile (const internals_RMfbClear *fbClear,
1655 			   RMstate *s,
1656 			   int push_attrib_enable,
1657 			   RMenum applyGL)
1658 {
1659     int      dwidth, dheight, tiles_across, tiles_high, i, j, dx, dy;
1660     float    xzoom, yzoom;
1661     GLint    save_viewport[4];
1662     RMimage *tile;
1663 
1664     if (applyGL == RM_FALSE)
1665 	return 0;
1666 
1667     /*
1668      * todo: GL_ALL_ATTRIB_BITS is clearly overkill; find a smaller mask.
1669      */
1670     glPushAttrib(GL_ALL_ATTRIB_BITS);
1671 
1672     dwidth = s->vp[2]; /* pixels across in viewport */
1673     dheight = s->vp[3]; /* pixels high in viewport */
1674 
1675     tile = fbClear->bgImageTile;
1676     rmImageGetPixelZoom(tile, &xzoom, &yzoom);
1677 
1678     dx = tile->w * xzoom;
1679     dy = tile->h * yzoom;
1680 
1681     tiles_across = dwidth / dx;
1682     tiles_high = dheight / dy;
1683 
1684     if (dheight % dy != 0)
1685 	tiles_high++;
1686 
1687     if (dwidth % dx != 0)
1688 	tiles_across++;
1689 
1690     /*
1691      * first, tile the viewport with the image
1692      *
1693      * steps we have to take to make this happen:
1694      * 1. turn off lighting
1695      * 2. establish the appropriate camera, preserving whatever is
1696      *    on the projection matrix stack.
1697      * 3. create identity transform, preserving whatever is on the
1698      *    modelview matrix stack.
1699      * 4. draw the tile a bunch of times.
1700      * 5. restore the saved matrices.
1701      *
1702      * TODO: only do one drawpixels. the rest can be done more
1703      * efficiently with copypixels. performance degrades as the size
1704      * of the image tile gets smaller.
1705      *
1706      * June 2005: ToDO: alternate: reinstate pre-multistage display lists
1707      */
1708     glDisable(GL_LIGHTING);
1709     glDisable(GL_DEPTH_TEST);
1710 
1711     /*
1712      * don't need to set state in RMstate object because we are
1713      * pushing/popping the OpenGL state inside this routine.
1714      */
1715 
1716     glGetIntegerv(GL_VIEWPORT, save_viewport);
1717 
1718     glMatrixMode(GL_MODELVIEW);
1719     glPushMatrix();
1720     glLoadIdentity();
1721 
1722     glMatrixMode(GL_PROJECTION);
1723     glLoadIdentity();
1724 
1725     glOrtho(0.0, (double)save_viewport[2], 0.0, (double)save_viewport[3], -1.0, 1.0);
1726 
1727     glPixelZoom(xzoom, yzoom);
1728     {
1729 	int ix, iy = 0;
1730 
1731 	for (j = 0; j < tiles_high; j++)
1732 	{
1733 	    for (i = 0, ix = 0; i < tiles_across; i++, ix += dx)
1734 	    {
1735 		glRasterPos2i(ix, iy);
1736 #if 0
1737     /* 10/5/2000 all RMimage display list stuff removed during SBIR work */
1738 
1739 		glCallList(tile->d1);
1740 
1741 		/*
1742 		 * this hunk of code was left in so that we can play
1743 		 * around w/ testing of display lists for bg image tiles
1744 		 * and compare w/raw drawpixels calls.
1745 		 */
1746 
1747 		glDrawPixels(tile->w, tile->h, private_rmImageGetOGLFormat(tile), private_rmImageGetOGLType(tile), rmImageGetPixelData(tile));
1748 #endif
1749 		private_glDrawPixels(tile->w, tile->h, private_rmImageGetOGLFormat(tile), private_rmImageGetOGLType(tile), private_rmImageGetPixelData(tile), tile);
1750 
1751 	    }
1752 	    iy += dy;
1753 	}
1754     }
1755 
1756     /* restore matrices */
1757     glMatrixMode(GL_MODELVIEW);
1758     glPopMatrix();
1759 
1760     glMatrixMode(GL_PROJECTION);
1761     glLoadMatrixf((float *)&(s->projection.m[0][0]));
1762 
1763     glPopAttrib();
1764 
1765     return(push_attrib_enable);
1766 }
1767 
1768 
1769 /* PRIVATE
1770  *
1771  * private_setBackgroundColor - an internal routine used to perform a
1772  * framebuffer clear using a background color scene parameter.
1773  */
1774 int
private_setBackgroundColor(const internals_RMfbClear * fbClear,RMstate * s,int push_attrib_enable,RMenum applyGL)1775 private_setBackgroundColor (const internals_RMfbClear *fbClear,
1776 			    RMstate *s,
1777 			    int push_attrib_enable,
1778 			    RMenum applyGL)
1779 {
1780     GLclampf red, g, b, a;
1781 
1782     s = NULL; 			/* foil compiler warning */
1783     /* future: update RMstate to indicate the current background color */
1784 
1785     red = fbClear->bgColor->r;
1786     g = fbClear->bgColor->g;
1787     b = fbClear->bgColor->b;
1788     a = fbClear->bgColor->a;
1789 
1790     if (applyGL == RM_TRUE)
1791     {
1792 	glClearColor(red, g, b, a);
1793 	glClear(GL_COLOR_BUFFER_BIT);
1794     }
1795 
1796     /* no changes to RMstate at this time - maybe in the future we'll add background color & tile to the RMstate */
1797     return(push_attrib_enable);
1798 }
1799 
1800 
1801 /* PRIVATE
1802  *
1803  * private_setBackgroundDepthImage - internal routine used to tile the
1804  * depth buffer with a depth image. if the source image is smaller than
1805  * the viewport, the source image is tiled across the depth buffer starting
1806  * at the upper left corner of the viewport. if the source image does not
1807  * evenly divide the viewport, the ragged edges are on the right and bottom.
1808  */
1809 int
private_setBackgroundDepthImage(const internals_RMfbClear * fbClear,RMstate * s,int push_attrib_enable,RMenum applyGL)1810 private_setBackgroundDepthImage (const internals_RMfbClear *fbClear,
1811 				 RMstate *s,
1812 				 int push_attrib_enable,
1813 				 RMenum applyGL)
1814 {
1815     int      dwidth, dheight, tiles_across, tiles_high, i, j, dx, dy;
1816     float    xzoom, yzoom;
1817     GLint save_viewport[4];
1818     RMimage *tile;
1819 
1820     if (applyGL == RM_FALSE)
1821 	return 0;
1822 
1823     glPushAttrib(GL_ALL_ATTRIB_BITS);
1824 
1825     glGetIntegerv(GL_VIEWPORT, save_viewport);
1826 
1827     glMatrixMode(GL_MODELVIEW);
1828     glLoadIdentity();
1829     glMatrixMode(GL_PROJECTION);
1830     glLoadIdentity();
1831 
1832     glEnable(GL_DEPTH_TEST);
1833     glDisable(GL_LIGHTING);
1834     glDepthMask(GL_TRUE);
1835     glDepthFunc(GL_ALWAYS);
1836 
1837     /* disable color mask - so depth image doesn't get
1838        written to the color buffer! */
1839     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1840 
1841     tile = fbClear->depthImage;
1842 
1843     rmImageGetPixelZoom(tile, &xzoom, &yzoom);
1844     glPixelZoom(xzoom, yzoom);
1845 
1846     dx = tile->w * xzoom;
1847     dy = tile->h * yzoom;
1848 
1849     dwidth = s->vp[2] - s->vp[0]; /* pixels across in viewport */
1850     dheight = s->vp[3] - s->vp[1]; /* pixels high in viewport */
1851 
1852     glOrtho((GLdouble)(s->vp[0]), (GLdouble)(s->vp[2]), (GLdouble)(s->vp[1]), (GLdouble)(s->vp[3]), -1.0, 1.0);
1853 
1854     tiles_across = dwidth / dx;
1855     tiles_high = dheight / dy;
1856 
1857     if (dheight % dy != 0)
1858 	tiles_high++;
1859     if (dwidth % dx != 0)
1860 	tiles_across++;
1861 #if 0
1862     /* 10/5/2000 - all RMimage display list code removed for SBIR work */
1863     if (tile->d1 == -1)
1864     {
1865 	float *p, t;		/* temp */
1866 
1867 	tile->d1 = glGenLists(1);
1868 	glNewList(tile->d1, GL_COMPILE);
1869 
1870 	p = (float *)(tile->pixeldata);
1871 	t = *p;
1872 
1873 	private_glDrawPixels(tile->w, tile->h, private_rmImageGetOGLFormat(tile), private_rmImageGetOGLType(tile), private_rmImageGetPixelData(tile), tile);
1874 	glEndList();
1875     }
1876 #endif
1877 
1878     {
1879 	int ix, iy = 0;
1880 
1881 	for (j = 0; j < tiles_high; j++)
1882 	{
1883 	    for (i = 0, ix = 0; i < tiles_across; i++, ix += dx)
1884 	    {
1885 		glRasterPos3i(ix, iy, 0);
1886 #if 0
1887 		/* 10/5/2000 - all RMimage display list code removed, SBIR */
1888 		glCallList(tile->d1);
1889 		/*
1890 		 * this hunk of code was left in so that we can play
1891 		 * around w/ testing of display lists for bgimage tiles
1892 		 * and compare w/raw drawpixels calls.
1893 		 */
1894 
1895 		glDrawPixels(private_rmImageGetWidth(tile), private_rmImageGetHeight(tile), private_rmImageGetOGLFormat(tile), private_rmImageGetOGLType(tile), rmImageGetPixelData(tile));
1896 #endif
1897 		private_glDrawPixels(tile->w, tile->h, private_rmImageGetOGLFormat(tile), private_rmImageGetOGLType(tile), private_rmImageGetPixelData(tile), tile);
1898 
1899 	    }
1900 	    iy += dy;
1901 	}
1902     }
1903 
1904     /* restore matrices */
1905     glMatrixMode(GL_MODELVIEW);
1906     glLoadMatrixf((float *)&(s->modelView.m[0][0]));
1907 
1908     glMatrixMode(GL_PROJECTION);
1909     glLoadMatrixf((float *)&(s->projection.m[0][0]));
1910 
1911     glPopAttrib();
1912 
1913     return(push_attrib_enable);
1914 }
1915 
1916 
1917 /* PRIVATE
1918  *
1919  * private_setFog() - an internal routine used to activate OpenGL fogging
1920  * given RM-style scene parameters.
1921  */
1922 int
private_setFog(const RMnode * r,int push_attrib_enable,RMstate * rState,RMenum applyGL)1923 private_setFog (const RMnode *r,
1924 	        int push_attrib_enable,
1925 	        RMstate *rState,
1926 	        RMenum applyGL)
1927 {
1928     if (r->scene_parms == NULL)
1929 	return 0;
1930 
1931     if (r->scene_parms->fog)
1932     {
1933 	if (applyGL == RM_TRUE)
1934 	{
1935 	    RMfog *f;
1936 
1937 	    f = r->scene_parms->fog;
1938 
1939 	    glEnable(GL_FOG);
1940 	    glFogi(GL_FOG_MODE, f->fogMode);
1941 
1942 	    if (f->fogMode == GL_LINEAR)
1943 	    {
1944 		glFogf(GL_FOG_START, f->fogStart);
1945 		glFogf(GL_FOG_END, f->fogEnd);
1946 	    }
1947 	    else
1948 		glFogf(GL_FOG_DENSITY, f->fogDensity);
1949 
1950 	    glFogfv(GL_FOG_COLOR, (GLfloat *)&(f->fogColor));
1951 
1952 	    rState->fog = *(r->scene_parms->fog);
1953 	    rState->fogActive = RM_TRUE;
1954 
1955 	    /* temp */
1956 /*	    glHint(GL_FOG_HINT, GL_NICEST); */
1957 	}
1958     }
1959 
1960     return(push_attrib_enable);
1961 }
1962 
1963 
1964 /* PRIVATE
1965  *
1966  * private_setClipPlanes() - internal routine used to map from RM scene
1967  * parameters to OpenGL style clipping planes.
1968  */
1969 int
private_setClipPlanes(const RMnode * r,int push_attrib_enable,RMstate * rState,RMenum applyGL)1970 private_setClipPlanes (const RMnode *r,
1971 		       int push_attrib_enable,
1972 		       RMstate *rState,
1973 		       RMenum applyGL)
1974 {
1975     if (r->scene_parms == NULL)
1976 	return 0;
1977 
1978     if ((r->scene_parms->cp0) && (rmClipPlaneIsEnabled(r->scene_parms->cp0)))
1979     {
1980 	GLdouble eq[4];
1981 
1982 	if (applyGL == RM_TRUE)
1983 	{
1984 	    eq[0] = r->scene_parms->cp0->a;
1985 	    eq[1] = r->scene_parms->cp0->b;
1986 	    eq[2] = r->scene_parms->cp0->c;
1987 	    eq[3] = r->scene_parms->cp0->d;
1988 	    glClipPlane(GL_CLIP_PLANE0, eq);
1989 	    glEnable(GL_CLIP_PLANE0);
1990 	}
1991 	rState->cp0 = r->scene_parms->cp0;
1992     }
1993 
1994     if ((r->scene_parms->cp1) && (rmClipPlaneIsEnabled(r->scene_parms->cp1)))
1995     {
1996         GLdouble eq[4];
1997 
1998 	if (applyGL == RM_TRUE)
1999 	{
2000 	    eq[0] = r->scene_parms->cp1->a;
2001 	    eq[1] = r->scene_parms->cp1->b;
2002 	    eq[2] = r->scene_parms->cp1->c;
2003 	    eq[3] = r->scene_parms->cp1->d;
2004 	    glClipPlane(GL_CLIP_PLANE1, eq);
2005 	    glEnable(GL_CLIP_PLANE1);
2006 	}
2007 	rState->cp1 = r->scene_parms->cp1;
2008     }
2009 
2010     if ((r->scene_parms->cp2) && (rmClipPlaneIsEnabled(r->scene_parms->cp2)))
2011     {
2012         GLdouble eq[4];
2013 
2014 	if (applyGL == RM_TRUE)
2015 	{
2016 	    eq[0] = r->scene_parms->cp2->a;
2017 	    eq[1] = r->scene_parms->cp2->b;
2018 	    eq[2] = r->scene_parms->cp2->c;
2019 	    eq[3] = r->scene_parms->cp2->d;
2020 	    glClipPlane(GL_CLIP_PLANE2, eq);
2021 	    glEnable(GL_CLIP_PLANE2);
2022 	}
2023 	rState->cp2 = r->scene_parms->cp2;
2024     }
2025 
2026     if ((r->scene_parms->cp3) && (rmClipPlaneIsEnabled(r->scene_parms->cp3)))
2027     {
2028         GLdouble eq[4];
2029 
2030 	if (applyGL == RM_TRUE)
2031 	{
2032 	    eq[0] = r->scene_parms->cp3->a;
2033 	    eq[1] = r->scene_parms->cp3->b;
2034 	    eq[2] = r->scene_parms->cp3->c;
2035 	    eq[3] = r->scene_parms->cp3->d;
2036 	    glClipPlane(GL_CLIP_PLANE3, eq);
2037 	    glEnable(GL_CLIP_PLANE3);
2038 	}
2039 	rState->cp3 = r->scene_parms->cp3;
2040     }
2041 
2042     if ((r->scene_parms->cp4) && (rmClipPlaneIsEnabled(r->scene_parms->cp4)))
2043     {
2044         GLdouble eq[4];
2045 
2046 	if (applyGL == RM_TRUE)
2047 	{
2048 	    eq[0] = r->scene_parms->cp4->a;
2049 	    eq[1] = r->scene_parms->cp4->b;
2050 	    eq[2] = r->scene_parms->cp4->c;
2051 	    eq[3] = r->scene_parms->cp4->d;
2052 	    glClipPlane(GL_CLIP_PLANE4, eq);
2053 	    glEnable(GL_CLIP_PLANE4);
2054 	}
2055 	rState->cp4 = r->scene_parms->cp4;
2056     }
2057 
2058     if ((r->scene_parms->cp5) && (rmClipPlaneIsEnabled(r->scene_parms->cp5)))
2059     {
2060         GLdouble eq[4];
2061 
2062 	if (applyGL == RM_TRUE)
2063 	{
2064 	    eq[0] = r->scene_parms->cp5->a;
2065 	    eq[1] = r->scene_parms->cp5->b;
2066 	    eq[2] = r->scene_parms->cp5->c;
2067 	    eq[3] = r->scene_parms->cp5->d;
2068 	    glClipPlane(GL_CLIP_PLANE5, eq);
2069 	    glEnable(GL_CLIP_PLANE5);
2070 	}
2071 	rState->cp5 = r->scene_parms->cp5;
2072     }
2073     return(push_attrib_enable);
2074 }
2075 
2076 
2077 /* PRIVATE
2078  *
2079  * private_setSurfaceProps - internal routine used to set current surface
2080  * reflectance properties given RMnode material properties.
2081  */
2082 int
private_setSurfaceProps(const RMnode * r,int push_attrib_enable,RMstate * s,RMenum applyGL)2083 private_setSurfaceProps (const RMnode *r,
2084 			 int push_attrib_enable,
2085 			 RMstate *s,
2086 			 RMenum applyGL)
2087 {
2088     /* we assume that r->sprops is defined */
2089 #define RM_WHICHFACE GL_FRONT_AND_BACK
2090 
2091     if (r->sprops->ambient_color != NULL)
2092     {
2093 	if (applyGL == RM_TRUE)
2094 	    glMaterialfv(RM_WHICHFACE, GL_AMBIENT, (GLfloat *)(r->sprops->ambient_color));
2095 	s->ambient = *(r->sprops->ambient_color);
2096     }
2097 
2098     if (r->sprops->diffuse_color != NULL)
2099     {
2100 	if (applyGL == RM_TRUE)
2101 	    glMaterialfv(RM_WHICHFACE,GL_DIFFUSE, (GLfloat *)(r->sprops->diffuse_color));
2102 	s->diffuse = *(r->sprops->diffuse_color);
2103     }
2104 
2105     if (r->sprops->specular_color != NULL)
2106     {
2107 	if (applyGL == RM_TRUE)
2108 	    glMaterialfv(RM_WHICHFACE,GL_SPECULAR, (GLfloat *)(r->sprops->specular_color));
2109 	s->specular = *(r->sprops->specular_color);
2110     }
2111 
2112     if (r->sprops->unlit_color != NULL)
2113     {
2114 	/* use the unlit color for the diffuse property iff the diffuse property isn't already defined */
2115 
2116 	if (r->sprops->diffuse_color == NULL && applyGL == RM_TRUE)
2117 	    glMaterialfv(RM_WHICHFACE, GL_DIFFUSE, (GLfloat *)(r->sprops->unlit_color));
2118 
2119 	/* just copy it into the render state struct */
2120 	s->unlit_color = *(r->sprops->unlit_color);
2121 	glColor4fv((GLfloat *)&(s->unlit_color));
2122     }
2123 
2124     if (r->sprops->specular_exponent != NULL)
2125     {
2126 	float f;
2127 
2128 	rmNodeGetSpecularExponent(r,&f);
2129 	s->specular_exponent = f;
2130 
2131 	if (applyGL == RM_TRUE)
2132 	    glMaterialf(RM_WHICHFACE, GL_SHININESS,f);
2133     }
2134     return(push_attrib_enable);
2135 }
2136 
2137 
2138 /* PRIVATE
2139  *
2140  * private_setRenderProps() - an internal routine used to set the current
2141  * shademodel, establish front-face definitions, polygon fill mode,
2142  * line width and dashing style, point-size, and current cull mode.
2143  */
2144 int
private_setRenderProps(const RMnode * r,int push_attrib_enable,RMstate * s,RMenum applyGL,RMstateCache * rsc)2145 private_setRenderProps (const RMnode *r,
2146 		        int push_attrib_enable,
2147 		        RMstate *s,
2148 		        RMenum applyGL,
2149 			RMstateCache *rsc)
2150 {
2151     if (r->rprops->normalizeNormals)
2152     {
2153 	if (*(r->rprops->normalizeNormals) == RM_TRUE)
2154 	    glEnable(GL_NORMALIZE);
2155     }
2156 
2157     if (r->rprops->shademodel)
2158     {
2159 	if (applyGL == RM_TRUE)
2160 	{
2161 	   switch(*(r->rprops->shademodel))
2162 	       {
2163 	       case RM_SHADER_SMOOTH:
2164 		   glShadeModel(GL_SMOOTH);
2165 		   break;
2166 
2167 	       case RM_SHADER_FLAT:
2168 		   glShadeModel(GL_FLAT);
2169 		   break;
2170 
2171 	       case RM_SHADER_NOLIGHT:
2172 		   glShadeModel(GL_FLAT);
2173 		   glDisable(GL_LIGHTING);
2174 		   s->lightingActive = RM_FALSE;
2175 		   if (rsc != NULL)
2176 		       rsc->lightingActive = RM_FALSE;
2177 		   break;
2178 
2179 	       default:
2180 		   /* ? */
2181 		   break;
2182 	    }
2183 	}
2184 	s->shademodel = *(r->rprops->shademodel);
2185     }
2186 
2187     if (r->rprops->front_face)
2188     {
2189 	if (applyGL == RM_TRUE)
2190 	{
2191 	   switch (*(r->rprops->front_face))
2192 	       {
2193 	       case RM_CCW:
2194 		   glFrontFace(GL_CCW);
2195 		   break;
2196 
2197 	       case RM_CW:
2198 		   glFrontFace(GL_CW);
2199 		   break;
2200 
2201 	       default:
2202 		   /* ? */
2203 		   break;
2204 	       }
2205 	}
2206 	s->front_face = *(r->rprops->front_face);
2207     }
2208 
2209     /* both the following must be defined */
2210     if (r->rprops->poly_mode_face && r->rprops->poly_mode_drawstyle)
2211     {
2212 	int face, mode;
2213 
2214 	switch (*(r->rprops->poly_mode_face))
2215 	    {
2216 	    case RM_FRONT:
2217 	        face = GL_FRONT;
2218 	        break;
2219 
2220 	    case RM_BACK:
2221 	        face = GL_BACK;
2222 	        break;
2223 
2224 	    case RM_FRONT_AND_BACK:
2225 	        face = GL_FRONT_AND_BACK;
2226 	        break;
2227 
2228 	    default:
2229 	        face = GL_FRONT_AND_BACK;
2230 	        break;
2231 	    }
2232 
2233 	switch (*(r->rprops->poly_mode_drawstyle))
2234 	    {
2235 	    case RM_POINT:
2236 	        mode = GL_POINT;
2237 	        break;
2238 
2239 	    case RM_LINE:
2240 	        mode = GL_LINE;
2241 	        break;
2242 
2243 	    case RM_FILL:
2244 	    default:
2245 	        mode = GL_FILL;
2246 	        break;
2247 	    }
2248 
2249 	if (applyGL == RM_TRUE)
2250 	    glPolygonMode(face,mode);
2251 
2252 	s->poly_mode_face = *(r->rprops->poly_mode_face);
2253 	s->poly_mode_drawstyle = *(r->rprops->poly_mode_drawstyle);
2254     }
2255 
2256     if (r->rprops->linewidth)
2257     {
2258 	int indx;
2259 	extern RMLinewidthEnum rmlinewidths[];
2260 
2261 	s->linewidth = *(r->rprops->linewidth);
2262 	indx = private_rmLinewidthToIndex(s->linewidth);
2263 
2264 	if (applyGL == RM_TRUE)
2265 	    glLineWidth(rmlinewidths[indx].width);
2266     }
2267 
2268     if (r->rprops->linestyle)
2269     {
2270 	int                    indx;
2271 	GLint                  factor;
2272 	GLushort               pattern;
2273 	extern RMLinestyleEnum rmlinestyles[];
2274 
2275 	s->linestyle = *(r->rprops->linestyle);
2276 
2277 	/* convert from an enumerator to an index */
2278 	indx = private_rmLinestyleToIndex(s->linestyle);
2279 
2280 	factor = rmlinestyles[indx].ogl_factor;
2281 	pattern = rmlinestyles[indx].ogl_pattern;
2282 
2283 	if (applyGL == RM_TRUE)
2284 	{
2285 	    if (s->linestyle == RM_LINES_SOLID)
2286 		glDisable(GL_LINE_STIPPLE);
2287 	    else
2288 	    {
2289 		glLineStipple(factor, pattern);
2290 		glEnable(GL_LINE_STIPPLE);
2291 	    }
2292 	}
2293     }
2294 
2295     if (r->rprops->pointsize)
2296     {
2297 	if (applyGL == RM_TRUE)
2298 	    glPointSize((GLfloat)*(r->rprops->pointsize));
2299 	s->pointsize = *(r->rprops->pointsize);
2300     }
2301 
2302     if (r->rprops->cull_mode)
2303     {
2304 	if (applyGL == RM_TRUE)
2305 	{
2306 	   switch (*(r->rprops->cull_mode))
2307 	       {
2308 	       case RM_CULL_FRONT:
2309 		   glEnable(GL_CULL_FACE);
2310 		   glCullFace(GL_FRONT);
2311 		   break;
2312 
2313 	       case RM_CULL_BACK:
2314 		   glEnable(GL_CULL_FACE);
2315 		   glCullFace(GL_BACK);
2316 		   break;
2317 
2318 	       case RM_CULL_FRONT_AND_BACK:
2319 		   glEnable(GL_CULL_FACE);
2320 		   glCullFace(GL_FRONT_AND_BACK);
2321 		   break;
2322 
2323 	       case RM_CULL_NONE:
2324 		   glDisable(GL_CULL_FACE);
2325 		   break;
2326 
2327 	       default:
2328 		   /* ? */
2329 		   break;
2330 	       }
2331 	}
2332 	s->cull_mode = *(r->rprops->cull_mode);
2333     }
2334     return(push_attrib_enable);
2335 }
2336 
2337 
2338 /* PRIVATE
2339  *
2340  * private_rmPostRender() - internal routine called after frame rendering
2341  * has occured. if we're here, we assume that the application has attached
2342  * a post-rendering callback to the pipe, so we'll read the framebuffer
2343  * into an RMimage object, invoke the application callback with the
2344  * framebuffer contents as a parameter, then free the temp RMimage upon
2345  * return from the app callback.
2346  */
2347 void
private_rmPostRender(int whichbuffer_enum,RMpipe * p)2348 private_rmPostRender (int whichbuffer_enum,
2349 		      RMpipe *p)
2350 {
2351     /* if we're here, assume that p->postrenderfunc != NULL */
2352     unsigned char *pixelbuf;
2353     int            w, h;
2354     RMimage       *img;
2355     RMenum	   channel;
2356 
2357     /* get the image dims */
2358     rmPipeGetWindowSize(p, &w, &h);
2359 
2360     /* malloc an rmImage */
2361     img = rmImageNew(2, w, h, 1, RM_IMAGE_RGB, RM_UNSIGNED_BYTE, RM_COPY_DATA);
2362 
2363     pixelbuf = rmImageGetPixelData(img);
2364 
2365     /* call the internal routine to read the framebuffer */
2366     glReadBuffer(whichbuffer_enum);
2367     private_rmReadBytePixels(pixelbuf, w, h, private_rmImageGetElements(img), GL_RGB, private_rmImageGetBytesPerScanline(img));
2368 
2369     /* call the user function */
2370     switch (whichbuffer_enum)
2371         {
2372         case GL_BACK:
2373 	    channel = RM_ALL_CHANNELS;
2374 	    break;
2375 
2376         case GL_BACK_LEFT:
2377         case GL_FRONT_LEFT:
2378 	    channel = RM_LEFT_CHANNEL;
2379 	    break;
2380 
2381         case GL_BACK_RIGHT:
2382         case GL_FRONT_RIGHT:
2383 	    channel = RM_RIGHT_CHANNEL;
2384 	    break;
2385 
2386         default: /* bogus buffer? */
2387 	    channel = RM_ALL_CHANNELS;
2388 	    break;
2389         }
2390     (*p->postrenderfunc)(img, channel);
2391 
2392     /* free the local memory */
2393     rmImageDelete(img);
2394 }
2395 
2396 
2397 /* PRIVATE
2398  *
2399  * private_rmPostRenderDepthBuffer() - internal routine called after frame
2400  * rendering has occured. if we're here, we assume that the application
2401  * has attached a post-rendering callback to the pipe, so we'll read the DEPTH
2402  * buffer into an RMimage object, invoke the application callback with the
2403  * framebuffer contents as a parameter, then free the temp RMimage upon
2404  * return from the app callback.
2405  */
2406 void
private_rmPostRenderDepthBuffer(GLenum whichbuffer_enum,RMpipe * p)2407 private_rmPostRenderDepthBuffer (GLenum whichbuffer_enum,
2408 				 RMpipe *p)
2409 {
2410     /* if we're here, assume that p->postrenderfunc != NULL */
2411     int       w, h;
2412     float    *pixelbuf;
2413     RMimage  *img;
2414     RMenum    rm_enum;
2415 
2416     /* get the image dims */
2417     rmPipeGetWindowSize(p, &w, &h);
2418 
2419     /* malloc an rmImage */
2420     img = rmImageNew(2, w, h, 1, RM_IMAGE_DEPTH, RM_FLOAT, RM_COPY_DATA);
2421 
2422     pixelbuf = rmImageGetPixelData(img);
2423 
2424     /* call the internal routine to read the framebuffer */
2425     glReadBuffer(whichbuffer_enum);
2426 
2427     /* need to determine this programmatically - it probably varies as a function of implementation */
2428     glPixelTransferf(GL_DEPTH_SCALE, 1.0001F);
2429 
2430     private_rmReadFloatPixels(pixelbuf, w, h, private_rmImageGetElements(img), GL_DEPTH_COMPONENT);
2431 
2432     glPixelTransferf(GL_DEPTH_SCALE, 1.0F);
2433 
2434     /* call the user function */
2435     switch (whichbuffer_enum)
2436         {
2437         case GL_BACK_LEFT:
2438         case GL_FRONT_LEFT:
2439 	    rm_enum = RM_LEFT_CHANNEL;
2440 	    break;
2441 
2442         case GL_BACK_RIGHT:
2443         case GL_FRONT_RIGHT:
2444 	    rm_enum = RM_RIGHT_CHANNEL;
2445 	    break;
2446 
2447         case GL_BACK:
2448         default:
2449 	    rm_enum = RM_ALL_CHANNELS;
2450 	    break;
2451         }
2452     (*p->postrender_depthbufferfunc)(img, rm_enum);
2453 
2454     /* free the local memory */
2455     rmImageDelete(img);
2456 }
2457 
2458 
2459 /* PRIVATE
2460  *
2461  * private_setBackgroundDepthValue -  internal routine that clears the
2462  * depth buffer, activated by the presence of a depth value scene parameter.
2463  */
2464 int
private_setBackgroundDepthValue(const internals_RMfbClear * fbClear,RMstate * rState,RMenum applyGL)2465 private_setBackgroundDepthValue (const internals_RMfbClear *fbClear,
2466 				 RMstate *rState,
2467 				 RMenum applyGL)
2468 {
2469     GLclampd d;
2470 
2471     /* future: update RMstate to indicate background depth value */
2472     rState = NULL;		/* foil compiler warning */
2473 
2474     /* at the present time, we ignore push_attrib_enable and the render state */
2475     if (applyGL == RM_TRUE)
2476     {
2477 	d = *(fbClear->depthValue);
2478 
2479 	glClearDepth(d);
2480 	glClear(GL_DEPTH_BUFFER_BIT);
2481     }
2482     return(0);			/* return value ignored */
2483 }
2484 
2485 /*
2486  * PRIVATE
2487  */
2488 int
private_manageTextureState(RMtexture * t,RMstate * rState,RMpipe * p,int applyGL,int textureUnitIndex)2489 private_manageTextureState(RMtexture *t,
2490 			   RMstate *rState,
2491 			   RMpipe *p,
2492 			   int applyGL,
2493 			   int textureUnitIndex)
2494 {
2495     RMcacheKey oldTextureIDKey, oldTextureDataKey;
2496     RMcacheKey pipeIDKey, pipeDataKey;
2497     int compListIndx;
2498     GLuint textureName;
2499     int haveNewTexture=0, haveNewData=0;
2500 
2501     /*
2502      * first, compare the texture ID cache key with that in the
2503      * RMpipe. if they differ, we need to generate a new texture.
2504      * we won't need to generate a new OpenGL texture except during
2505      * the first encounter with an RMtexture (render-time download,
2506      * possible overridden by pre-rendering texture loads - to be
2507      * implemented in the future) or when the app deletes then replaces
2508      * an RMtexture scene parameter. the latter case will rarely happen.
2509      */
2510 
2511     if (applyGL == RM_FALSE)
2512 	return 1;
2513 
2514     /* first check to see if we're using an app-supplied texture ID. if so,
2515        just activate texturing and return. */
2516     if (t->appTextureID != NULL)
2517     {
2518 #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK)
2519 	if (glIsTexture(*(t->appTextureID) == GL_FALSE))
2520 	    printf("app supplied textureID is not a valid OpenGL texture. \n");
2521 	else
2522 	    printf("app supplied textureID is OK \n");
2523 #endif
2524 
2525 	if (private_rmTextureGetDims(t) == 2)
2526 	{
2527 	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, t->wrap_mode);
2528 	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, t->wrap_mode);
2529 
2530 	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
2531 	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
2532 
2533 	    glEnable(GL_TEXTURE_2D);
2534 	    glBindTexture(GL_TEXTURE_2D,*(t->appTextureID));
2535 	    rState->texture_mode = GL_TEXTURE_2D;
2536 	}
2537 	else if (private_rmTextureGetDims(t) == 3)
2538 	{
2539 	    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, t->wrap_mode);
2540 	    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, t->wrap_mode);
2541 	    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, t->wrap_mode);
2542 
2543 	    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
2544 	    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
2545 
2546 	    glEnable(GL_TEXTURE_3D);
2547 	    glBindTexture(GL_TEXTURE_3D, *(t->appTextureID));
2548 	    rState->texture_mode = GL_TEXTURE_3D;
2549 	}
2550 	else
2551 	{
2552 	    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, t->wrap_mode);
2553 	    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
2554 	    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
2555 
2556 	    glEnable(GL_TEXTURE_1D);
2557 	    glBindTexture(GL_TEXTURE_1D, *(t->appTextureID));
2558 	    rState->texture_mode = GL_TEXTURE_1D;
2559 	}
2560 
2561 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, t->envMode);
2562 	if (t->blendColor != NULL)
2563 	    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat *)(t->blendColor));
2564 	return 1;
2565     }
2566 
2567 
2568     oldTextureIDKey = private_rmTextureGetIDCacheKey(t);
2569     compListIndx = t->compListIndx;
2570 
2571     if (compListIndx >= p->contextCache->numTextureIDCacheKeys)
2572     {
2573 	int newSize;
2574 	int oldSize = p->contextCache->numTextureIDCacheKeys;
2575 	int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
2576 	int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
2577 
2578 	newSize = numNewPages * NUM_ITEMS_PER_PAGE;
2579 
2580 	p->contextCache->textureIDCacheKeys = (RMcacheKey *)realloc(p->contextCache->textureIDCacheKeys, newSize * sizeof(RMcacheKey));
2581 
2582 	/* initialize new stuff to -1 */
2583 	memset((void *)(p->contextCache->textureIDCacheKeys + oldSize), 0xFF,
2584 	       (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(RMcacheKey));
2585 
2586 	p->contextCache->numTextureIDCacheKeys = newSize;
2587 
2588 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
2589 	printf("private_manageTextureState() - reallocating contextCache->textureIDCacheKeys; oldSize = %d, newSize = %d \n", oldSize, newSize);
2590 #endif
2591     }
2592 
2593     pipeIDKey = p->contextCache->textureIDCacheKeys[compListIndx];
2594 
2595     if (oldTextureIDKey != pipeIDKey)
2596 	haveNewTexture = 1;
2597 
2598     if (haveNewTexture != 0)
2599     {
2600 	private_rmOGLTextureDelete(t,p);
2601 
2602 	glGenTextures(1,&textureName);
2603 	/* dispose of the old texture */
2604 
2605 	if (compListIndx >= p->contextCache->numTextureIDs)
2606 	{
2607 	    int newSize;
2608 	    int oldSize = p->contextCache->numTextureIDs;
2609 	    int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
2610 	    int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
2611 
2612 	    newSize = numNewPages * NUM_ITEMS_PER_PAGE;
2613 
2614 	    p->contextCache->textureIDs = (GLuint *)realloc(p->contextCache->textureIDs, newSize * sizeof(GLuint));
2615 
2616 	    /* initialize new stuff to -1 */
2617 	    memset((void *)(p->contextCache->textureIDs + oldSize), 0xFF,
2618 		   (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(GLuint));
2619 	    p->contextCache->numTextureIDs = newSize;
2620 
2621 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
2622 	    printf("private_manageTextureState() - reallocating contextCache->textureIDs; oldSize = %d, newSize = %d \n", oldSize, newSize);
2623 #endif
2624 	}
2625 
2626 	p->contextCache->textureIDs[compListIndx] = textureName;
2627 	p->contextCache->textureIDCacheKeys[compListIndx] = oldTextureIDKey;
2628     }
2629     else
2630 	textureName = p->contextCache->textureIDs[compListIndx];
2631 
2632     /*
2633      * check to see if the texture data needs to be pushed down
2634      * the gfx pipe. this condition depends upon two things: 1)
2635      * whether the textureData cache key inside the RMtexture is the
2636      * same as the textureData cache key inside the RMpipe, and 2)
2637      * if the "texture is resident."
2638      */
2639 
2640     if (compListIndx >= p->contextCache->numTextureDataCacheKeys)
2641     {
2642 	int newSize;
2643 	int oldSize = p->contextCache->numTextureDataCacheKeys;
2644 	int numNewPages = private_rmCacheComputeNumberNewPages(oldSize, NUM_ITEMS_PER_PAGE, compListIndx);
2645 	int numOldPages = oldSize/NUM_ITEMS_PER_PAGE;
2646 
2647 	newSize = numNewPages * NUM_ITEMS_PER_PAGE;
2648 
2649 	p->contextCache->textureDataCacheKeys = (RMcacheKey *)realloc(p->contextCache->textureDataCacheKeys, newSize * sizeof(RMcacheKey));
2650 
2651 	/* initialize new stuff to -1 */
2652 	memset((void *)(p->contextCache->textureDataCacheKeys + oldSize),
2653 	       0xFF, (numNewPages-numOldPages)*NUM_ITEMS_PER_PAGE*sizeof(RMcacheKey));
2654 	p->contextCache->numTextureDataCacheKeys = newSize;
2655 
2656 #if (DEBUG_LEVEL & DEBUG_REALLOC_TRACE)
2657 	printf("private_manageTextureState() - reallocating contextCache->textureDataCacheKeys; oldSize = %d, newSize = %d \n", oldSize, newSize);
2658 #endif
2659 
2660     }
2661 
2662     oldTextureDataKey = private_rmTextureGetDataCacheKey(t);
2663     pipeDataKey = p->contextCache->textureDataCacheKeys[compListIndx];
2664 
2665     if (oldTextureDataKey != pipeDataKey)
2666 	haveNewData = 1;
2667 
2668     /*
2669      * 11/11/04. if requested, activate multitexturing. Note that values
2670      * of textureUnitIndex between 0..RM_MAX_MULTITEXTURES-1 indicate
2671      * multitexturing, whereas a value of RM_MAX_MULTITEXTURES indicates
2672      * that we want "plain old texturing".
2673      */
2674     if (textureUnitIndex < RM_MAX_MULTITEXTURES)
2675     {
2676 	if (RM_ASSERT(p->caps, "private_manageTextureState error - the input RMpipe does not have a capabilities structure. Please file a bug report. Texturing will proceed using the non-multitextured code path.") == RM_WHACKED)
2677 	    textureUnitIndex = textureUnitIndex; /* compiler fodder */
2678 
2679 	else if (p->caps->haveMultiTexturing != RM_TRUE)
2680 
2681 	    rmWarning("private_manageTextureState warning - you have requested that an RMtexture be assigned to a multitexturing unit. However, it does not appear that the underlying OpenGL platform supports OpenGL. I will proceed, but the texture will be assigned to the regular OpenGL texturing unit. Rendering errors are likely to result. ");
2682 	else
2683 	    (*(p->caps->activeTextureARB))(GL_TEXTURE0_ARB + textureUnitIndex);
2684     }
2685 
2686     /*
2687      * enable texturing and bind the texture object.
2688      * update the RMstate to reflect that texturing is active.
2689      */
2690 
2691     if (private_rmTextureGetDims(t) == 2)
2692     {
2693 	glEnable(GL_TEXTURE_2D);
2694 	glBindTexture(GL_TEXTURE_2D,textureName);
2695 	rState->texture_mode = GL_TEXTURE_2D;
2696     }
2697     else if (private_rmTextureGetDims(t) == 3)
2698     {
2699 	glEnable(GL_TEXTURE_3D);
2700 	glBindTexture(GL_TEXTURE_3D, textureName);
2701 	rState->texture_mode = GL_TEXTURE_3D;
2702     }
2703     else
2704     {
2705 	glEnable(GL_TEXTURE_1D);
2706 	glBindTexture(GL_TEXTURE_1D, textureName);
2707 	rState->texture_mode = GL_TEXTURE_1D;
2708     }
2709 
2710     /*
2711      * set the texture environment attributes:
2712      * 1. the texture mode (GL_MODULATE, GL_DECAL, GL_BLEND, or GL_REPLACE)
2713      * 2. texture blend color, if present
2714      */
2715 /*    fprintf(stderr,"setting GL_TEXTURE_ENV_MODE to %0x \n", t->envMode); */
2716 
2717     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, t->envMode);
2718     if (t->blendColor != NULL)
2719 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat *)(t->blendColor));
2720 
2721     if (haveNewData != 0)
2722     {
2723 
2724 #if (DEBUG_LEVEL & DEBUG_TRACE)
2725 	fprintf(stderr," downloading texture to OpenGL \n");
2726 #endif
2727 	p->contextCache->textureDataCacheKeys[compListIndx] = oldTextureDataKey;
2728 	/* stuff the new texture data down to OpenGL */
2729 	private_rmTextureToOGL(p, t, haveNewTexture);
2730     }
2731 
2732     /* need to add residency check */
2733 
2734     rState->texture = t;
2735 
2736     return 1;
2737 }
2738 
2739 
2740 /* PRIVATE
2741  *
2742  * private_updateSceneParms - an internal routine used to activate all
2743  * scene parameters at an RMnode.
2744  */
2745 int
private_updateSceneParms(const RMnode * r,RMstate * rState,RMenum applyGL,int push_attrib_enable,RMpipe * renderPipe,RMstateCache * rsc)2746 private_updateSceneParms (const RMnode *r,
2747 			  RMstate *rState,
2748 			  RMenum applyGL,
2749 			  int push_attrib_enable,
2750 			  RMpipe *renderPipe,
2751 			  RMstateCache *rsc)
2752 {
2753     /*
2754      * this routine updates the scene parameters in rState to
2755      * reflect the changes requested by the input RMnode "r".
2756      *
2757      * cameras and viewports are processed prior to this routine.
2758      *
2759      * the rState parm is always updated, although not all scene
2760      * parameters cause a change to rState.
2761      *
2762      * when "applyGL" is set to RM_TRUE, the appropriate OpenGL
2763      * calls are made that have the scene parameters take effect.
2764      *
2765      * this routine returns a 1 if any changes were made to rState,
2766      * otherwise a 0 is returned.
2767      *
2768      * the routines preCamFunc and perObjFunc are hooks used when
2769      * rendermode is GL_SELECT to drop bread crumbs so that cameras
2770      * generate feedback tokens, otherwise they are not used.
2771      */
2772 
2773     /*
2774      * do background fill operations after the viewport is set.
2775      * note that we can't do BOTH background color AND a background image.
2776      *
2777      * don't draw tiles when we're in select mode.  although the spec
2778      * seems to indicate that no select events are generated for
2779      * drawpixels calls, i've had problems in mesa with them being
2780      * generated. (don't draw tiles in feedback mode. this is handled
2781      * as a modeling step when the PS file is created)
2782      */
2783 
2784     {
2785 	GLuint mask;
2786 	mask = private_rmNodeGetAttribMask(r);
2787 	if ((mask != 0) && (applyGL == RM_TRUE))
2788 	{
2789 	    private_rmGLPushAttrib(renderPipe, r, mask);
2790 	    push_attrib_enable = 1;
2791 	}
2792     }
2793 
2794     if (r->scene_parms && r->scene_parms->textProps != NULL)
2795     {
2796 	/*
2797 	 * text props don't do anything to OpenGL.
2798 	 * can we copy the pointer from the RMnode over rather
2799 	 * than creating a new one?
2800 	 * let's try doing that: 7/8/99
2801 	 */
2802 	rState->textProps = r->scene_parms->textProps;
2803 
2804 	/*
2805 	 * a change of text props is otherwise significant (but not to
2806 	 * OpenGL). if we've not already done a state push, we'll
2807 	 * push something small on the stack.
2808 	 *
2809 	 * the issue is that a change in RMstate is bound to a change
2810 	 * in OpenGL attribute stack depth
2811 	 */
2812 	if (push_attrib_enable != 1)
2813 	{
2814 	    if (applyGL == RM_TRUE)
2815 	    {
2816 		private_rmGLPushAttrib(renderPipe, r, GL_ACCUM_BUFFER_BIT); /* something small */
2817 		push_attrib_enable = 1;
2818 	    }
2819 	}
2820     }
2821 
2822     /* do the lights */
2823     if (r->scene_parms != NULL)
2824 	push_attrib_enable |= process_scene_lights(r, push_attrib_enable, rState, applyGL, rsc);
2825 
2826     /* update surface properties if present */
2827     if (r->sprops != NULL)
2828 	push_attrib_enable |= private_setSurfaceProps(r, push_attrib_enable, rState, applyGL);
2829 
2830     /* update rendering properties if present */
2831     if (r->rprops != NULL)
2832 	push_attrib_enable |= private_setRenderProps(r, push_attrib_enable, rState, applyGL, rsc);
2833 
2834     /* do clipping planes if present */
2835     if (r->scene_parms)
2836 	push_attrib_enable |= private_setClipPlanes(r, push_attrib_enable, rState, applyGL);
2837 
2838     /* do fog if present */
2839     if (r->scene_parms)
2840 	push_attrib_enable |= private_setFog(r, push_attrib_enable, rState, applyGL);
2841 
2842     /* do texture if present */
2843     if ((r->scene_parms != NULL) && (r->scene_parms->haveAnyTextures == RM_TRUE))
2844     {
2845 	int i;
2846 
2847 	/* 11/11/04 - todo - need to figure out a way to accelerate this
2848 	   stage of processing.  */
2849 	for (i=0; i <= RM_MAX_MULTITEXTURES; i++)
2850 	{
2851 	    if ((r->scene_parms->textures[i] != NULL) &&
2852 		(renderPipe->caps->haveMultiTexturing == RM_TRUE))
2853 	    {
2854 		/* only download multitextures if OpenGL supports multitexturing */
2855 		push_attrib_enable |= private_manageTextureState(r->scene_parms->textures[i], rState, renderPipe, applyGL, i);
2856 	    }
2857 	    else if ((r->scene_parms->textures[i] != NULL) &&
2858 		     (i == RM_MAX_MULTITEXTURES))
2859 	    {
2860 		/* the "normal", single-texture/non-multitexture case */
2861 		push_attrib_enable |= private_manageTextureState(r->scene_parms->textures[i], rState, renderPipe, applyGL, i);
2862 	    }
2863 	}
2864     }
2865 
2866     /* set the "default" color */
2867 #if 0
2868     if (applyGL == RM_TRUE)
2869 	glColor4fv((GLfloat *)&(rState->unlit_color));
2870 #endif
2871 
2872     if (push_attrib_enable)
2873 	rState->attrib_stack_depth += 1;
2874 
2875     return(push_attrib_enable);
2876 }
2877 
2878 static void
private_rmPipeMultiStageSerial(RMnode * rootedTree,RMpipe * drawToPipe)2879 private_rmPipeMultiStageSerial (RMnode *rootedTree,
2880 				RMpipe *drawToPipe)
2881 {
2882     if (rmPipeGetInitMatrixStackMode(drawToPipe) == RM_FALSE)
2883     {
2884 	RMmatrix initModel, initProjection, initTexture;
2885 
2886         glGetFloatv(GL_MODELVIEW_MATRIX,&(initModel.m[0][0]));
2887 	glGetFloatv(GL_PROJECTION_MATRIX,&(initProjection.m[0][0]));
2888 	glGetFloatv(GL_TEXTURE_MATRIX,&(initTexture.m[0][0]));
2889 	private_rmView(drawToPipe, rootedTree, drawToPipe->frameNumber, &initModel, NULL, &initProjection, &initTexture);
2890     }
2891     else
2892 	private_rmView(drawToPipe, rootedTree, drawToPipe->frameNumber, NULL, NULL, NULL, NULL);
2893 
2894 
2895     private_rmSetBackBuffer(drawToPipe);
2896     private_rmRender(drawToPipe, drawToPipe->frameNumber);
2897 
2898     private_postRenderBarrierFunc(drawToPipe);
2899 
2900     if (drawToPipe->timeSyncFunc != NULL)
2901 	(*(drawToPipe->timeSyncFunc))(drawToPipe);
2902 
2903     private_postRenderSwapBuffersFunc(drawToPipe);
2904 
2905     private_postRenderImageFuncs(drawToPipe, GL_FRONT);
2906 }
2907 
2908 static void
private_rmPipeMultiStageViewParallel(RMnode * rootedTree,RMpipe * drawToPipe)2909 private_rmPipeMultiStageViewParallel(RMnode *rootedTree,
2910 				     RMpipe *drawToPipe)
2911 {
2912     RMmultiStageThreadControl *m;
2913     RMthreadArgs *ta;
2914     int viewIndx;
2915 
2916     if (drawToPipe->mtControl == NULL) /* init multiple rendering threads */
2917     {
2918 	int i;
2919 	RMenum stat;
2920 
2921 	m = (RMmultiStageThreadControl *)malloc(sizeof(RMmultiStageThreadControl));
2922 	drawToPipe->mtControl = (void *)m;
2923 
2924 	memset(m,0,sizeof(RMmultiStageThreadControl));
2925 
2926 	m->nThreads = 1;	/* view ONLY */
2927 
2928 	m->threadIDs = (RMthread *)malloc(sizeof(RMthread)*(m->nThreads));
2929 	m->args = (RMthreadArgs *)malloc(sizeof(RMthreadArgs)*(m->nThreads));
2930 
2931 	/* for each thread, set up barriers and launch threads */
2932 	for (i=0;i<m->nThreads;i++)
2933 	{
2934 	    ta = &(m->args[i]);
2935 
2936 	    ta->p = drawToPipe;
2937 	    ta->n = rootedTree;
2938 
2939 	    ta->initModel = rmMatrixNew();
2940 	    ta->initView = NULL;
2941 	    ta->initProjection = rmMatrixNew();
2942 	    ta->initTexture = rmMatrixNew();
2943 
2944 	    ta->one = (barrier_t *)malloc(sizeof(barrier_t));
2945 	    ta->two = (barrier_t *)malloc(sizeof(barrier_t));
2946 	    barrier_init (ta->one, 2);
2947 	    barrier_init (ta->two, 2);
2948 	}
2949 
2950 	/* create each thread. these func will block trying to get
2951 	 past mutex A, which is owned by the invoking thread */
2952 
2953 	stat = rmThreadCreate(m->threadIDs+0, private_rmViewThreadFunc,
2954 			      (void *)&(m->args[0]));
2955 #if 0
2956 				/* no usleep on win32 */
2957 	usleep(10);
2958 #endif
2959     }
2960 
2961     m = (RMmultiStageThreadControl *)(drawToPipe->mtControl);
2962     ta = m->args;
2963 
2964     /* dispatch view for current frame */
2965     ta[0].p = drawToPipe;
2966     ta[0].n = rootedTree;
2967     ta[0].commandOpcode = THREAD_WORK;
2968     ta[0].frameNumber = drawToPipe->frameNumber;
2969     viewIndx = private_rmSelectEvenOddBuffer(ta[0].frameNumber);
2970 
2971     glGetFloatv(GL_MODELVIEW_MATRIX,&(ta[0].initModel->m[0][0]));
2972     glGetFloatv(GL_PROJECTION_MATRIX,&(ta[0].initProjection->m[0][0]));
2973     glGetFloatv(GL_TEXTURE_MATRIX,&(ta[0].initTexture->m[0][0]));
2974 
2975     barrier_wait(ta[0].one);	/* make sure view thread starts */
2976 
2977     /* dispatch render for last frame */
2978     if (drawToPipe->frameNumber > 0)
2979     {
2980 	private_rmRender (drawToPipe, drawToPipe->frameNumber-1);
2981 
2982 	private_postRenderBarrierFunc(drawToPipe);
2983 
2984 	if (drawToPipe->timeSyncFunc != NULL)
2985 	    (*(drawToPipe->timeSyncFunc))(drawToPipe);
2986 
2987 	private_postRenderSwapBuffersFunc(drawToPipe);
2988 
2989 	private_postRenderImageFuncs(drawToPipe, GL_FRONT);
2990     }
2991 
2992     barrier_wait(ta[0].two);
2993 
2994     /* thread finished command xeq */
2995 #if (DEBUG_LEVEL & DEBUG_TRACE)
2996     fprintf(stderr," threads finished \n");
2997     fflush(stderr);
2998 #endif
2999 
3000 }
3001 
3002 static void
private_rmPipeMultiStageParallel(RMnode * rootedTree,RMpipe * drawToPipe)3003 private_rmPipeMultiStageParallel (RMnode *rootedTree,
3004 				  RMpipe *drawToPipe)
3005 {
3006     RMmultiStageThreadControl *m;
3007     RMthreadArgs *ta;
3008     int viewIndx, renderIndx;
3009 
3010 
3011     if (drawToPipe->mtControl == NULL) /* init multiple rendering threads */
3012     {
3013 	RMenum stat;
3014 	int i;
3015 
3016 	m = (RMmultiStageThreadControl *)malloc(sizeof(RMmultiStageThreadControl));
3017 	drawToPipe->mtControl = (void *)m;
3018 
3019 	memset(m,0,sizeof(RMmultiStageThreadControl));
3020 
3021 	m->nThreads = 2;	/* view, render */
3022 
3023 	m->threadIDs = (RMthread *)malloc(sizeof(RMthread)*(m->nThreads));
3024 	m->args = (RMthreadArgs *)malloc(sizeof(RMthreadArgs)*(m->nThreads));
3025 
3026 	/* for each thread, set up barriers and launch threads */
3027 	for (i=0;i<m->nThreads;i++)
3028 	{
3029 	    ta = &(m->args[i]);
3030 
3031 	    ta->p = drawToPipe;
3032 	    ta->n = rootedTree;
3033 
3034 	    /* no OpenGL matrix stack model loading for full parallel multistage */
3035 	    ta->initModel = ta->initView = ta->initProjection = ta->initTexture = NULL;
3036 
3037 	    ta->one = (barrier_t *)malloc(sizeof(barrier_t));
3038 	    ta->two = (barrier_t *)malloc(sizeof(barrier_t));
3039 	    barrier_init (ta->one, 2);
3040 	    barrier_init (ta->two, 2);
3041 	}
3042 
3043 #ifdef RM_X
3044 	/* release the current context prior to launching the
3045 	 detached rendering thread. */
3046 
3047 	if ( (glXMakeCurrent(rmxPipeGetDisplay(ta->p), None, NULL)) == False)
3048 	    rmError("Error deassigning OpenGL context prior to creating worker threads. ");
3049 
3050 #endif
3051 
3052 #ifdef RM_WIN
3053 	stat = wglMakeCurrent(ta->p->hdc,NULL);
3054 #endif
3055 
3056 	/* create each thread. these func will block trying to get
3057 	 past mutex A, which is owned by the invoking thread */
3058 
3059 	stat = rmThreadCreate(m->threadIDs+0, private_rmViewThreadFunc,
3060 			      (void *)&(m->args[0]));
3061 
3062 	stat = rmThreadCreate(m->threadIDs+1, private_rmRenderThreadFunc,
3063 			      (void *)&(m->args[1]));
3064 #if 0
3065 				/* no usleep on win32 */
3066 	usleep(10);
3067 #endif
3068     }
3069 
3070     m = (RMmultiStageThreadControl *)(drawToPipe->mtControl);
3071     ta = m->args;
3072 
3073     /* set up args */
3074 
3075     /* dispatch render for last frame */
3076     ta[1].p = drawToPipe;
3077     ta[1].n = rootedTree;
3078     ta[1].commandOpcode = THREAD_WORK;
3079     ta[1].frameNumber = drawToPipe->frameNumber-1;
3080     renderIndx = private_rmSelectEvenOddBuffer(ta[1].frameNumber);
3081 
3082     barrier_wait(ta[1].one);
3083 
3084     /* now dispatch view for current frame */
3085     ta[0].p = drawToPipe;
3086     ta[0].n = rootedTree;
3087     ta[0].commandOpcode = THREAD_WORK;
3088     ta[0].frameNumber = drawToPipe->frameNumber;
3089     viewIndx = private_rmSelectEvenOddBuffer(ta[0].frameNumber);
3090 
3091     barrier_wait(ta[0].one);
3092 
3093     barrier_wait(ta[0].two);
3094     barrier_wait(ta[1].two);
3095 
3096     /* thread finished command xeq */
3097 #if (DEBUG_LEVEL & DEBUG_TRACE)
3098     fprintf(stderr," threads finished \n");
3099     fflush(stderr);
3100 #endif
3101 }
3102 
3103 void
private_fbClear(internals_RMfbClear * fbClear,RMstate * rState,RMenum applyGL,RMenum fbClearEnable)3104 private_fbClear(internals_RMfbClear *fbClear,
3105 		RMstate *rState,
3106 		RMenum applyGL,
3107 		RMenum fbClearEnable)
3108 {
3109     /* in this routine, assume that fbClear != NULL */
3110     if ((fbClear->bgImageTile) && (fbClearEnable)
3111 	&& (rState->rendermode != GL_SELECT) && (rState->rendermode != GL_FEEDBACK))
3112 	private_setBackgroundTile(fbClear, rState, RM_FALSE, applyGL);
3113     else if ((fbClear->bgColor) && (fbClearEnable))
3114 	private_setBackgroundColor(fbClear, rState, RM_FALSE, applyGL);
3115 
3116     /* check depth value or image parms */
3117     if ((fbClear->depthValue != NULL) && (fbClearEnable))
3118 	private_setBackgroundDepthValue(fbClear, rState, applyGL);
3119 
3120     if ((fbClear->depthImage != NULL) && (fbClearEnable))
3121 	private_setBackgroundDepthImage(fbClear, rState, RM_FALSE, applyGL);
3122 }
3123 
3124 /* EOF */
3125