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