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