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: rmpipe.c,v 1.28 2005/09/12 04:03:51 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.28 $
29  * $Log: rmpipe.c,v $
30  * Revision 1.28  2005/09/12 04:03:51  wes
31  * Minor documentation updates.
32  *
33  * Revision 1.27  2005/06/26 18:57:03  wes
34  * Added initialization code to rmPipeNew that clears the new attrib mask stack.
35  *
36  * Revision 1.26  2005/06/12 21:18:23  wes
37  * Minor language changes to in-code documentation.
38  *
39  * Revision 1.25  2005/06/06 02:04:29  wes
40  * Lots of small additions to clean up compiler warnings.
41  *
42  * Revision 1.24  2005/05/16 01:02:02  wes
43  * Streamlining rmPipeMakeCurrent
44  *
45  * Revision 1.23  2005/03/16 16:45:47  wes
46  * Minor code changes, documentation update.
47  *
48  * Revision 1.22  2005/02/24 16:17:25  wes
49  * Added support for fbClears to be set at the RMpipe level. Apps can
50  * still set them at the RMnode level if desired for fine-grained control.
51  *
52  * Revision 1.21  2005/02/19 16:40:20  wes
53  * Distro sync and consolidation.
54  * Repairs to fix memory leak associated with repeated calls to rmPipeNew,
55  * rmPipeMakeCurrent, rmPipeClose.
56  *
57  * Revision 1.20  2005/01/23 17:08:25  wes
58  * Copyright updated to 2005.
59  * Updates to support access and use of extensions; multitexturing on all
60  * platforms, use of 3d texture extension to realize implementation of
61  * volume rendering and related functions on Windows platforms.
62  *
63  * Revision 1.19  2004/09/26 21:47:09  wes
64  * Modified rmPipeMakeCurrent to do more thorough checking before
65  * making the OpenGL context current. In X, you must have a valid
66  * Display, a valid Window and a pre-assigned context before OpenRM
67  * will do a glXMakeCurrent call.
68  *
69  * Also, modified rmPipeClose to zero out the internal variables for
70  * the contextCache and displayLists fields so that you can call rmPipeClose
71  * on an RMpipe more than once and not get an error.
72  *
73  * Revision 1.18  2004/08/07 17:12:59  wes
74  * Updated rmPipeMakeCurrent so that the return status accurately reflects
75  * that both (1) the OpenGL context is active and usable, and (2) that
76  * RM was able to initialize the context cache and component manager.
77  *
78  * Revision 1.17  2004/05/09 22:23:13  wes
79  * Update to rmPipeMakeCurrent to accommodate component mgr, context cache
80  * and quadrics display list construction when the app has specified
81  * NULL as a drawable. The implication here is that they're using their
82  * own OpenGL context. Added a routine to check for the presence of
83  * an active context. The new routine contains arch-specific code.
84  *
85  * Revision 1.16  2004/03/27 16:46:56  wes
86  * Tweak rmPipeMakeCurrent so that glXMakeCurrent is called only if we have
87  * a valid window and context handle under X11 (those checks were already
88  * done for Win32)
89  *
90  * Revision 1.15  2004/02/23 03:03:48  wes
91  * New routine: rmPipeGetFrameNumber().
92  *
93  * Revision 1.14  2004/01/16 16:57:03  wes
94  * Added time synchronization function which is used to achieve
95  * constant-rate rendering.
96  *
97  * Revision 1.13  2003/12/12 00:34:13  wes
98  * Added documentation for rmPipeSetFrameRate and rmPipeGetFrameRate.
99  *
100  * Revision 1.12  2003/12/06 03:26:06  wes
101  * Documentation tweaks to RMtime routines, updates to RMtime routines for
102  * Windows.
103  *
104  * Revision 1.11  2003/12/01 02:13:05  wes
105  * Additions to support constant frame-rate rendering on both Unix and Win32.
106  *
107  * Revision 1.10  2003/10/03 19:20:47  wes
108  * Use platform-independent interface to access the OpenGL context.
109  *
110  * Revision 1.9  2003/07/23 13:32:28  wes
111  * Win32: problems with offscreen rendering appeared with new context
112  * initialization code sequence (1.5.0). Minor repairs needed to fix the bug.
113  *
114  * Revision 1.8  2003/04/12 21:02:00  wes
115  * Undo of movement of RMpipe view-render buffer init back into rendering
116  * path, and out of rmPipeNew. The init code can't be called from rmPipeNew
117  * because the init code depends upon the channel format, which is usually
118  * set by the app after rmPipeNew.
119  *
120  * Revision 1.7  2003/04/12 19:48:30  wes
121  * Set the default comm size to 1, default rank to zero.
122  *
123  * Revision 1.6  2003/04/05 14:12:06  wes
124  * Add code to rmPipeClose() that calls routines freeing inter-stage resources.
125  *
126  * Revision 1.5  2003/03/16 21:56:16  wes
127  * Documentation updates.
128  *
129  * Revision 1.4  2003/02/14 00:21:02  wes
130  * *** empty log message ***
131  *
132  * Revision 1.3  2003/02/02 02:07:15  wes
133  * Updated copyright to 2003.
134  *
135  * Revision 1.2  2003/02/01 17:56:15  wes
136  * Win32 code work to reflect new RMpipe initialization sequence.
137  *
138  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
139  * Manual rebuild of rm150 repository.
140  *
141  * Revision 1.19  2003/01/27 05:04:42  wes
142  * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR
143  * platforms w/o too much disruption to existing apps.
144  *
145  * Revision 1.18  2003/01/16 22:21:17  wes
146  * Updated all source files to reflect new organization of header files:
147  * all header files formerly located in include/rmaux, include/rmi, include/rmv
148  * are now located in include/rm.
149  *
150  * Revision 1.17  2003/01/11 18:44:22  wes
151  * Added global control over whether or not display lists are used during
152  * rendering by adding the new RMpipe controls rmPipeSetDisplayListEnable()
153  * and rmPipeGetDisplayListEnable().
154  *
155  * Revision 1.16  2002/12/31 00:55:22  wes
156  *
157  * Various enhancements to support Chromium - achitecture-specific sections
158  * of RMpipe were cleaned up, etc.
159  *
160  * Revision 1.15  2002/08/29 22:20:32  wes
161  *
162  * Massive upgrade to accommodate dynamic object reallocation within
163  * the component manager, and within the context cache. Use the
164  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
165  * whenever a realloc occurs. With this upgrade, there are no
166  * OpenRM limits on the size of the scene graph. There will be external
167  * limits, such as the amount of RAM and the amount of space available
168  * to your OpenGL implementation.
169  *
170  * Revision 1.14  2002/06/30 21:51:22  wes
171  * Added code by SF member barrett that checks for NULL when deleting
172  * an RMpipe's context cache.
173  *
174  * Revision 1.13  2002/04/30 19:33:05  wes
175  * Updated copyright dates.
176  *
177  * Revision 1.12  2001/10/15 00:11:31  wes
178  * Minor tweak.
179  *
180  * Revision 1.11  2001/10/15 00:10:20  wes
181  * Added code to close the window on when an RMpipe is closed.
182  *
183  * Revision 1.10  2001/07/15 17:17:59  wes
184  * Added code to cleanse the context cache when the RMpipe is either
185  * rmPipeClose()'d or rmPipeDelete()'d.
186  *
187  * Revision 1.9  2001/06/04 00:59:55  wes
188  * Added documentation for RMpipe processing modes.
189  *
190  * Revision 1.8  2001/06/03 20:49:46  wes
191  * Removed "rmPipeGetCurrent", added calls to query current processing
192  * mode to be able to determine if it's an offscreen mode or a
193  * multithreaded mode.
194  *
195  * Revision 1.7  2001/03/31 17:12:39  wes
196  * v1.4.0-alpha-2 checkin.
197  *
198  * Revision 1.6  2000/12/03 22:33:55  wes
199  * Mods for thread-safety.
200  *
201  * Revision 1.5  2000/08/23 23:27:45  wes
202  * Minor edits for readability.
203  *
204  * Revision 1.4  2000/05/14 23:37:11  wes
205  * Added control via RMpipe attribute to how OpenGL matrix stack
206  * is initialized or used during rendering.
207  *
208  * Revision 1.3  2000/04/20 16:29:47  wes
209  * Documentation additions/enhancements, some code rearragement.
210  *
211  * Revision 1.2  2000/02/29 23:43:53  wes
212  * Compile warning cleanups.
213  *
214  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
215  * OpenRM 1.2 Checkin
216  *
217  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
218  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
219  *
220  */
221 
222 /*
223  * generic pipe utilities (window system independent) in this file.
224  * specific pipe/window utilities are in rmx.c or rmw.c
225  */
226 
227 #include <rm/rm.h>
228 #include "rmprivat.h"
229 #include "rmmultis.h"
230 
231 /* stuff for debugging constant-rate rendering */
232 #define DEBUG_RSYNC 0
233 #if DEBUG_RSYNC
234 
235 #define MAX_RSYNC_SAMPLES 1000
236 
237 typedef struct
238 {
239     RMtime t;
240     int frameNumber;
241 } RMtimeSyncStruct;
242 
243 RMtimeSyncStruct timeSyncData[1000];
244 int timeSyncIndx = 0;
245 
246 #endif
247 
248 static int private_rmCheckForActiveContext(void);
249 static void private_rmPipeGetCapabilities(RMpipeOGLCapabilities *);
250 
251 /*
252  * ----------------------------------------------------
253  * @Name rmPipeCreateContext
254  @pstart
255  RMenum rmPipeCreateContext (RMpipe *toUse)
256  @pend
257 
258  @astart
259  RMpipe *toUse - a handle to an RMpipe (modified).
260  @aend
261 
262  @dstart
263 
264  This routine will create a platform-specific OpenGL context that honors
265  the display format attributes contained in the RMpipe. Use
266  rmPipeSetChannelFormat() to set such parameters prior to creating the context.
267  Changing the channel format parameters after the context has been created
268  with this routine will have no effect.
269 
270  After the context has been created with this routine, be sure to call
271  rmPipeMakeCurrent() to perform final intialization steps needed to ready
272  the context for use in rendering.
273 
274  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
275 
276 
277  @dend
278  * ----------------------------------------------------
279  */
280 RMenum
rmPipeCreateContext(RMpipe * p)281 rmPipeCreateContext (RMpipe *p)
282 {
283     if (p->createContextFunc != NULL)
284 	return(p->createContextFunc(p));
285     else
286 	rmError(" rmPipeCreateContext() error - no context creation function assigned!! Ouch!");
287 
288     return RM_WHACKED;
289 }
290 
291 /*
292  * ----------------------------------------------------
293  * @Name rmPipeNew
294   @pstart
295   RMpipe * rmPipeNew (RMenum targetPlatform)
296   @pend
297 
298   @astart
299   RMenum targetPlatform - select the appropriate platform. This parameter
300     must be one of RM_PIPE_GLX, RM_PIPE_WGL or RM_PIPE_CR.
301   @aend
302 
303   @dstart
304 
305   Use this routine to create a new RMpipe object for use with a specified
306   display platform. Upon success, a handle to the new RMpipe object is
307   returned to the caller, or NULL is returned upon failure.
308 
309   The input parameter must be one of RM_PIPE_GLX, RM_PIPE_WGL, RM_PIPE_CR or
310   RM_PIPE_NOPLATFORM. RM_PIPE_GLX specifies use on any X-based system that
311   has the GLX extension (supports OpenGL through the server). RM_PIPE_WGL
312   specifies use on a Win32 platform. RM_PIPE_CR specifies use only on a
313   Chromium-enabled system. RM_PIPE_NOPLATFORM may be be used on any
314   platform. The difference between RM_PIPE_NOPLATFORM and others is that
315   some RMpipe fields are not initialized (swapbuffers function, context
316   creation function,... ).
317 
318   Note that RM_PIPE_GLX and RM_PIPE_WGL platforms can make use of Chromium
319   as well for doing single application to one or more crservers. However,
320   an RM_PIPE_CR platform is highly Chromium-specific. Refer to the RM
321   Programming Guide for more details.
322 
323   During rmPipeNew(), the RMpipe object is initialized with the following
324   platform-specific and platform-neutral settings:
325 
326   1. The "swapbuffers" function is set to a platform-appropriate value. The
327   application may later override this setting using rmPipeSetSwapBuffersFunc().
328   By assigning a default swapbuffers function, we are assuming that the
329   OpenGL context (created later) will be double buffered. For the
330   RM_PIPE_NOPLATFORM, no swapbuffers function is assigned.
331 
332   2. The "context creation function" is set to a platform-appropriate value.
333   The application may indirectly override the context creation function using
334   rmPipeSetContext() to assign an OpenGL context to the RMpipe. Such an
335   assignment must occur between rmPipeNew() and rmPipeMakeCurrent().
336 
337   3. The default channel format is RM_MONO_CHANNEL, which corresponds to
338   an OpenGL visual that has RGBA color buffers, a depth buffer, and which
339   is double-buffered. The channel format can be set using
340   rmPipeSetChannelFormat() after rmPipeNew() returns, and before a window
341   is created (or before drawing occurs in the case of RM_PIPE_CR).
342 
343   4. The default processing mode is RM_PIPE_MULTISTAGE. This mode corresponds
344   to serial rendering using a two-stage pipeline. You can set the processing
345   mode after rmPipeNew() returns (see rmPipeSetProcessingMode), but before
346   rmPipeMakeCurrent().
347 
348   5. The "post render barrier function" is set to NULL (see
349   rmPipeSetPostRenderBarrierFunc).
350 
351   6. The "post render function" is set to NULL (see
352   rmPipeSetPostRenderFunc).
353 
354   7. Each of the following three passes of the multipass rendering
355   engine is enabled by default: opaque 3D, transparent 3D, opaque
356   2D. Applications may not change the order of these rendering passes,
357   but may enable or disable a given rendering pass with
358   rmPipeSetRenderPassEnable().
359 
360 
361   The basic sequence of steps needed to fully initialize RM for rendering are:
362 
363   1. Use rmPipeNew(yourPlatform) to create the RMpipe object specific
364      for your platform.
365 
366   2. Set any optional parameters on the RMpipe: processing mode (see
367      rmPipeSetProcessingMode), channel format (see rmPipeSetChannelFormat),
368      XDisplay on X systems (see rmxPipeSetDisplay).
369 
370      X11 note: if you want to display somewhere other than getenv($DISPLAY),
371      you will need to make an explicit call to rmxPipeSetDisplay() using
372      an appropriate XDisplay structure. By default, rmPipeNew(RM_PIPE_GLX)
373      will perform XOpenDisplay(getenv("$DISPLAY")), and assign the
374      resulting XDisplay structure to the RMpipe. An opened X Display is
375      necessary for access to bitmap fonts.
376 
377   3. Create a window suitable for display. This can be done with
378      either rmauxCreateXWindow() or rmauxCreateW32Window(), or a suitable
379      drawable can be provided by an external source (for more details, see
380      the RM Programming Guide).
381 
382   4. Assign the window to the RMpipe (see rmPipeSetWindow)
383 
384   5. Make the pipe current (rmPipeMakeCurrent).
385 
386   @dend
387   * ----------------------------------------------------
388  */
389 RMpipe *
rmPipeNew(RMenum targetPlatform)390 rmPipeNew (RMenum targetPlatform)
391 {
392     RMpipe *t;
393     extern RMenum RM_DEFAULT_PIPE_DISPLAY_LIST_ENABLE;
394 
395     if ((targetPlatform != RM_PIPE_GLX) && (targetPlatform != RM_PIPE_WGL) &&
396 	(targetPlatform != RM_PIPE_CR) && (targetPlatform != RM_PIPE_NOPLATFORM))
397     {
398 	rmError("rmPipeNew() error - the input targetPlatform must be one of RM_PIPE_GLX, RM_PIPE_WGL, RM_PIPE_CR, RM_PIPE_NOPLATFORM");
399 	return NULL;
400     }
401 
402     t = (RMpipe *)calloc(1,sizeof(RMpipe));
403 
404     if (t == NULL)
405 	return(NULL);
406 
407     private_rmPipeSetPlatform(t, targetPlatform);
408 
409     rmPipeSetSwapBuffersFunc(t, NULL);
410 
411 #ifdef RM_X
412     if (targetPlatform == RM_PIPE_GLX)
413     {
414 	/* 2/5/05 - want ability for selective XOpenDisplay */
415 	/* 5/1/05 - why? wes */
416 	const char *displayName = getenv("DISPLAY");
417 	Display *theDisplay = XOpenDisplay(displayName);
418 	rmxPipeSetDisplay(t, theDisplay);
419 
420 	rmPipeSetSwapBuffersFunc(t, rmPipeSwapBuffersX11);
421 	t->shutdownFunc = private_rmPipeCloseContextX11;
422 	t->createContextFunc = private_rmxPipeCreateContext;
423     }
424 #endif
425 #ifdef RM_WIN
426     if (targetPlatform == RM_PIPE_WGL)
427     {
428 	rmPipeSetSwapBuffersFunc(t, rmPipeSwapBuffersWin32);
429 	t->shutdownFunc = private_rmPipeCloseContextW32;
430 	t->createContextFunc = rmwPipeCreateContext;
431     }
432 #endif
433 #ifdef RM_CR
434     if (targetPlatform == RM_PIPE_CR)
435     {
436 #ifdef RM_X
437 	/* 2/5/05 - want ability for selective XOpenDisplay */
438 	/* 5/1/05 - why? wes */
439 	/* 5/1/05 - when building the Chromium-enabled version of RM, you
440 	 should also build with -DRM_X because the RMpipe needs the $DISPLAY
441  	 to access bitmap fonts. */
442 	const char *displayName = getenv("DISPLAY");
443 	Display *theDisplay = XOpenDisplay(displayName);
444 	rmxPipeSetDisplay(t, theDisplay);
445 #endif
446 	private_rmPipeInitCR(t);
447 	t->shutdownFunc = private_rmPipeCloseContextCR;
448 	t->createContextFunc = rmPipeCreateContextCR;
449 	t->contextCR = -1;
450     }
451 #endif
452 
453     if (targetPlatform == RM_PIPE_NOPLATFORM)
454     {
455 	t->shutdownFunc = NULL;
456 	t->createContextFunc = NULL;
457     }
458 
459     rmPipeSetCommSize(t, 1); /* default comm size is 1 */
460     rmPipeSetRank(t, 0);     /* default rank is zero */
461 
462     rmPipeSetPostRenderBarrierFunc(t, NULL);
463     rmPipeSetPostRenderFunc(t, NULL);
464     rmPipeSetInitMatrixStackMode(t, RM_TRUE);
465 
466     t->channel_format = RM_MONO_CHANNEL;
467     t->processingMode = RM_PIPE_MULTISTAGE;
468     t->offscreen = RM_FALSE;
469 
470     rmPipeSetChannelFormat(t, RM_MONO_CHANNEL);
471 
472     /* enable 3 stage, multipass rendering */
473     rmPipeSetRenderPassEnable(t, RM_TRUE, RM_TRUE, RM_TRUE);
474 
475     /* set default display list use policy */
476     rmPipeSetDisplayListEnable(t, RM_DEFAULT_PIPE_DISPLAY_LIST_ENABLE);
477 
478     /* set frame rate to -1. this means constant-rate rendering stuff
479        is disabled by default, and the app must specifically request it. */
480     rmPipeSetFrameRate(t, -1);
481     private_rmPipeSetTimeSyncFunc(t, NULL);
482 
483     /* initialize the local attrib mask stack */
484     t->localMaskStackTop = 0;
485     memset((void *)(t->localMaskStack), 0, sizeof(GLuint)*MAX_MASK_STACK_DEPTH);
486 
487     return(t);
488 }
489 
490 /*
491  * ----------------------------------------------------
492  * @Name rmPipeDelete
493  @pstart
494  RMenum rmPipeDelete (RMpipe *toDelete)
495  @pend
496 
497  @astart
498  RMpipe *toDelete - a handle to an RMpipe to be deleted.
499  @aend
500 
501  @dstart
502 
503  Releases resources associated with an RMpipe object. This is the
504  opposite of rmPipeNew(). Returns RM_WHACKED if the input RMpipe is
505  NULL.
506 
507  @dend
508  * ----------------------------------------------------
509  */
510 RMenum
rmPipeDelete(RMpipe * p)511 rmPipeDelete (RMpipe *p)
512 {
513     if (RM_ASSERT(p, "rmPipeDelete() error: the input RMpipe is NULL") == RM_WHACKED)
514 	return(RM_WHACKED);
515     /*
516      * we could potentially do more work, like close the window, close
517      * the display, etc. but for now (Jan 2000) we'll just do the free().
518      */
519     rmPipeClose(p);
520 
521     /* new in 1.6.0, free the capabilities struct if present. */
522     if (p->caps != NULL)
523     {
524 	free((void *)p->caps);
525 	p->caps = NULL;
526     }
527     free((void *)p);
528 
529     return(RM_CHILL);
530 }
531 
532 
533 /*
534  * ----------------------------------------------------
535  * @Name rmPipeMakeCurrent
536  @pstart
537  RMenum rmPipeMakeCurrent (RMpipe *toUse)
538  @pend
539 
540  @astart
541  RMpipe *toUse - a handle to an RMpipe object (input).
542  @aend
543 
544  @dstart
545 
546  Use this routine to make a named RMpipe "active." Making an RMpipe
547  "active" involves three primary processing stages. First, we take steps
548  to either verify that an OpenGL context is current already, or we make
549  current the OpenGL context assigned to the RMpipe. Second, we initialize
550  the RMpipe's context cache. Third, we initialize some OpenGL variables
551  needed by RM for rendering.
552 
553  This routine will return a value of RM_CHILL to indicate that RM and OpenGL
554  are ready for rendering. A value of RM_WHACKED is returned if either of the
555  following is true: (1) RM was unable to initialize an OpenGL rendering
556  context and/or make it current; (2) RM was unable to initialize its
557  internal context cache and component manager. Both conditions (1) and (2)
558  must be satisfied before rendering may occur. A return value of RM_WHACKED
559  means that the RMpipe is not ready for use in rendering.
560 
561  All applications will use this routine to make an RMpipe "active."
562 
563  In the first stage of processing, we first check to see if there is an
564  already "current" OpenGL context. If so, we do not disturb it, but just
565  go ahead and use it. If no OpenGL context is already current, then we will
566  attempt to make current the OpenGL context assigned to the RMpipe. This step
567  requires the presence of a Window or HWND parameter in the X11 and Windows
568  environments, respectively.
569 
570  In the second stage of processing, this routine will check for the existance
571  of an RMpipe "context cache," and will create a new one if one does not exist.
572  If a context cache exists, it will be flushed and replaced with a new one.
573 
574  The context cache is used internally by RM to store retained mode, OpenGL
575  context-specific data, such as display list indices, texture object identifiers,
576  and so forth.  The reason for creating/replacing/activating the context cache
577  in this routine, rather than earlier (when the OpenGL context is created) is
578  due to the inconsistencies between X11 and Win32 in how OpenGL is initialized.
579  In X11, the GLX context must be created prior to creating an X11 window
580  (XCreateWindow needs an XVisualInfo structure, which reflects the pixel format
581  chosen with glXChooseVisual). In Win32, the equivalent of an XVisualInfo structure
582  is created using a window handle.
583 
584  In nearly all applications, this routine will be called only once. It is not an
585  error call it multiple times, but developers must be aware that any existing
586  retained mode structures will be flushed by rmPipeMakeCurrent, and rebuilt
587  during subsequent renderings.
588 
589  This routine *must* be called by all applications between
590  rmPipeNew() (RMpipe initialization) and rmFrame() (rendering).
591 
592  @dend
593  * ----------------------------------------------------
594  */
595 RMenum
rmPipeMakeCurrent(RMpipe * pipe)596 rmPipeMakeCurrent (RMpipe *pipe)
597 {
598     RMenum haveActiveContext=RM_FALSE;
599 
600     if (RM_ASSERT(pipe, "rmPipeMakeCurrent() error: the input RMpipe is NULL") == RM_WHACKED)
601 	return RM_WHACKED;
602 
603 #ifdef RM_X
604     if (private_rmPipeGetPlatform(pipe) == RM_PIPE_GLX)
605     {
606 	/* first, check to see if the assigned context is active. */
607 	if ((haveActiveContext = private_rmCheckForActiveContext()) != RM_TRUE)
608 	{
609 	    /* don't have an active context. See if we have enough to make an
610 	     active context. */
611 	    Window w = rmPipeGetWindow(pipe);
612 	    GLXContext ctx = rmPipeGetContext(pipe);
613 	    Display *d = rmxPipeGetDisplay(pipe);
614 
615 	    if ((w != 0) && (ctx != NULL) && (d != NULL))
616 	    {
617 		if (glXMakeCurrent(rmxPipeGetDisplay(pipe), rmPipeGetWindow(pipe), rmPipeGetContext(pipe)) == True)
618 		    haveActiveContext = RM_TRUE;
619 	    }
620 	    else
621 	    {
622 		rmWarning("rmPipeMakeCurrent (X11): we don't have an active OpenGL context, and don't have enough variables set in the RMpipe to make an active context. We need: (1) an open Display (see rmxPipeSetDisplay), (2) a window or drawable (see rmPipeSetWindow), and (3) an OpenGL context (see rmPipeSetContext).");
623 		return RM_WHACKED;
624 	    }
625 	}
626     }
627 #endif
628 #ifdef RM_WIN
629     if (private_rmPipeGetPlatform(pipe) == RM_PIPE_WGL)
630     {
631 	/* first, check to see if the assigned context is active. */
632 	if ((haveActiveContext = private_rmCheckForActiveContext()) != RM_TRUE)
633 	{
634 	    /* don't have an active context. See if we have enough to make an
635 	     active context. */
636 	    HWND hWnd = rmPipeGetWindow(pipe);
637 	    HGLRC ctx = rmPipeGetContext(pipe);
638 
639 	    if ((hWnd != 0) && (ctx != NULL))
640 	    {
641 		if (wglMakeCurrent (pipe->hdc, ctx) == TRUE)
642 		    haveActiveContext = RM_TRUE;
643 		else
644 		{
645 		    private_rmwCheckAndDisplayLastError("rmPipeMakeCurrent: After wglMakeCurrent");
646 		    return RM_WHACKED;
647 		}
648 	    }
649 	    else
650 	    {
651 		rmWarning("rmPipeMakeCurrent (Win32): we don't have an active OpenGL context, and at least one of an OpenGL context and/or window has not been assigned to the RMpipe.");
652 		return RM_WHACKED;
653 	    }
654 	}
655     }
656 #endif
657 
658 #ifdef RM_CR
659     /* special code for making the context current in Chromium */
660     if (private_rmPipeGetPlatform(pipe) == RM_PIPE_CR)
661 	haveActiveContext = rmPipeMakeCurrentCR(pipe);
662 #endif
663 
664     if (private_rmPipeGetPlatform(pipe) == RM_PIPE_NOPLATFORM)
665     {
666 	if ((haveActiveContext = private_rmCheckForActiveContext()) != RM_TRUE)
667 	{
668 	    rmError("rmPipeMakeCurrent error -- for your RM_PIPE_NOPLATFORM RMpipe, it does not appear there is a current, active OpenGL context. Therefore, OpenGL is not initialized and ready for use by OpenRM Scene Graph. ");
669 	    return RM_WHACKED;
670 	}
671     }
672 
673     if (haveActiveContext == RM_TRUE)
674     {
675 #ifdef RM_WIN
676 	glPixelStorei(GL_PACK_ALIGNMENT, 4);
677 	glPixelStorei(GL_UNPACK_ALIGNMENT, 4); /* say's that we're word aligned on each scanline */
678 #endif
679 #ifdef RM_X
680 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
681 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* say's that we're byte aligned on each scanline */
682 #endif
683     }
684 
685     /* at this point, wstat == 1 means we have a valid, active OpenGL
686        context. if wstat == 0, OpenGL is not ready to go. */
687 
688     /*
689      * flush any existing context cache.
690      */
691     if (pipe->contextCache != NULL && haveActiveContext == RM_TRUE)
692 	private_rmCacheFlush(pipe->contextCache);
693 
694     /*
695      * then build a new one.
696      */
697     if (private_rmCacheInit(&(pipe->contextCache)) != RM_CHILL)
698     {
699 	rmError("rmPipeMakeCurrent - unable to initialize the RMpipe context cache. Please file a bug report.");
700 	return RM_WHACKED;
701     }
702 
703     /*
704      * load prebuilt display lists for quadrics objects into the
705      * context cache of each pipe.
706      */
707 
708     if (pipe->contextCache != NULL && haveActiveContext == RM_TRUE)
709 	private_rmInitQuadrics(pipe->contextCache);
710 
711     /*
712      * if we have a valide OpenGL context and the component manager/context
713      * cache is ready to go, go ahead and obtain the capabilities for
714      * the RMpipe object.
715      */
716     if (haveActiveContext == RM_TRUE)
717     {
718 	RMpipeOGLCapabilities *caps = (RMpipeOGLCapabilities *)calloc(1,sizeof(RMpipeOGLCapabilities));
719 	private_rmPipeGetCapabilities(caps);
720 	pipe->caps = caps;
721     }
722 
723     /*
724      * return status of 1 indicates that we have both initialized the
725      * context cache as well as the OpenGL context, and that RM is ready
726      * to render stuff. A value of 0 means that either one of these two
727      * init operations failed, and that RM cannot render anything.
728      */
729     return( (haveActiveContext == RM_TRUE) ? RM_CHILL : RM_WHACKED );
730 }
731 
732 
733 /*
734  * ----------------------------------------------------
735  * @Name rmPipeClose
736  @pstart
737  RMenum rmPipeClose(RMpipe *toClose)
738  @pend
739 
740  @astart
741  RMpipe *toClose - a handle to an RMpipe (modified).
742  @aend
743 
744  @dstart
745 
746  This routine will destroy the OpenGL rendering context associated
747  with the input RMpipe object, and delete all resources associated
748  with the RMpipe's context cache, including all OpenGL display lists
749  and texture object id's.
750 
751  On X11, this routine will also close the X Display associated with
752  the RMpipe.
753 
754  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
755 
756  @dend
757  * ----------------------------------------------------
758  */
759 RMenum
rmPipeClose(RMpipe * toClose)760 rmPipeClose (RMpipe *toClose)
761 {
762     /* deletes an OpenGL rendering context */
763     if (RM_ASSERT(toClose, "rmPipeClose() error: the input RMpipe is NULL.") == RM_WHACKED)
764 	return(RM_WHACKED);
765 
766     /*
767      * we want to first shut down any rendering threads so that we can
768      * reattach to the OpenGL context in order to delete display lists, etc.
769      */
770 
771     /* temp - assume that the rendering stuff is serial, no parallel stuff.
772      TODO: we need to add a call that will close down the rendering threads,
773      if any. this call will return control of the OpenGL rendering
774      context to the caller (us) so that we can do stuff to the
775      OpenGL rendering context. 7/4/01 w.bethel */
776 
777     if (toClose->contextCache != NULL)
778     {
779 	private_rmCacheDelete(toClose, toClose->contextCache);
780 	toClose->contextCache = NULL;
781     }
782 
783     if (toClose->shutdownFunc != NULL)
784 	toClose->shutdownFunc(toClose);
785 
786     /*
787      * free up resources associated with view-render buffers
788      */
789     if (toClose->displayLists != NULL)
790     {
791 	private_rmPipeDisplayListsDelete(toClose);
792 	toClose->displayLists = NULL;
793     }
794 
795 #if DEBUG_RSYNC
796     {
797 	FILE *f=fopen("timeSync.txt","w");
798 	int i, n;
799 	double d;
800 	int thisUn, nextUn;
801 
802 	/* need to weave in some code to test for start != 0, which
803 	   would be caused by wrapping around in the ring buffer */
804 
805 	if (timeSyncIndx >= MAX_RSYNC_SAMPLES)
806 	{
807 	    n = MAX_RSYNC_SAMPLES;
808 	    thisUn = (timeSyncIndx+1) % MAX_RSYNC_SAMPLES;
809 	}
810 	else
811 	{
812 	    n = timeSyncIndx;
813 	    thisUn = 0;
814 	}
815 
816 	nextUn = (thisUn + 1) % MAX_RSYNC_SAMPLES;
817 
818 	for (i=0; i<n-1; i++)
819 	{
820 	    if (i == 0)
821 		d = 0.;
822 	    else
823 		d = rmTimeDifferenceMS(&(timeSyncData[thisUn].t),
824 				       &(timeSyncData[nextUn].t));
825 	    fprintf(f,"%d\t%g\n", timeSyncData[thisUn].frameNumber, d);
826 
827 	    thisUn++;
828 	    thisUn = thisUn % MAX_RSYNC_SAMPLES;
829 	    nextUn++;
830 	    nextUn = nextUn % MAX_RSYNC_SAMPLES;
831 	}
832 
833 	fclose(f);
834 	timeSyncIndx = 0;
835     }
836 #endif
837 
838     return(RM_CHILL);
839 }
840 
841 /*
842  * ----------------------------------------------------
843  * @Name rmPipeSwapBuffers
844  @pstart
845  RMenum rmPipeSwapBuffers (RMpipe *p)
846  @pend
847 
848  @astart
849  RMpipe *p - a handle to an RMpipe (input).
850  @aend
851 
852  @dstart
853 
854  This routine will cause a buffer-swap on the display and window
855  specified by the input RMpipe.
856 
857  In the interest of speed, no error checking is performed inside this
858  routine.
859 
860  This routine is most typically called from within a rendering manager
861  routine, and not directly from the application. There is nothing that
862  precludes it's use directly by applications, if so desired.
863 
864 
865  @dend
866  * ----------------------------------------------------
867  */
868 RMenum
rmPipeSwapBuffers(const RMpipe * p)869 rmPipeSwapBuffers(const RMpipe *p)
870 {
871     if (RM_ASSERT(p, "rmPipeSwapBuffers() error: the input RMpipe is NULL.") == RM_WHACKED)
872 	return(RM_WHACKED);
873 #if 0
874     if (RM_ASSERT(p->swapBuffersFunc, "rmPipeSwapBuffers() warning: there is no swapbuffers function assigned to the input RMpipe.") == RM_WHACKED)
875 	return RM_WHACKED;
876 #endif
877 
878     if (p->swapBuffersFunc != NULL)
879 	p->swapBuffersFunc(p);
880 
881     return RM_CHILL;
882 }
883 
884 
885 /*
886  * ----------------------------------------------------
887  * @Name rmPipeSetChannelFormat
888  @pstart
889  RMenum rmPipeSetChannelFormat (RMpipe *toModify,
890 		                RMenum channelFormat)
891  @pend
892 
893  @astart
894  RMpipe *toModify - a handle to an RMpipe object (modified).
895 
896  RMenum channelFormat - an RMenum value specifying a display
897     format. May be one of RM_MONO_CHANNEL, RM_REDBLUE_STEREO_CHANNEL,
898     RM_BLUERED_STEREO_CHANNEL, or RM_MBUF_STEREO_CHANNEL.  @aend
899 
900  @dstart
901 
902  Use this routine to set the "channel format" of an RMpipe object.
903  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
904 
905  The RMpipe channel format serves two purposes. First, when
906  multibuffered stereo is requested, this information must be known
907  prior to creating an OpenGL rendering context. So, the channel format
908  provides hints about the type of OpenGL capabilities that are needed
909  by the application.  As such, it is likely that the channel format
910  interface will evolve over time to include more access to additional
911  OpenGL capabilities.
912 
913  Second, when a channel format is specified, internal to
914  rmPipeSetChannelFormat(), an RM rendering callback is assigned to the
915  pipe. The rendering callback knows about multipass rendering as well
916  as how to instruct the underlying rendering engine in the details of
917  managing stereo rendering.
918 
919  This routine must be called between the time you create the RMpipe with
920  rmPipeNew(), and before an OpenGL rendering context is created with
921  rmPipeCreateContext(). It is a logic error to change an RMpipe's channel
922  format after the OpenGL context has been created.
923 
924 
925  @dend
926  * ----------------------------------------------------
927  */
928 RMenum
rmPipeSetChannelFormat(RMpipe * p,RMenum channel_format)929 rmPipeSetChannelFormat (RMpipe *p,
930 		        RMenum channel_format)
931 {
932     RMenum rstat = RM_CHILL;
933 
934     if (RM_ASSERT(p, "rmPipeSetChannelFormat() error: the input RMpipe pointer is NULL.") == RM_WHACKED)
935 	return(RM_WHACKED);
936 
937     switch (channel_format)
938        {
939        case RM_MONO_CHANNEL:
940        case RM_REDBLUE_STEREO_CHANNEL:
941        case RM_BLUERED_STEREO_CHANNEL:
942        case RM_MBUF_STEREO_CHANNEL:
943 	   p->channel_format = channel_format;
944 	   rstat = RM_CHILL;
945 	   break;
946 
947        case RM_OFFSCREEN_MONO_CHANNEL:
948        case RM_OFFSCREEN_REDBLUE_STEREO_CHANNEL:
949        case RM_OFFSCREEN_BLUERED_STEREO_CHANNEL:
950 	   p->offscreen = RM_TRUE;
951 	   p->channel_format = channel_format;
952 	   rmPipeSetSwapBuffersFunc(p, NULL); /* turn off swapbuffers when
953 						 rendering offscreen */
954 	   rstat = RM_CHILL;
955 	   break;
956 
957        default:
958 	  rmError("rmPipeSetChannelFormat() error: the input channel format is not recognized.");
959 	  return (RM_WHACKED);
960        }
961 
962     if (rstat == RM_CHILL)
963 	private_rmSetChannelRenderFunc(p);
964 
965     return(rstat);
966 }
967 
968 
969 /*
970  * ----------------------------------------------------
971  * @Name rmPipeGetChannelFormat
972  @pstart
973  RMenum rmPipeGetChannelFormat (const RMpipe *toQuery)
974  @pend
975 
976  @astart
977  const RMpipe *toQuery - a handle to an RMpipe object (input).
978  @aend
979 
980  @dstart
981 
982  Returns to the caller the current channel format of an RMpipe
983  object. A successful return value will be one of RM_MONO_CHANNEL,
984  RM_REDBLUE_STEREO_CHANNEL, RM_BLUERED_STEREO_CHANNEL or
985  RM_MBUF_STEREO_CHANNEL. A return value of RM_WHACKED indicates an
986  error of some type.
987 
988  @dend
989  * ----------------------------------------------------
990  */
991 RMenum
rmPipeGetChannelFormat(const RMpipe * p)992 rmPipeGetChannelFormat (const RMpipe *p)
993 {
994     if (RM_ASSERT(p, "rmPipeGetChannelFormat() error: the input RMpipe pointer is NULL.") == RM_WHACKED)
995 	return(RM_WHACKED);
996 
997     return(p->channel_format);
998 }
999 
1000 /*
1001  * ----------------------------------------------------
1002  * @Name rmPipeSetInitMatrixStackMode
1003  @pstart
1004  RMenum rmPipeSetInitMatrixStackMode(RMpipe *toModify,
1005 			             RMenum newMode)
1006  @pend
1007 
1008  @astart
1009  RMpipe *toModify - a handle to an RMpipe object (modified).
1010  RMenum newMode - an RMenum value, either RM_TRUE or RM_FALSE, that
1011     controls how matrix transformations are applied to the OpenGL
1012     matrix stack.
1013  @aend
1014 
1015  @dstart
1016 
1017  By default, OpenRM will initialize the OpenGL matrix stack during
1018  a frame rendering operation by setting GL_MODELVIEW, GL_PROJECTION and
1019  GL_TEXTURE matrices to the Identity matrix. This behavior may be
1020  overridden, so that OpenRM will honor any existing matrices in
1021  the matrix stacks while accumulating nested transformations. This is
1022  helpful in some deployment environments, such as combining OpenRM
1023  with CAVElib (www.vrco.com).
1024 
1025  When the input enumerator is set to RM_TRUE (the default), OpenRM
1026  will initialize the OpenGL matrix stack to the identity matrix prior
1027  to accumulating transformations during rendering. When the input enum
1028  is set to RM_FALSE, OpenRM will NOT initialize the matrix stack, and
1029  any existing transformations within the scene graph will be
1030  accumulated with the contents of the matrix stack at render time.
1031 
1032  More precisely, if the GL_MODELVIEW matrix stack has the matrix M,
1033  and the scene graph defines a matrix transformation S, the combined
1034  transformation will be S*M (left multiplication), so that the scene
1035  graph transformation S is effectively applied prior to the outer
1036  transformation M when vertex data moves down the OpenGL transformation
1037  pipeline.
1038 
1039  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1040  @dend
1041  * ----------------------------------------------------
1042  */
1043 RMenum
rmPipeSetInitMatrixStackMode(RMpipe * t,RMenum newMode)1044 rmPipeSetInitMatrixStackMode(RMpipe *t,
1045 			     RMenum newMode)
1046 {
1047     if (RM_ASSERT(t,"rmPipeSetInitMatrixStackMode() error: the input RMpipe is NULL. ") == RM_WHACKED)
1048 	return(RM_WHACKED);
1049 
1050     if ((newMode != RM_TRUE) && (newMode != RM_FALSE))
1051     {
1052 	rmError("rmPipeSetInitMatrixStackMode() error: the input newMode RMenum is neither RM_TRUE nor RM_FALSE");
1053 	return(RM_WHACKED);
1054     }
1055 
1056     t->initMatrixStack = newMode;	/* RM_TRUE or RM_FALSE */
1057     return(RM_CHILL);
1058 }
1059 
1060 /*
1061  * ----------------------------------------------------
1062  * @Name rmPipeGetInitMatrixStackMode
1063  @pstart
1064  RMenum rmPipeGetInitMatrixStackMode(const RMpipe *toQuery)
1065  @pend
1066 
1067  @astart
1068  const RMpipe *toQuery - a handle to an RMpipe object (queried).
1069  @aend
1070 
1071  @dstart
1072  This routine will return the "init matrix stack" attribute of an
1073  RMpipe object. A return value of RM_TRUE means the OpenGL matrix
1074  stack will be initialized by OpenRM during frame rendering, while
1075  a value of RM_FALSE means that any existing values in the OpenGL
1076  matrix stack will be honored during rendering.
1077 
1078  A return value of RM_WHACKED indicates an error condition.
1079  @dend
1080  * ----------------------------------------------------
1081  */
1082 RMenum
rmPipeGetInitMatrixStackMode(const RMpipe * t)1083 rmPipeGetInitMatrixStackMode(const RMpipe *t)
1084 {
1085     if (RM_ASSERT(t,"rmPipeGetInitMatrixStackMode() error: the input RMpipe is NULL. ") == RM_WHACKED)
1086 	return(RM_WHACKED);
1087 
1088     return(t->initMatrixStack);
1089 }
1090 
1091 /*
1092  * ----------------------------------------------------
1093  * @Name rmPipeSetRenderPassEnable
1094  @pstart
1095  RMenum rmPipeSetRenderPassEnable(RMpipe *toModify,
1096 			          RMenum opaque3DEnable,
1097 				  RMenum transparent3DEnable,
1098 				  RMenum opaque2DEnable)
1099  @pend
1100 
1101  @astart
1102  RMpipe *toModify - a handle to an RMpipe (modified).
1103 
1104  RMenum opaque3DEnable,transparent3DEnable, opaque2DEnable - RMenum
1105     values, may be either RM_TRUE or RM_FALSE.
1106  @aend
1107 
1108  @dstart
1109 
1110  This routine is used to selectely enable or disable one of the
1111  rendering passes of the RM multipass rendering engine. Applications
1112  may not change the order of the rendering passes, but may selectively
1113  enable or disable a given pass. The order of the passes is:
1114 
1115  1. 3D Opaque
1116 
1117  2. 3D Transparent
1118 
1119  3. 2D Opaque
1120 
1121  (There may be a 2D transparent pass in a later release.)
1122 
1123  During each of these passes, traversal filters are applied at each
1124  node of the RM scene graph. If, at any stage during the traversal,
1125  the scene graph node does not pass the traversal filter test, that
1126  node, and any descendents, are not processed.
1127 
1128  For this reason, developers should carefully consider scene graph
1129  design such that 3D opaque, 3D transparent and 2D objects are
1130  appropriately partitioned within the scene graph itself.
1131 
1132  Background scene operations (background clear color, background image
1133  tile, background depth value, background depth image) are performed
1134  during rendering passes 1 and 3. A common RM error is to place a
1135  background scene operation at a node that is processed during
1136  multiple rendering passes.
1137 
1138  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1139 
1140  @dend
1141  * ----------------------------------------------------
1142  */
1143 RMenum
rmPipeSetRenderPassEnable(RMpipe * t,RMenum opaque3DEnable,RMenum transparent3DEnable,RMenum opaque2DEnable)1144 rmPipeSetRenderPassEnable (RMpipe *t,
1145 			   RMenum opaque3DEnable,
1146 			   RMenum transparent3DEnable,
1147 			   RMenum opaque2DEnable)
1148 {
1149     if (RM_ASSERT(t, "rmPipeSetRenderPassEnable() error: the input RMpipe is NULL") == RM_WHACKED)
1150 	return(RM_WHACKED);
1151 
1152     t->opaque3DEnable = opaque3DEnable;
1153     t->transparent3DEnable = transparent3DEnable;
1154     t->opaque2DEnable = opaque2DEnable;
1155     return(RM_CHILL);
1156 }
1157 
1158 
1159 /*
1160  * ----------------------------------------------------
1161  * @Name rmPipeGetRenderPassEnable
1162  @pstart
1163  RMenum rmPipeGetRenderPassEnable(const RMpipe *t,
1164 			          RMenum *opaque3DEnableReturn,
1165 				  RMenum *transparent3DEnableReturn,
1166 				  RMenum *opaque2DEnableReturn)
1167 
1168  @pend
1169 
1170  @astart
1171  const RMpipe *t - a handle to an RMpipe (input).
1172 
1173  RMenum *opaque3DEnableReturn, *transparent3DEnableReturn,
1174     *opaque2DEnableReturn - handles to RMenum values (result).
1175  @aend
1176 
1177  @dstart
1178 
1179  This routine is used to obtain the boolean values that indicate if
1180  a particular rendering pass is enabled in the RMpipe.
1181 
1182  Each of the return parameters is optional - a value of NULL will skip
1183  reporting of that particular rendering pass.
1184 
1185  Upon success, RM_CHILL is returned, and RM_TRUE or RM_FALSE is copied
1186  into non-NULL caller-supplied memory for each of the RMpipe rendering
1187  passes.  Otherwise, RM_WHACKED is returned, and caller-supplied
1188  memory remains unmodified.
1189 
1190  @dend
1191  * ----------------------------------------------------
1192  */
1193 RMenum
rmPipeGetRenderPassEnable(const RMpipe * t,RMenum * opaque3DEnableReturn,RMenum * transparent3DEnableReturn,RMenum * opaque2DEnableReturn)1194 rmPipeGetRenderPassEnable (const RMpipe *t,
1195 			   RMenum *opaque3DEnableReturn,
1196 			   RMenum *transparent3DEnableReturn,
1197 			   RMenum *opaque2DEnableReturn)
1198 {
1199     if (RM_ASSERT(t, "rmPipeSetGenderPassEnable() error: the input RMpipe is NULL") == RM_WHACKED)
1200 	return(RM_WHACKED);
1201 
1202     if (opaque3DEnableReturn != NULL)
1203 	*opaque3DEnableReturn = t->opaque3DEnable;
1204     if (transparent3DEnableReturn != NULL)
1205 	*transparent3DEnableReturn = t->transparent3DEnable;
1206     if (opaque2DEnableReturn != NULL)
1207 	*opaque2DEnableReturn = t->opaque2DEnable;
1208 
1209     return(RM_CHILL);
1210 }
1211 
1212 
1213 /*
1214  * ----------------------------------------------------
1215  * @Name rmPipeSetWindowSize
1216  @pstart
1217  RMenum rmPipeSetWindowSize (RMpipe *toModify,
1218 		             int newWidth,
1219 			     int newHeight)
1220  @pend
1221 
1222  @astart
1223  RMpipe *toModify - a handle to an RMpipe (modified).
1224 
1225  int newWidth, newHeight - integer values specifing the pixel width
1226     and height of the window associated with an RMpipe (input).
1227  @aend
1228 
1229  @dstart
1230 
1231  This routine sets the RMpipe's notion of pixel width and height of
1232  it's associated display window. RM_CHILL is returned upon success, or
1233  RM_WHACKED upon failure.
1234 
1235  The most typical use of this routine will be when an application
1236  detects, through an event loop, that the window geometry has
1237  changed. The application is reponsible for notifying RM of such
1238  changes; RM doesn't manage events and doesn't keep track of the size
1239  of the display window.
1240 
1241  This routine is called by rmPipeSetWindow().
1242 
1243  @dend
1244  * ----------------------------------------------------
1245  */
1246 RMenum
rmPipeSetWindowSize(RMpipe * pipe,int width,int height)1247 rmPipeSetWindowSize (RMpipe *pipe,
1248 		     int width,
1249 		     int height)
1250 {
1251     if (RM_ASSERT(pipe, "rmPipeSetWindowSize() error: the input RMpipe object is NULL.") == RM_WHACKED)
1252 	return(RM_WHACKED);
1253 
1254     pipe->xwindow_width = width;
1255     pipe->xwindow_height = height;
1256     return(RM_CHILL);
1257 }
1258 
1259 
1260 /*
1261  * ----------------------------------------------------
1262  * @Name rmPipeGetWindowSize
1263  @pstart
1264  RMenum rmPipeGetWindowSize (const RMpipe *toQuery,
1265 		             int *widthReturn,
1266 			     int *heightReturn)
1267  @pend
1268 
1269  @astart
1270  const RMpipe *toQuery - a handle to an RMpipe (input).
1271 
1272  int *widthReturn, *heightReturn - pointers to integers (return).
1273     Values of NULL are acceptable.
1274  @aend
1275 
1276  @dstart
1277 
1278  This routine returns via caller-supplied memory the named RMpipe's
1279  notion of the current window width and height. RM_CHILL is returned
1280  upon success, or RM_WHACKED upon failure.
1281 
1282  Callers interested in only width or height may specify NULL for the
1283  parameter for which information is not requested.
1284 
1285  @dend
1286  * ----------------------------------------------------
1287  */
1288 RMenum
rmPipeGetWindowSize(const RMpipe * pipe,int * width,int * height)1289 rmPipeGetWindowSize (const RMpipe *pipe,
1290 		     int *width,
1291 		     int *height)
1292 {
1293     if (RM_ASSERT(pipe, "rmPipeGetWindowSize() error: the input RMpipe is NULL") == RM_WHACKED)
1294 	return(RM_WHACKED);
1295 
1296     if (width != NULL)
1297 	*width = pipe->xwindow_width;
1298     if (height != NULL)
1299 	*height = pipe->xwindow_height;
1300     return(RM_CHILL);
1301 }
1302 
1303 
1304 /*
1305  * ----------------------------------------------------
1306  * @Name rmPipeSetSwapBuffersFunc
1307  @pstart
1308  RMenum rmPipeSetSwapBuffersFunc (RMpipe *toModify,
1309 			          void (newFunc)(RMpipe *))
1310  @pend
1311 
1312  @astart
1313  RMpipe *toModify - a handle to an RMpipe (modified).
1314 
1315  void (newFunc)(RMpipe *) - a handle to an application callback
1316     (input).
1317  @aend
1318 
1319  @dstart
1320 
1321  Use this routine to set the "swapbuffers" callback function
1322  associated with an RMpipe object. Returns RM_CHILL upon success, or
1323  RM_WHACKED upon failure.
1324 
1325  The swapbuffers function is invoked after rendering has completed,
1326  and after the post-render barrier function, and the post-render
1327  framebuffer and depthbuffer grab callbacks, if any. By default,
1328  rmSwapBuffers() is assigned to all RMpipe objects' swapbuffers
1329  callback functions at the time the RMpipe is created with RMpipe
1330  new. The function rmSwapBuffers() calls the native window-system
1331  procedure that causes front and back buffers to be swapped.
1332 
1333  If the application overrides the default swapbuffers function, the
1334  application callback will be provided a single input parameter: a
1335  handle to an RMpipe object. The RMpipe object contains enough
1336  information to enable application code to do the swapbuffers call.
1337 
1338  @dend
1339  * ----------------------------------------------------
1340  */
1341 RMenum
rmPipeSetSwapBuffersFunc(RMpipe * p,RMenum (* sbfunc)(const RMpipe *))1342 rmPipeSetSwapBuffersFunc (RMpipe *p,
1343 			  RMenum (*sbfunc)(const RMpipe *))
1344 {
1345 #if 0
1346     if ((RM_ASSERT(p, "rmPipeSetSwapBuffersFunc() error: the input RMpipe is NULL") == RM_WHACKED) ||
1347 	(RM_ASSERT((void *)sbfunc, "rmPipeSetSwapBuffersFunc() error: the input function handle is NULL") == RM_WHACKED))
1348 	return(RM_WHACKED);
1349 #endif
1350     /* cave change: allow for setting a NULL swapbuff func */
1351     if (RM_ASSERT(p, "rmPipeSetSwapBuffersFunc() error: the input RMpipe is NULL") == RM_WHACKED)
1352 	return(RM_WHACKED);
1353 
1354     p->swapBuffersFunc = sbfunc;
1355     return(RM_CHILL);
1356 }
1357 
1358 
1359 /*
1360  * ----------------------------------------------------
1361  * @Name rmPipeSetPostRenderFunc
1362  @pstart
1363  RMenum rmPipeSetPostRenderFunc (RMpipe *toModify,
1364 			         void (*postRenderFunc)(const RMimage *, RMenum))
1365  @pend
1366 
1367  @astart
1368  RMpipe *toModify - a handle to an RMpipe (modified).
1369 
1370  void (*postRenderFunc)(RMimage *, RMenum) - a handle to an
1371     application callback.
1372  @aend
1373 
1374  @dstart
1375 
1376  This routine assigns a "post render" application callback to the
1377  RMpipe. The post render callback is invoked after rendering has
1378  occured, and after the "post render barrier function" has been called
1379  (if any), but before the "post render depthbuffer function" (if any)
1380  and before the swapbuffers function. RM_CHILL is returned upon
1381  success, or RM_WHACKED upon failure.
1382 
1383  Use a value of NULL for the postRenderFunc to effectively disable
1384  post rendering callbacks.
1385 
1386  The purpose of the post render function is to allow applications to
1387  grab a copy of the color planes of the framebuffer after rendering
1388  has occured. If you want the raw image data produced by the
1389  rendering, this is the path to use.
1390 
1391  When the application callback is invoked, the callback is invoked
1392  with two parameters. The first is a handle to an RMimage object. Use
1393  rmImageGetPixelData() to obtain the raw pixel data from this image.
1394  At this time (Jan 2000) the image provided to the app callback is in
1395  GL_RGBA, GL_UNSIGNED_BYTE format. Applications are advised to use the
1396  rmImageGet*() series of routines to obtain RMimage configuration
1397  information. In particular, pay close attention to scanline-padding
1398  issues.
1399 
1400  The second parameter provided to the application callback is an
1401  RMenum value that is one of RM_ALL_CHANNELS, RM_LEFT_CHANNEL or
1402  RM_RIGHT_CHANNEL. Multibuffered stereo channels will invoke the
1403  application callback twice, once for each channel. Anaglyph stereo
1404  formats (RM_REDBLUE_STEREO_CHANNEL and RM_BLUERED_STEREO_CHANNEL)
1405  will trigger the callback just once. This may change in the future
1406  (Jan 2000).
1407 
1408  The RMimage object provided to applications is managed by RM.
1409 
1410  @dend
1411  * ----------------------------------------------------
1412  */
1413 RMenum
rmPipeSetPostRenderFunc(RMpipe * p,void (* prfunc)(const RMimage *,RMenum))1414 rmPipeSetPostRenderFunc (RMpipe *p,
1415 			 void (*prfunc)(const RMimage *, RMenum))
1416 {
1417     if (RM_ASSERT(p, "rmPipeSetPostRenderFunc() error: the input RMpipe object is NULL") == RM_WHACKED)
1418 	return(RM_WHACKED);
1419 
1420     p->postrenderfunc = prfunc;
1421     return(RM_CHILL);
1422 }
1423 
1424 
1425 /*
1426  * ----------------------------------------------------
1427  * @Name rmPipeSetPostRenderDepthFunc
1428  @pstart
1429  RMenum rmPipeSetPostRenderDepthFunc (RMpipe *toModify,
1430 			              void (*postRenderDepthFunc)(const RMimage *, RMenum))
1431  @pend
1432 
1433  @astart
1434  RMpipe *toModify - a handle to an RMimage object (modified).
1435 
1436  void (*postRenderDepthFunc)(RMimage *, RMenum) - a handle to an
1437     application callback (input).
1438  @aend
1439 
1440  @dstart
1441 
1442  Use this routine to assign a "post render depth buffer" callback to
1443  an RMpipe object. RM_CHILL is returned upon success, or RM_WHACKED
1444  upon failure.
1445 
1446  Use a value of NULL for the postRenderDepthFunc to effectively
1447  disable this post rendering callback.
1448 
1449  Whereas the "post render callback" gives applications access to the
1450  color planes of the framebuffer after rendering, the purpose of this
1451  callback is to give applications access to the depth buffer after
1452  rendering has completed. Assigning a "post render depth buffer
1453  callback" will cause the application callback to be invoked after
1454  rendering, and after the post-render barrier function, after the post
1455  render callback (the color planes) but before the swapbuffers
1456  function.
1457 
1458  The pixel data of the RMimage object provided to the application, the
1459  first application callback parameter, contains the contents of the
1460  depth buffer of the scene just rendered. The pixel data in the
1461  RMimage object is in RM_FLOAT format. Applications should use the
1462  rmImageGet*() series of routines to query specific RMimage
1463  attributes.
1464 
1465  The second parameter provided to the application callback is an
1466  RMenum value that is one of RM_ALL_CHANNELS, RM_LEFT_CHANNEL or
1467  RM_RIGHT_CHANNEL. Multibuffered stereo channels will invoke the
1468  application callback twice, once for each channel. Anaglyph stereo
1469  formats (RM_REDBLUE_STEREO_CHANNEL and RM_BLUERED_STEREO_CHANNEL)
1470  will trigger the callback just once. This may change in the future
1471  (Jan 2000).
1472 
1473  The RMimage object provided to applications is managed by RM.
1474 
1475  @dend
1476  * ---------------------------------------------------- */
1477 RMenum
rmPipeSetPostRenderDepthFunc(RMpipe * p,void (* prfunc)(const RMimage *,RMenum))1478 rmPipeSetPostRenderDepthFunc (RMpipe *p,
1479 			      void (*prfunc)(const RMimage *, RMenum))
1480 {
1481     if (RM_ASSERT(p, "rmPipeSetPostRenderDepthFunc() error: the input RMpipe object is NULL") == RM_WHACKED)
1482 	return(RM_WHACKED);
1483 
1484     p->postrender_depthbufferfunc = prfunc;
1485     return(RM_CHILL);
1486 }
1487 
1488 
1489 /*
1490  * ----------------------------------------------------
1491  * @Name rmPipeSetPostRenderBarrierFunc
1492  @pstart
1493  RMenum rmPipeSetPostRenderBarrierFunc (RMpipe *toModify,
1494 			                void (*barrierFunc)(RMpipe *))
1495  @pend
1496 
1497  @astart
1498  RMpipe *toModify - a handle to an RMpipe object (modified).
1499 
1500  void (*barrierFunc)(RMpipe *) - a handle to an application callback
1501     (input).
1502 
1503  @aend
1504 
1505  @dstart
1506 
1507  Use this routine to set the "post render barrier function" on an
1508  RMpipe object. Use a value of NULL for barrierFunc to disable this
1509  callback, or remove a previously installed callback. Returns RM_CHILL
1510  upon success, or RM_WHACKED upon failure.
1511 
1512  The "post render barrier" callback, if present, will be invoked
1513  immediately after rendering, but prior to any other callbacks (post
1514  render color planes callback, post render depth buffer callback or
1515  swapbuffers). This routine is intended for use by parallel rendering
1516  applications.
1517 
1518  The application callback will be provided a single parameter, an
1519  RMpipe.
1520 
1521  @dend
1522  * ----------------------------------------------------
1523  */
1524 RMenum
rmPipeSetPostRenderBarrierFunc(RMpipe * t,void (* barrierFunc)(RMpipe *))1525 rmPipeSetPostRenderBarrierFunc (RMpipe *t,
1526 			        void (*barrierFunc)(RMpipe *))
1527 {
1528     if (RM_ASSERT(t, "rmPipeSetPostRenderBarrierFunc error: the input RMpipe * is NULL.") == RM_WHACKED)
1529 	return(RM_WHACKED);
1530 
1531     t->postRenderBarrierFunc = barrierFunc;
1532     return(RM_CHILL);
1533 }
1534 
1535 /*
1536  * ----------------------------------------------------
1537  * @Name rmPipeProcessingModeIsMultithreaded
1538  @pstart
1539  RMenum rmPipeProcessingModeIsMultithreaded (const RMpipe *toQuery)
1540  @pend
1541 
1542  @astart
1543  const RMpipe *toQuery - a handle to an RMpipe (input).
1544  @aend
1545 
1546  @dstart
1547  This routine can be used to determine if the processing mode of
1548  the RMpipe toQuery is a multithreaded format. If toQuery's
1549  processing mode is either RM_PIPE_MULTISTAGE_VIEW_PARALLEL or
1550  RM_PIPE_MULTISTAGE_PARALLEL, this routine will return RM_TRUE.
1551  Otherwise, RM_FALSE is returned.
1552 
1553  See also rmPipeGetProcessingMode().
1554  @dend
1555  * ----------------------------------------------------
1556  */
1557 RMenum
rmPipeProcessingModeIsMultithreaded(const RMpipe * toQuery)1558 rmPipeProcessingModeIsMultithreaded(const RMpipe *toQuery)
1559 {
1560     RMenum pmode = rmPipeGetProcessingMode(toQuery);
1561 
1562     if ((pmode == RM_PIPE_MULTISTAGE_VIEW_PARALLEL) ||
1563 	(pmode == RM_PIPE_MULTISTAGE_PARALLEL))
1564 	return(RM_TRUE);
1565     else
1566 	return(RM_FALSE);
1567 }
1568 
1569 /*
1570  * ----------------------------------------------------
1571  * @Name rmPipeGetProcessingMode
1572  @pstart
1573  RMenum rmPipeGetProcessingMode (const RMpipe *toQuery)
1574  @pend
1575 
1576  @astart
1577  const RMpipe *toQuery - a handle to an RMpipe object (input).
1578  @aend
1579 
1580  @dstart
1581  This routine will return the processing mode of the RMpipe toQuery.
1582  Upon success, one of the following is returned to the caller:
1583  RM_PIPE_SERIAL, RM_PIPE_MULTISTAGE, RM_PIPE_MULTISTAGE_PARALLEL or
1584  RM_PIPE_MULTISTAGE_VIEW_PARALLEL.
1585 
1586  Upon failure, RM_WHACKED is returned to the caller.
1587  @dend
1588  * ----------------------------------------------------
1589  */
1590 RMenum
rmPipeGetProcessingMode(const RMpipe * toQuery)1591 rmPipeGetProcessingMode(const RMpipe *toQuery)
1592 {
1593     if (RM_ASSERT(toQuery,"rmPipeGetProcessingMode() error: the input RMpipe is NULL") == RM_WHACKED)
1594 	return(RM_WHACKED);
1595     return(toQuery->processingMode);
1596 }
1597 
1598 /*
1599  * ----------------------------------------------------
1600  * @Name rmPipeSetProcessingMode
1601  @pstart
1602  RMenum rmPipeSetProcessingMode (RMpipe *toModify,
1603 			         RMenum newMode)
1604  @pend
1605 
1606  @astart
1607  RMpipe *toModify - a handle to an RMpipe (modified).
1608  RMenum newMode - a RMenum specifying a processing mode. This value must
1609  be one of:  RM_PIPE_SERIAL, RM_PIPE_MULTISTAGE, RM_PIPE_MULTISTAGE_PARALLEL
1610  or RM_PIPE_MULTISTAGE_VIEW_PARALLEL.
1611 
1612  @aend
1613 
1614  @dstart
1615  This routine will select the "processing mode" for an RMpipe object.
1616  The processing mode assigns a rendering engine to the RMpipe for use
1617  in subsequent rendering operations. Upon success, RM_CHILL is returned
1618  to the caller; upon failure, RM_WHACKED is returned.
1619 
1620  Applications may set the processing mode on an RMpipe any time between
1621  when it is created (using either rmPipeNew or rmPipeInit) and the
1622  first time a frame is rendered. As of this time (June 2001), it is
1623  not possible to change the processing mode of an RMpipe, and this routine
1624  will not detect this error condition. Your application will likely
1625  crash if you attempt to alter the processing mode of an RMpipe after
1626  the first frame has been drawn.
1627 
1628  OpenRM uses a two-stage rendering pipeline: a view traversal of the
1629  scene graph prepares a list of things to be drawn during a rendering
1630  traversal.
1631 
1632  The following processing modes are supported:
1633 
1634  RM_PIPE_MULTISTAGE - uses a two-stage rendering traversal (view, render), and
1635  both stages are called sequentially within the same process/thread as
1636  the caller. There is no parallelization in this processing mode.
1637 
1638  RM_PIPE_MULTISTAGE_PARALLEL - each of the two rendering stages are called
1639  from detached Posix threads. The render thread will assume ownership of
1640  the OpenGL context (applications should NOT make any OpenGL calls except
1641  from within node callbacks invoked by the OpenRM renderer). This mode
1642  is fully parallelized.
1643 
1644  RM_PIPE_MULTISTAGE_VIEW_PARALLEL - the view traversal is assigned to a
1645  detached thread, while the render traversal remains in the same
1646  execution process/thread as the caller (and does not attempt to exert
1647  ownership of the OpenGL rendering context). This mode is also fully
1648  parallelized, and is quite useful when combining OpenRM with other
1649  toolkits that provide device and event management and which make
1650  assumptions about ownership of the OpenGL rendering context (e.g.,
1651  CAVELibrary, VRJuggler, FLTK, etc.).
1652  @dend
1653  * ----------------------------------------------------
1654  */
1655 RMenum
rmPipeSetProcessingMode(RMpipe * toModify,RMenum newMode)1656 rmPipeSetProcessingMode(RMpipe *toModify,
1657 			RMenum newMode)
1658 {
1659     if (RM_ASSERT(toModify,"rmPipeSetProcessingMode() error: the input RMpipe is NULL") == RM_WHACKED)
1660 	return(RM_WHACKED);
1661 
1662     if ((newMode != RM_PIPE_SERIAL) && (newMode != RM_PIPE_MULTISTAGE) && (newMode != RM_PIPE_MULTISTAGE_PARALLEL) && (newMode != RM_PIPE_MULTISTAGE_VIEW_PARALLEL))
1663     {
1664 	rmError("rmPipeSetProcessingMode() error: the input processing mode is not valid.");
1665 	return(RM_WHACKED);
1666     }
1667 
1668 #ifdef _NO_PTHREADS
1669     /*
1670      * if we're not using or don't have access to pthreads, permit use of
1671      * only one of the single-threaded processing modes.
1672      */
1673     if ((newMode == RM_PIPE_MULTISTAGE_PARALLEL) || (newMode == RM_PIPE_MULTISTAGE_VIEW_PARALLEL))
1674     {
1675         rmWarning("You are using a version of RM Scene Graph that was built without threads support and have requested an RMpipe processing mode that requires threading. The RMpipe processing mode you will be using instead is RM_PIPE_MULTISTAGE.");
1676 	newMode = RM_PIPE_MULTISTAGE;
1677     }
1678 #endif
1679 
1680     toModify->processingMode = newMode;
1681 
1682     /* need to update the renderfunc based on new processing mode */
1683     rmPipeSetChannelFormat(toModify, rmPipeGetChannelFormat(toModify));
1684     return(RM_CHILL);
1685 }
1686 
1687 /*
1688  * ----------------------------------------------------
1689  * @Name rmPipeGetDisplayListEnable
1690  @pstart
1691  RMenum rmPipeGetDisplayListEnable (const RMpipe *toQuery)
1692  @pend
1693 
1694  @astart
1695  const RMpipe *toQuery - a handle to an RMpipe object (input).
1696  @aend
1697 
1698  @dstart
1699  This routine will return the RMpipe's notion of whether or not it will use
1700  OpenGL display lists when rendering primitives. The returned value will be
1701  either RM_TRUE, which indicates that display lists will be used when
1702  rendering primitives on the RMpipe, or RM_FALSE, which indicates that no
1703  RMprimitives will be drawn using display lists.
1704 
1705  See also: rmPipeSetDisplayListEnable, rmPrimitiveSetDisplayListEnable.
1706  @dend
1707  * ----------------------------------------------------
1708  */
1709 RMenum
rmPipeGetDisplayListEnable(const RMpipe * toQuery)1710 rmPipeGetDisplayListEnable(const RMpipe *toQuery)
1711 {
1712     if (RM_ASSERT(toQuery,"rmPipeGetDisplayListEnable() error: the input RMpipe is NULL") == RM_WHACKED)
1713 	return(RM_WHACKED);
1714     return(toQuery->displayListEnableBool);
1715 }
1716 
1717 /*
1718  * ----------------------------------------------------
1719  * @Name rmPipeSetDisplayListEnable
1720  @pstart
1721  RMenum rmPipeSetDisplayListEnable (RMpipe *toModify,
1722 			            RMenum newMode)
1723  @pend
1724 
1725  @astart
1726  RMpipe *toModify - a handle to an RMpipe (modified).
1727  RMenum newMode - a RMenum specifying whether or not RMprimitives rendered on
1728    the RMpipe toModify will use display lists. The input value should be
1729    either RM_TRUE or RM_FALSE.
1730 
1731  @aend
1732 
1733  @dstart
1734 
1735  Set's the RMpipe's policy on the use of display lists. When the value
1736  of newMode is set to RM_TRUE, use of display lists on the RMpipe toModify
1737  is enabled. When set to RM_FALSE, use of display lists on the RMpipe is
1738  disabled. The default policy for use of display lists is RM_TRUE, and this
1739  value is set at the time the RMpipe is created. You can override the
1740  default behavior by calling rmPipeSetDisplayListEnable() with a value
1741  of RM_FALSE.
1742 
1743  Use of display lists can greatly accelerate rendering performance on
1744  many platforms. By default, RM will attempt to create display lists for
1745  RMprimitives during rendering, and reuse them in subsequent renderings.
1746 
1747  Applications can control use of display lists in two ways: at the RMpipe
1748  level, and at the RMprimitive level. At the RMpipe level, you can
1749  enable or disable use of display lists for all RMprimitives drawn on RMpipe
1750  using the routine rmPipeSetDisplayListEnable. At the RMprimitive level,
1751  you can enable or disable the use of display lists for a single primitive
1752  using rmPrimitiveSetDisplayListEnable().
1753 
1754  The RMprimitive display list  policy does not override the display list
1755  policy set at the RMpipe level. In other words, if the policy at the RMpipe
1756  level is set to RM_FALSE, then no display lists will be used, even if the
1757  policy at the RMprimitive level is set to RM_TRUE. On the other hand, if
1758  the policy at the RMpipe level is set to RM_TRUE, a policy at the RMprimitive
1759  level of RM_FALSE will result on no display lists being used for the
1760  one RMprimitive. In order for display lists to be used at any given
1761  RMprimitive, the logical AND of RMpipe and RMprimitive display list
1762  policies must be RM_TRUE.
1763 
1764  To obtain the current display list use policy at an RMpipe, use the routine
1765  rmPipeGetDisplayListEnable().
1766 
1767  See also rmPrimitiveSetDisplayListEnable().
1768  @dend
1769  * ----------------------------------------------------
1770  */
1771 RMenum
rmPipeSetDisplayListEnable(RMpipe * toModify,RMenum newMode)1772 rmPipeSetDisplayListEnable(RMpipe *toModify,
1773 			   RMenum newMode)
1774 {
1775     if (RM_ASSERT(toModify,"rmPipeSetDisplayListEnable() error: the input RMpipe is NULL") == RM_WHACKED)
1776 	return(RM_WHACKED);
1777 
1778     if ((newMode != RM_TRUE) && (newMode != RM_FALSE))
1779     {
1780 	rmError("rmPipeSetDisplayListEnable() error: the new display list use policy mode is not valid.");
1781 	return(RM_WHACKED);
1782     }
1783 
1784     toModify->displayListEnableBool = newMode;
1785 
1786     return(RM_CHILL);
1787 }
1788 
1789 /*
1790  * ----------------------------------------------------
1791  * @Name rmPipeSetCommSize
1792  @pstart
1793  RMenum rmPipeSetCommSize (RMpipe *toModify)
1794  @pend
1795 
1796  @astart
1797  RMpipe *toModify - a handle to an RMpipe object (modified).
1798  @aend
1799 
1800  @dstart
1801 
1802  Sets the global number of PEs in an MPI-parallel application.
1803  Docs need to be better written.
1804 
1805  @dend
1806  * ----------------------------------------------------
1807  */
1808 RMenum
rmPipeSetCommSize(RMpipe * toModify,int globalNPE)1809 rmPipeSetCommSize (RMpipe *toModify,
1810 		   int globalNPE)
1811 {
1812     if (RM_ASSERT(toModify,"rmPipeSetCommSize() error: the input RMpipe is NULL") == RM_WHACKED)
1813 	return(RM_WHACKED);
1814 
1815     toModify->globalNPE = globalNPE;
1816     return RM_CHILL;
1817 }
1818 
1819 /*
1820  * ----------------------------------------------------
1821  * @Name rmPipeGetCommSize
1822  @pstart
1823  int rmPipeSetCommSize (const RMpipe *toQuery)
1824  @pend
1825 
1826  @astart
1827  const RMpipe *toQuery - a handle to an RMpipe object (input).
1828  @aend
1829 
1830  @dstart
1831 
1832  Returns the global number of PEs in an MPI-parallel application.
1833  Docs need to be better written.
1834 
1835  @dend
1836  * ----------------------------------------------------
1837  */
1838 int
rmPipeGetCommSize(const RMpipe * toQuery)1839 rmPipeGetCommSize (const RMpipe *toQuery)
1840 {
1841     if (RM_ASSERT(toQuery,"rmPipeGetCommSize() error: the input RMpipe is NULL") == RM_WHACKED)
1842 	return(RM_WHACKED);
1843 
1844     return toQuery->globalNPE;
1845 }
1846 
1847 /*
1848  * ----------------------------------------------------
1849  * @Name rmPipeSetRank
1850  @pstart
1851  RMenum rmPipeSetRank (RMpipe *toModify)
1852  @pend
1853 
1854  @astart
1855  RMpipe *toModify - a handle to an RMpipe object (modified).
1856  @aend
1857 
1858  @dstart
1859 
1860  Sets the rank value of one RMpipe in an MPI-parallel application.
1861  Docs need to be better written.
1862 
1863  @dend
1864  * ----------------------------------------------------
1865  */
1866 RMenum
rmPipeSetRank(RMpipe * toModify,int myRank)1867 rmPipeSetRank (RMpipe *toModify,
1868 	       int myRank)
1869 {
1870     if (RM_ASSERT(toModify,"rmPipeSetMyRank() error: the input RMpipe is NULL") == RM_WHACKED)
1871 	return(RM_WHACKED);
1872 
1873     toModify->myRank = myRank;
1874     return RM_CHILL;
1875 }
1876 
1877 /*
1878  * ----------------------------------------------------
1879  * @Name rmPipeGetRank
1880  @pstart
1881  int rmPipeGetRank (const RMpipe *toQuery)
1882  @pend
1883 
1884  @astart
1885  const RMpipe *toQuery - a handle to an RMpipe object (input).
1886  @aend
1887 
1888  @dstart
1889 
1890  Obtains the rank value of one RMpipe in an MPI-parallel application.
1891  Docs need to be better written.
1892 
1893  @dend
1894  * ----------------------------------------------------
1895  */
1896 int
rmPipeGetRank(const RMpipe * toQuery)1897 rmPipeGetRank (const RMpipe *toQuery)
1898 {
1899     if (RM_ASSERT(toQuery,"rmPipeGetMyRank() error: the input RMpipe is NULL") == RM_WHACKED)
1900 	return(RM_WHACKED);
1901 
1902     return toQuery->myRank;
1903 }
1904 
1905 #if 0
1906 /*
1907  * ----------------------------------------------------
1908  * @Name rmPipeGetDisplayName
1909  @pstart
1910  const char * rmPipeGetDisplayName (const RMpipe *toQuery)
1911  @pend
1912 
1913  @astart
1914  const RMpipe *toQuery - a handle to an RMpipe object (input).
1915  @aend
1916 
1917  @dstart
1918 
1919  Returns to the caller a character string defining $DISPLAY, the display
1920  name. $DISPLAY has an effect only on GL_PIPE_GLX platforms.
1921 
1922  @dend
1923  * ----------------------------------------------------
1924  */
1925 const char *
1926 rmPipeGetDisplayName(const RMpipe *toQuery)
1927 {
1928     if (RM_ASSERT(toQuery,"rmPipeGetDisplayName() error: the input RMpipe is NULL") == RM_WHACKED)
1929 	return NULL;
1930 
1931     return toQuery->displayName;
1932 }
1933 
1934 /*
1935  * ----------------------------------------------------
1936  * @Name rmPipeSetDisplayName
1937  @pstart
1938  RMenum rmPipeSetDisplayName (RMpipe *toModify, const char *displayName)
1939  @pend
1940 
1941  @astart
1942  RMpipe *toModify - a handle to an RMpipe object (modified).
1943  const char *displayName - character string defining name of the $DISPLAY
1944    to use in subsequent window system operations.
1945  @aend
1946 
1947  @dstart
1948 
1949  Use this routine to set the $DISPLAY variable in an RMpipe. This
1950  variable is used only on RM_PIPE_GLX platforms, and only when a
1951  Returns to the caller a character string defining $DISPLAY, the display
1952  name. $DISPLAY has an effect only on GL_PIPE_GLX platforms.
1953 
1954  @dend
1955  * ----------------------------------------------------
1956  */
1957 RMenum
1958 rmPipeSetDisplayName(RMpipe *toModify,
1959 		     const char *displayName)
1960 {
1961     if (RM_ASSERT(toModify,"rmPipeSetDisplayName() error: the input RMpipe is NULL") == RM_WHACKED)
1962 	return RM_WHACKED;
1963 
1964     if (toQuery->displayName != NULL)
1965     {
1966 	free((void *)(toQuery->displayName));
1967 	toQuery->displayName = NULL;
1968     }
1969 
1970     if ((displayName != NULL) && (displayName[0] != '\0'))
1971 	toQuery->displayName = strdup(displayName);
1972 
1973     return RM_CHILL;
1974 }
1975 
1976 /*
1977  * ----------------------------------------------------
1978  * @Name rmPipeGetDisplay
1979  @pstart
1980  void * rmPipeGetDisplay (const RMpipe *toQuery)
1981  @pend
1982 
1983  @astart
1984  const RMpipe *toQuery - a handle to an RMpipe object that will be
1985     queried (input).
1986  @aend
1987 
1988  @dstart
1989 
1990  Returns to the caller the X Display handle, cast to void *, associated
1991  with an RMpipe.
1992 
1993 
1994  @dend
1995  * ----------------------------------------------------
1996  */
1997 const void *
1998 rmPipeGetDisplay (const RMpipe *toQuery)
1999 {
2000 }
2001 
2002 RMenum
2003 rmPipeSetDisplay (RMpipe *toModify,
2004 		  void *XDisplayStruct)
2005 {
2006 }
2007 #endif
2008 
2009 /* PRIVATE */
2010 void
private_rmPipeCopy(RMpipe * source_pipe,RMpipe * dest_pipe)2011 private_rmPipeCopy (RMpipe *source_pipe,
2012                     RMpipe *dest_pipe)
2013 {
2014     memcpy((void *)dest_pipe, (void *)source_pipe, sizeof(RMpipe));
2015 }
2016 
2017 
2018 /* PRIVATE */
2019 int
private_rmComparePipes(RMpipe * p1,RMpipe * p2)2020 private_rmComparePipes (RMpipe *p1,
2021 		        RMpipe *p2)
2022 {
2023     /* returns 1 if pipes are identical, 0 otherwise */
2024     RM_ASSERT(p1, "NULL pipe (1) for comparison.");
2025     RM_ASSERT(p2, "NULL pipe (2) for comparison.");
2026 
2027 #ifdef RM_X /* do we actually need to compare the xcolormaps? */
2028     if ((p1->xdisplay == p2->xdisplay) && (p1->xvisual == p2->xvisual) && (p1->xdrawable == p2->xdrawable) &&
2029 	(p1->glxcontext == p2->glxcontext) && (p1->xcolormap == p2->xcolormap) && (p1->channel_format == p2->channel_format) &&
2030 	(p1->xwindow_width == p2->xwindow_width) && (p1->xwindow_height == p2->xwindow_height))
2031 	return(1);
2032     else
2033 	return(0);
2034 #endif
2035 
2036 #ifdef RM_WIN
2037     if ((p1->hwnd == p2->hwnd))
2038         return(1);
2039     else
2040         return(0);
2041 #endif
2042 }
2043 
2044 /* PRIVATE */
2045 RMenum
private_rmPipeIsOffscreenFormat(const RMpipe * p)2046 private_rmPipeIsOffscreenFormat(const RMpipe *p)
2047 {
2048     RMenum format = rmPipeGetChannelFormat(p);
2049 
2050     if ((format == RM_OFFSCREEN_MONO_CHANNEL) ||
2051 	(format == RM_OFFSCREEN_REDBLUE_STEREO_CHANNEL) ||
2052 	(format == RM_OFFSCREEN_BLUERED_STEREO_CHANNEL))
2053 	return RM_TRUE;
2054     else
2055 	return RM_FALSE;
2056 }
2057 
2058 /* constant frame rate stuff */
2059 /*
2060  * ----------------------------------------------------
2061  * @Name rmPipeSetFrameRate
2062  @pstart
2063  RMenum rmPipeSetFrameRate (RMpipe *toModify, int newFPS)
2064  @pend
2065 
2066  @astart
2067  RMpipe *toModify - a handle to an RMpipe (modified).
2068  int newFPS - an integer value indicating the target frames-per-second
2069      renderering rate when rendering on the RMpipe toModify.
2070  @aend
2071 
2072  @dstart
2073 
2074  This routine is used to specify the desired frame rate when rendering
2075  on the RMpipe toModify. The caller provides an integer value, newFPS,
2076  that indicates the desired number of frames per second. A value of 30
2077  will result in 30 frames per second being rendered, etc. A value of -1
2078  will disable constant-rate rendering: OpenRM will not "watch the clock"
2079  if you specify a value of -1 frames per second as the desired target
2080  rate. The value for newFPS should be a positive integer. Note that not
2081  all values of newFPS make sense on all platforms for reasons related
2082  to how OpenGL is implemented on your machine.
2083 
2084  Constant-rate rendering is really a misnomer : what the contstant-rate
2085  rendering capability in OpenRM really does is to use a high precision
2086  timer and sleep function to ensure that *no more than a given number
2087  of frames per second are rendered*. In this way, you can be assured that
2088  your application will not be rendering more than newFPS per second. If
2089  your application produces a heavy graphics load, the actual rendering
2090  rate may fall well short of newFPS frames per second.  Rather than
2091  calling this capability "constant frame rate" rendering, it is more
2092  accurately called "bounded frame rate" rendering.
2093 
2094  Future work in this area will result in the ability for the application
2095  to query the rendering "load" or "stress" values. This way, you'll be
2096  able to obtain a quantitative value that indicates how far "over budget"
2097  your rendering is, and take action accordingly. One remedial action
2098  will be for the application to use switch nodes and render lower-resolution
2099  models as a way to reduce graphics rendering load.
2100 
2101  From the newFPS parameter, a value of milliseconds-per-frame is computed.
2102  When your application calls rmFrame() for the first time, OpenRM makes
2103  note of the current time. It then proceeds with rendering without delay,
2104  and then returns control to the application after rendering is
2105  complete. The second time your application calls rmFrame(), OpenRM
2106  will delay rendering so that the time taken by rendering during the
2107  previous frame along with the time taken by the application for processing
2108  inbetween frames does not exceed the occur before the milliseconds-per-frame
2109  amount of time has passed. In other words, the period of timing is from
2110  the start of rendering to the start of rendering.
2111 
2112  The bounded-frame-rendering capability works on both Unix/Linux and Win32
2113  platforms subject to caveats that are described in the OpenRM Programming
2114  Guide. Additional caveats not specific to a platform are also discussed
2115  in the OpenRM Progamming Guide.
2116 
2117  Use the routine rmPipeGetFrameRate() to query the frames-per-second
2118  parameter of an RMpipe.
2119 
2120  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
2121 
2122  @dend
2123  * ----------------------------------------------------
2124  */
2125 RMenum
rmPipeSetFrameRate(RMpipe * p,int newFPS)2126 rmPipeSetFrameRate(RMpipe *p,
2127 		   int newFPS)
2128 {
2129     if (RM_ASSERT(p, "rmPipeSetFrameRate() error: the input RMpipe is NULL") == RM_WHACKED)
2130 	return RM_WHACKED;
2131 
2132     /* do a sanity check on the new FPS value: want either -1 or a positive
2133      integer value */
2134     if ((newFPS == 0) || (newFPS < -1))
2135     {
2136 	rmError("rmPipeSetFrameRate() error: the input newFramesPerSecond value must be either a positive integer indicating frame per second, or a value of -1 to disable constant-rate rendering. ");
2137 	return RM_WHACKED;
2138     }
2139 
2140     p->targetFrameRate = newFPS;
2141     rmTimeSet(&(p->timePerFrame), 0, 0);
2142     rmTimeCurrent(&(p->lastTimeStart));
2143 
2144     /* compute and actual RMtime version of newFPS. */
2145     if (newFPS > 0)
2146     {
2147 	double msPerFrame = 1000.0/(double)newFPS;
2148 	long usPerFrame = (long)(msPerFrame * 1000.0);
2149 	rmTimeSet(&(p->timePerFrame), 0, usPerFrame);
2150 	p->timePerFrameMS = msPerFrame;
2151 
2152 	private_rmPipeSetTimeSyncFunc(p, private_rmPipeTimeSyncFunc);
2153     }
2154     else
2155 	private_rmPipeSetTimeSyncFunc(p, NULL);
2156 
2157     return RM_CHILL;
2158 }
2159 
2160 /*
2161  * ----------------------------------------------------
2162  * @Name rmPipeGetFrameRate
2163  @pstart
2164  int rmPipeGetFrameRate (constRMpipe *toQuery)
2165  @pend
2166 
2167  @astart
2168  RMpipe *toQuery - a handle to an RMpipe (queried).
2169  @aend
2170 
2171  @dstart
2172 
2173  Use this routine to obtain the RMpipe's notion of how many frames per
2174  second it is supposed to render. For a more meaningful discussion of
2175  what the frames-per-second RMpipe attribute means, refer to the
2176  discussion for rmPipeSetFrameRate() as well as the OpenRM Programming
2177  Guide.
2178 
2179  Returns either -1 or a positive integer on success, or zero on failure.
2180 
2181  @dend
2182  * ----------------------------------------------------
2183  */
2184 int
rmPipeGetFrameRate(const RMpipe * p)2185 rmPipeGetFrameRate(const RMpipe *p)
2186 {
2187     if (RM_ASSERT(p, "rmPipeGetFrameRate() error: the input RMpipe is NULL") == RM_WHACKED)
2188 	return 0;
2189 
2190     return p->targetFrameRate;
2191 }
2192 
2193 void
private_rmPipeFPSStart(RMpipe * p)2194 private_rmPipeFPSStart(RMpipe *p)
2195 {
2196 #if 0
2197     RMtime now, wait, drift;
2198     double ms, diffMS;
2199 
2200     rmTimeCurrent(&now);
2201     ms = rmTimeDifferenceMS(&(p->lastTimeStart), &now);
2202 
2203     /*
2204      * quick test to see if whether or not we need to wait at all.
2205      */
2206     if (ms > p->timePerFrameMS)
2207     {
2208 /*	fprintf(stderr," SKIP!! est ms per frame = %g, current delta = %g\n", p->timePerFrameMS, ms); */
2209 	rmTimeCurrent(&(p->lastTimeStart));
2210 	return;
2211     }
2212 
2213     /*
2214      * compute amount of time we need to wait
2215      */
2216     diffMS = p->timePerFrameMS - ms;
2217 
2218     rmTimeEncodeMS(&wait, diffMS);
2219 
2220     /*
2221      * do the wait
2222      */
2223     rmTimeSleep(&wait);
2224     /* rmTimeSleepDrift(&wait, &drift); to accumulate/mediate error */
2225 
2226     /*
2227      * what time is it now?
2228      */
2229     rmTimeCurrent(&(p->lastTimeStart));
2230 
2231 /*    rmTimeDifference(&(p->lastTimeStart),&drift,(&p->lastTimeStart)); */
2232 #endif
2233     p = NULL; 			/* foil compiler warnings */
2234 }
2235 
2236 void
private_rmPipeFPSEnd(RMpipe * p)2237 private_rmPipeFPSEnd(RMpipe *p)
2238 {
2239     RMtime now;
2240     /*
2241      * compute the amount of time required for rendering
2242      */
2243     rmTimeCurrent(&now);
2244     rmTimeDifference(&(p->lastTimeStart), &now, &(p->lastRenderTime));
2245 }
2246 
2247 void
private_rmPipeSetTimeSyncFunc(RMpipe * t,void (* newFunc)(RMpipe *))2248 private_rmPipeSetTimeSyncFunc(RMpipe *t,
2249 			      void (*newFunc)(RMpipe *))
2250 {
2251     t->timeSyncFunc = newFunc;
2252 }
2253 
2254 void
private_rmPipeTimeSyncFunc(RMpipe * p)2255 private_rmPipeTimeSyncFunc(RMpipe *p)
2256 {
2257     RMtime now, wait, drift;
2258     double ms, diffMS;
2259 
2260     extern RMenum rmTimeSleepDrift(const RMtime *tSleep, RMtime *drift);
2261 
2262     rmTimeCurrent(&now);
2263     ms = rmTimeDifferenceMS(&(p->lastTimeStart), &now);
2264 
2265     /*
2266      * quick test to see if whether or not we need to wait at all.
2267      */
2268 #define FUDGE 0.0  /* ms fudge factor */
2269 
2270     if ((ms-FUDGE) > p->timePerFrameMS)
2271     {
2272 /*	fprintf(stderr," SKIP!! est ms per frame = %g, current delta = %g\n", p->timePerFrameMS, ms); */
2273 	rmTimeCurrent(&(p->lastTimeStart));
2274 	return;
2275     }
2276 
2277     /*
2278      * compute amount of time we need to wait
2279      */
2280     diffMS = p->timePerFrameMS - ms;
2281 
2282     rmTimeEncodeMS(&wait, diffMS);
2283 
2284     /*
2285      * do the wait
2286      */
2287 #define USE_DRIFT 1
2288 #if USE_DRIFT
2289     rmTimeSleepDrift(&wait, &drift);
2290 #else
2291     rmTimeSleep(&wait);
2292 #endif
2293 
2294     /*
2295      * what time is it now?
2296      */
2297     rmTimeCurrent(&(p->lastTimeStart));
2298 
2299 #if DEBUG_RSYNC
2300     {
2301 	int indx = timeSyncIndx % MAX_RSYNC_SAMPLES;
2302 	timeSyncData[indx].t = p->lastTimeStart; /* current time */
2303 	timeSyncData[indx].frameNumber = rmPipeGetFrameNumber(p);
2304 	timeSyncIndx++;
2305     }
2306 #endif
2307 
2308 #if USE_DRIFT
2309     /*
2310      * but, the timer should've gone off at now-drift, rather than now.
2311      * so, adjust "now" backwards by "drift" so that the next
2312      * frame happens at the right time.
2313      */
2314 
2315     {
2316 	long nowSecs, nowUSecs, dUSecs;
2317 
2318 	rmTimeGet(&(p->lastTimeStart), &nowSecs, &nowUSecs);
2319 
2320 	/* the seconds portion of the drift is most likely zero,
2321 	   so we'll ignore it */
2322 #define FUDGE_US 0
2323 	rmTimeGet(&drift, NULL, &dUSecs);
2324 	if (nowUSecs < (dUSecs+FUDGE_US))
2325 	{
2326 	    nowUSecs -= (dUSecs + 1000000 + FUDGE_US);
2327 	    nowSecs -= 1;
2328 	}
2329 	else
2330 	    nowUSecs -= (dUSecs+FUDGE_US);
2331 
2332 	rmTimeSet(&(p->lastTimeStart), nowSecs, nowUSecs);
2333     }
2334 #endif
2335 
2336 }
2337 
2338 
2339 /*
2340  * ----------------------------------------------------
2341  * @Name rmPipeGetFrameNumber
2342  @pstart
2343  int rmPipeGetFrameNumber (const RMpipe *toQuery)
2344  @pend
2345 
2346  @astart
2347  const RMpipe *toQuery - (input) a handle to an RMpipe.
2348  @aend
2349 
2350  @dstart
2351 
2352  Use this routine to obtain the RMpipe's notion of the current frame
2353  number. Upon success, a non-negative integer is returned. Upon failure,
2354  a value of -1 is returned.
2355 
2356  The RMpipe's frame number is initialized to zero when the RMpipe is
2357  created with rmPipeNew(). Upon each call to rmFrame(), the the
2358  frame number is incremented by one. There is no mechanism for applications
2359  to set the frame number, or for applications to reset the frame number
2360  to zero.
2361 
2362  @dend
2363  * ----------------------------------------------------
2364  */
2365 int
rmPipeGetFrameNumber(const RMpipe * toQuery)2366 rmPipeGetFrameNumber(const RMpipe *toQuery)
2367 {
2368     return toQuery->frameNumber;
2369 }
2370 
2371 static RMenum
private_rmCheckForActiveContext(void)2372 private_rmCheckForActiveContext(void)
2373 {
2374     /*
2375      * checks to see if there's an active OpenGL context. Return 1 if
2376      * all is well, otherwise, return a zero.
2377      */
2378 #ifdef RM_X
2379     if (glXGetCurrentContext() == NULL)
2380 	return RM_FALSE;
2381     else
2382 	return RM_TRUE;
2383 #elif RM_WIN
2384     if (wglGetCurrentContext() == NULL)
2385 	return RM_FALSE;
2386     else
2387 	return RM_TRUE;
2388 #else /* assume RM_CR */
2389     return RM_TRUE;
2390 #endif
2391 
2392 }
2393 
2394 /* PRIVATE */
2395 int
private_rmBuildExtensionTable(const char * s,char *** dst)2396 private_rmBuildExtensionTable(const char *s,
2397 			      char ***dst)
2398 {
2399     int n = 0;
2400     int i;
2401     char **d;
2402 
2403     d = (char **)malloc(sizeof(char *)*1024); /* max of 1024 extensions */
2404 
2405     for (i=0; i< (int)(strlen(s)); )
2406     {
2407 	int istart, iend;
2408 
2409 	/* scan to the first non-blank character */
2410 	while (s[i] == ' ')
2411 	    i++;
2412 
2413 	istart = i; 		/* beginning of string */
2414 
2415 	/* scan to the next character that isn't a blank or a NULL */
2416 	while ((s[i] != ' ') && (s[i] != '\0') && (s[i] != '\n'))
2417 	    i++;
2418 
2419 	iend = i-1;
2420 
2421 	d[n] = (char *)calloc(iend-istart+2, sizeof(char)); /* leave room for an extra NUL */
2422 	memcpy((void *)d[n], (void *)(s+istart), iend-istart+1);
2423 	n++;
2424 	i++;
2425     }
2426 
2427     *dst = d;
2428     return n;
2429 }
2430 
2431 /* PRIVATE */
2432 int
private_rmHaveExtension(char ** t,int n,const char * s)2433 private_rmHaveExtension(char **t,
2434 			int n,
2435 			const char *s)
2436 {
2437     int i;
2438 
2439     for (i=0; i<n; i++)
2440     {
2441 	if (strcmp(t[i], s) == 0)
2442 	    return 1;
2443     }
2444     return 0;
2445 }
2446 
2447 /* PRIVATE */
2448 static void
private_rmPipeGetCapabilities(RMpipeOGLCapabilities * c)2449 private_rmPipeGetCapabilities(RMpipeOGLCapabilities *c)
2450 {
2451     const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
2452     int nExtensions;
2453     char **extensionTable;
2454 
2455     nExtensions = private_rmBuildExtensionTable(extensions, &extensionTable);
2456 
2457     /* check for multitexturing capabilities */
2458     if (private_rmHaveExtension(extensionTable, nExtensions, "GL_ARB_multitexture") == 1)
2459     {
2460 	glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &(c->numTextureUnits));
2461 
2462 #if (DEBUG_LEVEL & DEBUG_TRACE)
2463 	printf(" Multitexturing is supported on this renderer. There are %d texture units available. \n", c->numTextureUnits);
2464 #endif
2465 
2466 	c->haveMultiTexturing = RM_TRUE;
2467 
2468 	c->activeTextureARB = private_rmGLGetProcAddr("glActiveTextureARB");
2469 	c->multiTexCoord1fvARB = private_rmGLGetProcAddr("glMultiTexCoord1fvARB");
2470 	c->multiTexCoord2fvARB = private_rmGLGetProcAddr("glMultiTexCoord2fvARB");
2471 	c->multiTexCoord3fvARB = private_rmGLGetProcAddr("glMultiTexCoord3fvARB");
2472     }
2473     else
2474     {
2475 #if (DEBUG_LEVEL & DEBUG_TRACE)
2476 	printf("Sorry, GL_ARB_multitexture not supported by this renderer.\n");
2477 #endif
2478 	c->haveMultiTexturing = RM_FALSE;
2479 	c->numTextureUnits = 0;
2480 
2481 	c->activeTextureARB = NULL;
2482 	c->multiTexCoord1fvARB = NULL;
2483 	c->multiTexCoord2fvARB = NULL;
2484 	c->multiTexCoord3fvARB = NULL;
2485     }
2486 
2487     /* check for 3D texturing */
2488     if (private_rmHaveExtension(extensionTable, nExtensions, "GL_EXT_texture3D") == 1)
2489     {
2490 	c->have3DTextures = RM_TRUE;
2491 	c->rm_glTexImage3D = private_rmGLGetProcAddr("glTexImage3DEXT");
2492 	c->rm_glTexSubImage3D = private_rmGLGetProcAddr("glTexSubImage3DEXT");
2493     }
2494     else
2495     {
2496 	c->have3DTextures = RM_FALSE;
2497 	c->rm_glTexImage3D = NULL;
2498 	c->rm_glTexSubImage3D = NULL;
2499     }
2500 
2501     /* clean up */
2502     {
2503 	int i;
2504 	for (i=0; i<nExtensions; i++)
2505 	    free((void *)extensionTable[i]);
2506 	free((void *)extensionTable);
2507     }
2508 }
2509 
2510 /*
2511  * ----------------------------------------------------
2512  * @Name rmPipeGetNumMultitextureUnits
2513  @pstart
2514  int rmPipeGetNumMultitextureUnits (const RMpipe *toQuery)
2515  @pend
2516 
2517  @astart
2518  const RMpipe *toQuery - (input) a handle to an RMpipe.
2519  @aend
2520 
2521  @dstart
2522 
2523  Use this routine to obtain the number of OpenGL multitexturing
2524  units available from the underlying OpenGL implementation. This
2525  routine returns the following values:
2526 
2527  -1 is used to indicate an error of some type, like if the input
2528  RMpipe is NULL.
2529 
2530  0 (zero) is returned if the underlying OpenGL platform does not support
2531  multitexturing.
2532 
2533  >0 (positive integer) is returned to indicate the number of usable
2534  OpenGL multitexture units. Note that the number of texture units is
2535  implementation dependent, but should be at least two when multitexturing
2536  is present.
2537 
2538  This routine should be called only after the input RMpipe has been
2539  subjected to successful call to rmPipeMakeCurrent.
2540 
2541  @dend
2542  * ----------------------------------------------------
2543  */
2544 int
rmPipeGetNumMultitextureUnits(const RMpipe * toQuery)2545 rmPipeGetNumMultitextureUnits(const RMpipe *toQuery)
2546 {
2547     if (RM_ASSERT(toQuery, "rmPipeGetNumMultitextureUnits error - the input RMpipe is NULL") == RM_WHACKED)
2548 	return -1;
2549 
2550     if (RM_ASSERT(toQuery->caps, "rmPipeGetNumMultitextureUnits internal error - the capabilities field is NULL. Please call rmPipeMakeCurrent before calling this routine. ") == RM_WHACKED)
2551 	return -1;
2552 
2553     if (toQuery->caps->haveMultiTexturing == RM_FALSE)
2554 	return 0;
2555 
2556     return toQuery->caps->numTextureUnits;
2557 }
2558 
2559 /*
2560  * ----------------------------------------------------
2561  * @Name rmPipeSetSceneBackgroundColor
2562  @pstart
2563  RMenum rmPipeSetSceneBackgroundColor (RMpipe *toModify,
2564 			               const RMcolor4D *newColor)
2565  @pend
2566 
2567  @astart
2568  RMnode *toModify - a handle to an RMpipe (input).
2569 
2570  const RMcolor4D *newColor - a handle to the desired background color
2571    (input).
2572  @aend
2573 
2574  @dstart
2575 
2576  In RM/OpenRM, you may set a "background color" scene parameter at the
2577  RMnode level, at the RMpipe level, or both. The background color may
2578  consist of a single color or a color background image. In addition,
2579  you may also set a depth value or a depth image that will be used to
2580  initialize the z-buffer. The main issue with assigning a background
2581  color/depth parameter at the RMnode vs. the RMpipe level is convenience
2582  vs. fine-grained control. If you assign the background color/depth
2583  value at the RMpipe level, the background will be cleared once
2584  each time your application calls rmFrame() to render a scene. In some cases,
2585  such as when multiple viewports are rendered within a single window
2586  with a single call to rmFrame(), then you must assign the background
2587  color/depth value at the RMnode level. Unlike when assigning such
2588  values at the RMpipe level, using them at the RMnode level requires
2589  special care due to the multiple rendering passes RM makes for a single
2590  call to rmFrame(). The RMnode containing the background color/depth
2591  values must have its traversal mask set such that it is invoked at most
2592  once per call to rmFrame().
2593 
2594  Use rmPipeSetSceneBackgroundColor to set the background color scene
2595  parameter at the RMpipe level. Calling this routine with a color
2596  argument of NULL disables the background color scene parameter.  During
2597  rendering, the color planes of the framebuffer are cleared to this
2598  background color (with a depth value of 1.0, see NOTE below).
2599 
2600  Upon success, RM_CHILL is returned and the specified background color
2601  scene parameter is set.  Otherwise, RM_WHACKED is returned, and the
2602  background color scene parameter remains unmodified.
2603 
2604  Passing in a value of NULL for the RMcolor4D object will effectively
2605  remove any existing background image color parameter from the RMpipe toModify.
2606 
2607  NOTE: internal to this routine, a call to rmPipeSetSceneDepthValue is
2608  performed, effectively coupling framebuffer and depthbuffer clears.
2609 
2610  Because this routine makes a copy of the input scene parameter (an
2611  RMcolor4D object), callers do not need to manage the input object after a
2612  successful return from this routine. This has important ramificiations:
2613 
2614  1. Since a copy is made, any changes made to the caller's object will have
2615  no effect upon the scene graph, unless this routine is called again to
2616  update the scene parameter inside the scene graph;
2617 
2618  2. Callers may safely delete their copy of the input object after a
2619  successful return from this routine.
2620 
2621  Related routines: rmPipeGetSceneBackgroundColor, rmPipeSetSceneBackgroundImage, rmPipeSetSceneDepthValue.
2622 
2623  @dend
2624  * ----------------------------------------------------
2625  */
2626 RMenum
rmPipeSetSceneBackgroundColor(RMpipe * r,const RMcolor4D * new_color)2627 rmPipeSetSceneBackgroundColor (RMpipe *r,
2628 			       const RMcolor4D *new_color)
2629 {
2630     if (RM_ASSERT(r, "rmPipeSetSceneBackgroundColor() error: the input RMpipe pointer is NULL.") == RM_WHACKED)
2631 	return(RM_WHACKED);
2632 
2633     if (r->fbClearNode == NULL)
2634 	r->fbClearNode = rmNodeNew("RMpipe fbClear node", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
2635 
2636     if (r->fbClearNode->fbClear == NULL)
2637 	r->fbClearNode->fbClear = private_rmFBClearNew();
2638 
2639     if (r->fbClearNode->fbClear->bgColor != NULL)
2640 	rmColor4DDelete(r->fbClearNode->fbClear->bgColor);
2641 
2642     if (new_color != NULL)
2643     {
2644 	float junk;
2645 
2646 	r->fbClearNode->fbClear->bgColor = rmColor4DNew(1);
2647 	*(r->fbClearNode->fbClear->bgColor) = *new_color;
2648 
2649 	if (rmPipeGetSceneDepthValue(r, &junk) == RM_WHACKED)
2650 	{
2651 	    extern float RM_DEFAULT_DEPTH_VALUE;
2652 
2653 	    junk = RM_DEFAULT_DEPTH_VALUE;
2654 	    rmPipeSetSceneDepthValue(r, &junk);
2655 	}
2656     }
2657     else
2658 	r->fbClearNode->fbClear->bgColor = NULL;
2659 
2660     return(RM_CHILL);
2661 }
2662 
2663 
2664 /*
2665  * ----------------------------------------------------
2666  * @Name rmPipeGetSceneBackgroundColor
2667  @pstart
2668  RMenum rmPipeGetSceneBackgroundColor (const RMpipe *toQuery,
2669 			               RMcolor4D *returnColor)
2670  @pend
2671 
2672  @astart
2673  const RMnode *toQuery - a handle to an RMpipe (input).
2674 
2675  RMcolor4D *returnColor - a handle to a caller-supplied RMcolor4D
2676     object (return).
2677  @aend
2678 
2679  @dstart
2680 
2681  Use this routine to obtain the background color scene parameter of an
2682  RMpipe, if such a scene parameter exists.
2683 
2684  Upon success, RM_CHILL is returned and the scene background color is
2685  copied into the caller-supplied RMcolor4D (effectively returning a copy
2686  of the background color scene parameter to the caller). If no such scene
2687  parameter exists, or if there is some error condition detected, RM_WHACKED
2688  is returned, and the caller-supplied colorReturn object remains unmodified.
2689 
2690  @dend
2691  * ----------------------------------------------------
2692  */
2693 RMenum
rmPipeGetSceneBackgroundColor(const RMpipe * r,RMcolor4D * color_return)2694 rmPipeGetSceneBackgroundColor (const RMpipe *r,
2695 			       RMcolor4D *color_return)
2696 {
2697     if ((RM_ASSERT(r, "rmPipeGetSceneBackgroundColor() error: the input RMpipe pointer is NULL.") == RM_WHACKED) ||
2698 	(RM_ASSERT(color_return, "rmPipeGetSceneBackgroundColor() error: the return RMcolor4D pointer is NULL.") == RM_WHACKED))
2699 	return(RM_WHACKED);
2700 
2701     if ((r->fbClearNode == NULL) || (r->fbClearNode->fbClear == NULL) ||
2702 	(r->fbClearNode->fbClear->bgColor == NULL))
2703 	return(RM_WHACKED);
2704 
2705     /* we are returning the contents of the scene parameter, an RMcolor4D
2706      object, to the caller, not the handle to the RMcolor4D object stored
2707      in the scene graph itself. */
2708 
2709     *color_return = *(r->fbClearNode->fbClear->bgColor);
2710 
2711     return(RM_CHILL);
2712 }
2713 
2714 
2715 /*
2716  * ----------------------------------------------------
2717  * @Name rmPipeSetSceneBackgroundImage
2718  @pstart
2719  RMenum rmPipeSetSceneBackgroundImage (RMpipe *toModify,
2720 			               const RMimage *newImageTile)
2721  @pend
2722 
2723  @astart
2724  RMpipe *toModify - a handle to an RMpipe (modified).
2725 
2726  const RMimage *newImageTile - a handle to an RMimage (input).
2727  @aend
2728 
2729  @dstart
2730 
2731  In RM/OpenRM, you may set a "background color" scene parameter at the
2732  RMnode level, at the RMpipe level, or both. The background color may
2733  consist of a single color or a color background image. In addition,
2734  you may also set a depth value or a depth image that will be used to
2735  initialize the z-buffer. The main issue with assigning a background
2736  color/depth parameter at the RMnode vs. the RMpipe level is convenience
2737  vs. fine-grained control. If you assign the background color/depth
2738  value at the RMpipe level, the background will be cleared once
2739  each time your application calls rmFrame() to render a scene. In some cases,
2740  such as when multiple viewports are rendered within a single window
2741  with a single call to rmFrame(), then you must assign the background
2742  color/depth value at the RMnode level. Unlike when assigning such
2743  values at the RMpipe level, using them at the RMnode level requires
2744  special care due to the multiple rendering passes RM makes for a single
2745  call to rmFrame(). The RMnode containing the background color/depth
2746  values must have its traversal mask set such that it is invoked at most
2747  once per call to rmFrame().
2748 
2749  rmPipeSetSceneBackgroundImage sets the background image scene parameter
2750  for the RMpipe.  When rendered, this image is tiled into the viewport at
2751  the scene depth value (or a default of 1.0) with an orthogonal projection,
2752  creating a background image. If the image does not fit the display, it will
2753  be tiled from top to bottom and left to right, so ragged edges fall on
2754  the bottom and right edges of the viewport.
2755 
2756  Passing in a value of NULL for the newImageTile parameter will
2757  effectively remove the background image tile scene parameter, if it
2758  exists.
2759 
2760  Upon success, RM_CHILL is returned and the background image scene
2761  parameter has been modified.  Otherwise, RM_WHACKED is returned.
2762 
2763  Because this routine makes a copy of the input scene parameter (an
2764  RMimage object), callers do not need to manage the input object after a
2765  successful return from this routine. This has important ramificiations:
2766 
2767  1. Since a copy is made, any changes made to the caller's object will have
2768  no effect upon the scene graph, unless this routine is called again to
2769  update the scene parameter inside the scene graph;
2770 
2771  2. Callers may safely delete their copy of the input object after a
2772  successful return from this routine.
2773 
2774  NOTE: internal to this routine, a call to rmPipSetSceneDepthValue() is
2775  performed, effectively coupling framebuffer clears (by image tiling) with
2776  depth buffer clears.
2777 
2778  @dend
2779  * ----------------------------------------------------
2780  */
2781 RMenum
rmPipeSetSceneBackgroundImage(RMpipe * p,const RMimage * tile)2782 rmPipeSetSceneBackgroundImage (RMpipe *p,
2783 			       const RMimage *tile)
2784 {
2785     if (RM_ASSERT(p, "rmPipeSetSceneBackgroundImage() error: input RMpipe is NULL. \n") == RM_WHACKED)
2786 	return(RM_WHACKED);
2787 
2788     if (p->fbClearNode == NULL)
2789 	p->fbClearNode = rmNodeNew("RMpipe fbClear node", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
2790 
2791     if (p->fbClearNode->fbClear == NULL)
2792 	p->fbClearNode->fbClear = private_rmFBClearNew();
2793 
2794     /* if there's an existing background image tile parameter, remove it. */
2795     if (p->fbClearNode->fbClear->bgImageTile != NULL)
2796 	rmImageDelete(p->fbClearNode->fbClear->bgImageTile);
2797 
2798     /* if the input isn't null, make a copy and assign it as a scene
2799      parameter. */
2800     if (tile != NULL)
2801     {
2802 	float junk;
2803 
2804 	p->fbClearNode->fbClear->bgImageTile = rmImageDup(tile);
2805 
2806 	/* if there's no background depth value, create one. this
2807 	 policy may change in the future. */
2808 	if (rmPipeGetSceneDepthValue(p, &junk) == RM_WHACKED)
2809 	{
2810 	    extern float RM_DEFAULT_DEPTH_VALUE;
2811 
2812 	    junk = RM_DEFAULT_DEPTH_VALUE;
2813 	    rmPipeSetSceneDepthValue(p, &junk);
2814 	}
2815     }
2816     else
2817 	p->fbClearNode->fbClear->bgImageTile = NULL;
2818 
2819     return(RM_CHILL);
2820 }
2821 
2822 
2823 /*
2824  * ----------------------------------------------------
2825  * @Name rmPipeGetSceneBackgroundImage
2826  @pstart
2827  RMenum rmPipeGetSceneBackgroundImage (const RMpipe *toQuery,
2828 			               RMimage **returnImageTile)
2829  @pend
2830 
2831  @astart
2832  const RMpipe *toQuery - a handle to an RMpipe (input).
2833 
2834  RMimage **returnImageTile - a handle to an RMimage handle (return).
2835  @aend
2836 
2837  @dstart
2838 
2839  Use this routine to obtain the background image scene parameter of an
2840  RMpipe.  Note that a handle to the RMimage is returned, not a
2841  copy of the actual pixel data.
2842 
2843  Upon success, RM_CHILL is returned and a handle to the scene
2844  background image is copied into the caller-supplied RMimage handle.
2845  Otherwise, RM_WHACKED is returned.
2846 
2847  Unlike most other rmPipeGetScene*() routines, this routine returns a
2848  handle to the actual object contained within the RMpipe, rather
2849  than returning a copy. Applications should exercise appropriate
2850  discretion when using this object.
2851 
2852  @dend
2853  * ----------------------------------------------------
2854  */
2855 RMenum
rmPipeGetSceneBackgroundImage(const RMpipe * r,RMimage ** tile_return)2856 rmPipeGetSceneBackgroundImage (const RMpipe *r,
2857 			       RMimage **tile_return)
2858 {
2859     if ((RM_ASSERT(r, "rmPipeGetSceneBackgroundImage() error: input RMpipe is NULL. \n") == RM_WHACKED) ||
2860 	(RM_ASSERT(r, "rmPipeGetSceneBackgroundImage() error: input pointer to RMimage pointer is NULL. ") == RM_WHACKED))
2861 	return(RM_WHACKED);
2862 
2863     /* detect the absence of any scene parms, or the absence of the
2864        background image tile scene parm.  */
2865 
2866     if ((r->fbClearNode == NULL) || (r->fbClearNode->fbClear == NULL) || (r->fbClearNode->fbClear->bgImageTile == NULL))
2867 	return(RM_WHACKED);
2868 
2869     *tile_return = r->fbClearNode->fbClear->bgImageTile;
2870 
2871     return(RM_CHILL);
2872 }
2873 
2874 /*
2875  * ----------------------------------------------------
2876  * @Name rmPipeSetSceneDepthImage
2877  @pstart
2878  RMenum rmPipeSetSceneDepthImage (RMpipe *toModify,
2879 			          const RMimage *newDepthImage)
2880  @pend
2881 
2882  @astart
2883  RMpipe *toModify - a handle to an RMpipe (modified).
2884 
2885  const RMimage *newDepthImage - a handle to a depth image (input)
2886  @aend
2887 
2888  @dstart
2889 
2890  In RM/OpenRM, you may set a "background color" scene parameter at the
2891  RMnode level, at the RMpipe level, or both. The background color may
2892  consist of a single color or a color background image. In addition,
2893  you may also set a depth value or a depth image that will be used to
2894  initialize the z-buffer. The main issue with assigning a background
2895  color/depth parameter at the RMnode vs. the RMpipe level is convenience
2896  vs. fine-grained control. If you assign the background color/depth
2897  value at the RMpipe level, the background will be cleared once
2898  each time your application calls rmFrame() to render a scene. In some cases,
2899  such as when multiple viewports are rendered within a single window
2900  with a single call to rmFrame(), then you must assign the background
2901  color/depth value at the RMnode level. Unlike when assigning such
2902  values at the RMpipe level, using them at the RMnode level requires
2903  special care due to the multiple rendering passes RM makes for a single
2904  call to rmFrame(). The RMnode containing the background color/depth
2905  values must have its traversal mask set such that it is invoked at most
2906  once per call to rmFrame().
2907 
2908  rmPipeSetSceneDepthImage assigns a depth image as a scene parameter for
2909  the input RMpipe toModify. The  depth image is similar to the background
2910  image tile, but is applied to the depth buffer, rather than the color planes
2911  of the framebuffer. Like the background image tile, the depth image scene
2912  parameter is tiled to fill the framebuffer, starting from the upper
2913  left-hand corner of the viewport. If the size of the depth buffer image
2914  and viewport do not match exactly, the "ragged edges" or on the right
2915  and the bottom of the viewport.
2916 
2917  Passing in a value of NULL for the RMimage object will have the effect
2918  of removing the background depth image scene parameter, if one exists,
2919  from the RMnode.
2920 
2921  Upon success, a copy of the caller's RMimage object is made, and the
2922  copy is assigned as a scene parameter (or, if the input RMimage object is
2923  NULL, the NULL is assigned as a depth image scene parameter, effectively
2924  turning off that scene parameter), and RM_CHILL is returned;
2925  otherwise, RM_WHACKED is returned.
2926 
2927  Because this routine makes a copy of the input scene parameter (an
2928  RMimage), callers do not need to manage the input object after a
2929  successful return from this routine. This has important ramificiations:
2930 
2931  1. Since a copy is made, any changes made to the caller's object will have
2932  no effect upon the scene graph, unless this routine is called again to
2933  update the scene parameter inside the scene graph;
2934 
2935  2. Callers may safely delete their copy of the input object after a
2936  successful return from this routine.
2937 
2938  Note: as a practical matter, it is suggested that the pixel format
2939  of input RMimage objects should be of type RM_FLOAT, and in the
2940  range 0..1. By default, depth buffer Pixels in OpenGL range from
2941  0..1 (or perhaps 0..0.9999, depending upon your interpretation), but
2942  this range may be manipulated with glPixelTransferf(). As of the time
2943  of this writing (May 2000), we have tested background depth images
2944  only with RMimage's consisting of RM_FLOAT pixels in the range 0..1
2945  (and they work - refer to the demonstration program "pdb" included with
2946  the openrm-demo distribution).
2947 
2948  @dend
2949  * ----------------------------------------------------
2950  */
2951 RMenum
rmPipeSetSceneDepthImage(RMpipe * p,const RMimage * new_depth_image)2952 rmPipeSetSceneDepthImage (RMpipe *p,
2953 			  const RMimage *new_depth_image)
2954 {
2955     if (RM_ASSERT(p, "rmPipeSetSceneDepthImage() error: the input RMpipe pointer is NULL.") == RM_WHACKED)
2956 	return(RM_WHACKED);
2957 
2958     if (p->fbClearNode == NULL)
2959 	p->fbClearNode = rmNodeNew("RMpipe fbClear node", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
2960 
2961     if (p->fbClearNode->fbClear == NULL)
2962 	p->fbClearNode->fbClear = private_rmFBClearNew();
2963 
2964     if (p->fbClearNode->fbClear->depthImage != NULL)
2965     {
2966 	rmImageDelete(p->fbClearNode->fbClear->depthImage);
2967 	p->fbClearNode->fbClear->depthImage = NULL;
2968     }
2969 
2970     if (new_depth_image != NULL)
2971 	p->fbClearNode->fbClear->depthImage = rmImageDup(new_depth_image);
2972 
2973     return(RM_CHILL);
2974 }
2975 
2976 
2977 /*
2978  * ----------------------------------------------------
2979  * @Name rmPipeGetSceneDepthImage
2980  @pstart
2981  RMenum rmPipeGetSceneDepthImage (const RMpipe *toQuery,
2982 			          RMimage **returnDepthImage)
2983  @pend
2984 
2985  @astart
2986  const RMpipe *toQuery - a handle to an RMnode (input).
2987 
2988  RMimage **returnDepthImage - a handle to a depth image handle
2989     (return).
2990  @aend
2991 
2992  @dstart
2993 
2994  Use this routine to obtain the RMpipe's depth image scene parameter. If
2995  such a scene parameter exists, the handle of the RMimage (depth image)
2996  scene parameter is copied into caller-supplied memory, and RM_CHILL is
2997  returned. Otherwise, in the event of an error or the absence of the
2998  depth image scene parameter, RM_WHACKED is returned and caller supplied
2999  memory remains unmodified.
3000 
3001  Unlike most other rmPipeGetScene*() routines, this routine returns a
3002  handle to the actual RMimage object contained within the scene graph, rather
3003  than returning a copy. Applications should exercise appropriate
3004  discretion when using this object.
3005 
3006  @dend
3007  * ----------------------------------------------------
3008  */
3009 RMenum
rmPipeGetSceneDepthImage(const RMpipe * p,RMimage ** depth_image_return)3010 rmPipeGetSceneDepthImage (const RMpipe *p,
3011 			  RMimage **depth_image_return)
3012 {
3013     if ((RM_ASSERT(p, "rmPipeGetSceneDepthImage() error: input RMpipe is NULL. \n") == RM_WHACKED) ||
3014 	(RM_ASSERT(depth_image_return, "rmPipeGetSceneDepthImage() error: input pointer to RMimage pointer is NULL. ") == RM_WHACKED))
3015 	return(RM_WHACKED);
3016 
3017     if ((p->fbClearNode == NULL) || (p->fbClearNode->fbClear == NULL) ||
3018 	(p->fbClearNode->fbClear->depthImage == NULL))
3019 	return(RM_WHACKED);
3020 
3021     *depth_image_return = p->fbClearNode->fbClear->depthImage;
3022 
3023     return(RM_CHILL);
3024 }
3025 
3026 
3027 /*
3028  * ----------------------------------------------------
3029  * @Name rmPipeSetSceneDepthValue
3030  @pstart
3031  RMenum rmPipeSetSceneDepthValue (RMpipe *toModify,
3032 			          const float *newDepthValue)
3033  @pend
3034 
3035  @astart
3036  RMpipe *toModify - a handle to an RMpipe (modified).
3037 
3038  const float *newDepthValue - a handle to the new depth value for the
3039     node (input).
3040  @aend
3041 
3042  @dstart
3043 
3044  In RM/OpenRM, you may set a "background color" scene parameter at the
3045  RMnode level, at the RMpipe level, or both. The background color may
3046  consist of a single color or a color background image. In addition,
3047  you may also set a depth value or a depth image that will be used to
3048  initialize the z-buffer. The main issue with assigning a background
3049  color/depth parameter at the RMnode vs. the RMpipe level is convenience
3050  vs. fine-grained control. If you assign the background color/depth
3051  value at the RMpipe level, the background will be cleared once
3052  each time your application calls rmFrame() to render a scene. In some cases,
3053  such as when multiple viewports are rendered within a single window
3054  with a single call to rmFrame(), then you must assign the background
3055  color/depth value at the RMnode level. Unlike when assigning such
3056  values at the RMpipe level, using them at the RMnode level requires
3057  special care due to the multiple rendering passes RM makes for a single
3058  call to rmFrame(). The RMnode containing the background color/depth
3059  values must have its traversal mask set such that it is invoked at most
3060  once per call to rmFrame().
3061 
3062  Use rmPipeSetSceneDepthValue to set the scene depth value parameter for
3063  an RMpipe. The presence of the scene depth value has the effect of
3064  clearing the depth buffer to the value of newDepthValue.
3065 
3066  Passing in a value of NULL for newDepthValue has the effect of disabling
3067  depth buffer clears.
3068 
3069  The input newDepthValue should have the magnitude specified by
3070  glPixelTransferf(GL_DEPTH_SCALE,X) and range specified by
3071  glPixelTransferf(GL_DEPTH_BIAS,X). In OpenGL, the default depth
3072  bias is 0.0 and range/scale is 1.0.
3073 
3074  Upon success, RM_CHILL is returned and the node's depth value is set.
3075  Otherwise, RM_WHACKED is returned.
3076 
3077  @dend
3078  * ----------------------------------------------------
3079  */
3080 RMenum
rmPipeSetSceneDepthValue(RMpipe * p,const float * newDepthValue)3081 rmPipeSetSceneDepthValue (RMpipe *p,
3082 			  const float *newDepthValue)
3083 {
3084     if (RM_ASSERT(p, "rmPipeSetSceneDepthValue() error: the input RMpipe pointer is NULL") == RM_WHACKED)
3085 	return(RM_WHACKED);
3086 
3087     if (p->fbClearNode == NULL)
3088 	p->fbClearNode = rmNodeNew("RMpipe fbClear node", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
3089 
3090     if (p->fbClearNode->fbClear == NULL)
3091 	p->fbClearNode->fbClear = private_rmFBClearNew();
3092 
3093     if (p->fbClearNode->fbClear->depthValue != NULL)
3094     {
3095 	free((void *)(p->fbClearNode->fbClear->depthValue));
3096 	p->fbClearNode->fbClear->depthValue = NULL;
3097     }
3098     if (newDepthValue != NULL)
3099     {
3100 	p->fbClearNode->fbClear->depthValue = rmFloatNew(1);
3101 	*(p->fbClearNode->fbClear->depthValue) = *newDepthValue;
3102     }
3103 
3104     return(RM_CHILL);
3105 }
3106 
3107 
3108 /*
3109  * ----------------------------------------------------
3110  * @Name rmPipeGetSceneDepthValue
3111  @pstart
3112  RMenum rmPipeGetSceneDepthValue (const RMpipe *toQuery,
3113    			          float *returnDepthValue)
3114  @pend
3115 
3116  @astart
3117  const RMpipe *toQuery - a handle to an RMpipe (input).
3118 
3119  float *returnDepthValue - a handle to a caller-supplied float for the
3120     queried depth value (return).
3121  @aend
3122 
3123  @dstart
3124 
3125  Use this routine to query the scene depth value for a given RMpipe.
3126 
3127  Upon success, RM_CHILL is returned and the node's depth value is
3128  copied into the caller-supplied float.  If the specified pointers are
3129  NULL, or no valid scene depth parameter exists, RM_WHACKED is
3130  returned.
3131 
3132  @dend
3133  * ----------------------------------------------------
3134  */
3135 RMenum
rmPipeGetSceneDepthValue(const RMpipe * p,float * dv)3136 rmPipeGetSceneDepthValue (const RMpipe *p,
3137 			  float *dv)
3138 {
3139     if ((RM_ASSERT(p, "rmPipeGetSceneDepthValue() error: the input RMpipe pointer is NULL") == RM_WHACKED) ||
3140 	(RM_ASSERT(dv, "rmPipeGetSceneDepthValue() error: the return float pointer is NULL.") == RM_WHACKED))
3141 	return(RM_WHACKED);
3142 
3143     if ((p->fbClearNode == NULL) || (p->fbClearNode->fbClear == NULL) || (p->fbClearNode->fbClear->depthValue == NULL))
3144 	return(RM_WHACKED);
3145 
3146     *dv = *(p->fbClearNode->fbClear->depthValue);
3147 
3148     return(RM_CHILL);
3149 }
3150 /* EOF */
3151