/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmscene.c,v 1.15 2005/06/26 18:58:42 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.15 $ * $Log: rmscene.c,v $ * Revision 1.15 2005/06/26 18:58:42 wes * Updated rmNodeSceneGetFog to return RM_WHACKED when no RMfog is present. * * Revision 1.14 2005/06/12 21:18:23 wes * Minor language changes to in-code documentation. * * Revision 1.13 2005/06/06 02:04:29 wes * Lots of small additions to clean up compiler warnings. * * Revision 1.12 2005/05/16 01:02:16 wes * Updated code documentation. * * Revision 1.11 2005/02/24 16:17:25 wes * Added support for fbClears to be set at the RMpipe level. Apps can * still set them at the RMnode level if desired for fine-grained control. * * Revision 1.10 2005/02/19 16:22:50 wes * Distro sync and consolidation. * * Revision 1.9 2005/01/23 17:08:25 wes * Copyright updated to 2005. * Updates to support access and use of extensions; multitexturing on all * platforms, use of 3d texture extension to realize implementation of * volume rendering and related functions on Windows platforms. * * Revision 1.8 2004/06/22 05:01:58 wes * Minor tweaks to support consistent state tracking. These changes * were made as a result to changes in the main RMSG tree during a * big PS bug fixing expedition. * * Revision 1.7 2004/04/09 14:48:18 wes * Fix compile warnings about unused variables. * * Revision 1.6 2004/01/16 16:48:35 wes * Updated copyright line for 2004. * * Revision 1.5 2003/11/22 00:53:41 wes * Changes to support RMtextures being shared when assigned as scene parameters * to properly implement instancing. * * Revision 1.4 2003/10/03 19:20:16 wes * Repaired bogus error message on rmNodeSetSceneLight(). * * Revision 1.3 2003/02/14 00:20:51 wes * No significant changes. * * Revision 1.2 2003/02/02 02:07:15 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.15 2003/01/20 05:39:49 wes * Rewrote texture state handling code. * * Revision 1.14 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.13 2002/04/30 19:33:26 wes * Updated copyright dates. * * Revision 1.12 2001/10/15 00:12:25 wes * Different treatment of rmTextProps scene params. The rmTextProps is * owned by the component manager, so we can't directly memcpy stuff from * one to another without causing problems. * * Revision 1.11 2001/07/15 17:15:29 wes * Cleanup of code that manages RMtextProps objects. * * Revision 1.10 2001/05/26 14:38:19 wes * Doc additions. * * Revision 1.9 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.8 2000/12/05 03:02:52 wes * Updated rmNodeSetSceneTexture to use rmImageDup() when copying * images from caller-supplied Rmtexture. Code-resident docs also updated. * * Revision 1.7 2000/12/03 22:35:38 wes * Mods for thread safety. * * Revision 1.6 2000/08/30 02:08:55 wes * In rmNodeSetSceneClipPlane, moved creation of scene parms struct * to earlier in the routine. Its previous placement was an error. * * Revision 1.5 2000/05/17 14:20:18 wes * Added lots of documentation. * * Revision 1.4 2000/05/14 15:24:53 wes * Added lots of documentation. * * Revision 1.3 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.2 2000/02/29 23:43:53 wes * Compile warning cleanups. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:48 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ /* documentation of public routines is incomplete in this file. */ #include #include "rmprivat.h" /* PRIVATE declarations */ internals_RMsceneParms *private_rmNodeSceneParmsNew (void); RMenum private_rmNodeSetSceneTexture(RMnode *n, RMtexture *t, int textureUnit); /* * ---------------------------------------------------- * @Name rmNodeSetSceneBackgroundColor @pstart RMenum rmNodeSetSceneBackgroundColor (RMnode *toModify, const RMcolor4D *newColor) @pend @astart RMnode *toModify - a handle to an RMnode (input). const RMcolor4D *newColor - a handle to the desired background color (input). @aend @dstart Use this routine to set the background color scene parameter. Calling this routine with a color argument of NULL disables the background color scene parameter. During rendering, the color planes of the framebuffer are cleared to this background color (with a depth value of 1.0, see NOTE below). Upon success, RM_CHILL is returned and the specified background color scene parameter is set. Otherwise, RM_WHACKED is returned, and the background color scene parameter remains unmodified. Passing in a value of NULL for the RMcolor4D object will effectively remove any existing background image color parameter from the RMnode toModify. NOTE: internal to this routine, a call to rmNodeSetSceneDepthValue is performed, effectively coupling framebuffer and depthbuffer clears. Because this routine makes a copy of the input scene parameter (an RMcolor4D object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. Related routines: rmNodeSetSceneBackgroundImageTile, rnNodeSetSceneDepthValue. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneBackgroundColor (RMnode *r, const RMcolor4D *new_color) { if (RM_ASSERT(r, "rmNodeSetSceneBackgroundColor() error: the input RMnode pointer is NULL.") == RM_WHACKED) return(RM_WHACKED); if (r->fbClear == NULL) r->fbClear = private_rmFBClearNew(); if (r->fbClear->bgColor != NULL) rmColor4DDelete(r->fbClear->bgColor); if (new_color != NULL) { float junk; r->fbClear->bgColor = rmColor4DNew(1); C4COPY(r->fbClear->bgColor, new_color); if (rmNodeGetSceneDepthValue(r, &junk) == RM_WHACKED) { extern float RM_DEFAULT_DEPTH_VALUE; junk = RM_DEFAULT_DEPTH_VALUE; rmNodeSetSceneDepthValue(r, &junk); } } else r->fbClear->bgColor = NULL; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneBackgroundColor @pstart RMenum rmNodeGetSceneBackgroundColor (const RMnode *toQuery, RMcolor4D *returnColor) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMcolor4D *returnColor - a handle to a caller-supplied RMcolor4D object (return). @aend @dstart Use this routine to obtain the background color scene parameter of an RMnode, if such a scene parameter exists. Upon success, RM_CHILL is returned and the scene background color is copied into the caller-supplied RMcolor4D (effectively returning a copy of the background color scene parameter to the caller). If no such scene parameter exists, or if there is some error condition detected, RM_WHACKED is returned, and the caller-supplied colorReturn object remains unmodified. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneBackgroundColor (const RMnode *r, RMcolor4D *color_return) { if ((RM_ASSERT(r, "rmNodeGetSceneBackgroundColor() error: the input RMnode pointer is NULL.") == RM_WHACKED) || (RM_ASSERT(color_return, "rmNodeGetSceneBackgroundColor() error: the return RMcolor4D pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((r->fbClear == NULL) || (r->fbClear->bgColor == NULL)) return(RM_WHACKED); /* we are returning the contents of the scene parameter, an RMcolor4D object, to the caller, not the handle to the RMcolor4D object stored in the scene graph itself. */ *color_return = *(r->fbClear->bgColor); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneBackgroundImage @pstart RMenum rmNodeSetSceneBackgroundImage (RMnode *toModify, const RMimage *newImageTile) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMimage *newImageTile - a handle to an RMimage (input). @aend @dstart Sets the background image scene parameter for the RMnode. When rendered, this image is tiled into the viewport at the scene depth value (or a default of 1.0) with an orthogonal projection, creating a background image. If the image does not fit the display, it will be tiled from top to bottom and left to right, so ragged edges fall on the bottom and right edges of the viewport. Passing in a value of NULL for the newImageTile parameter will effectively remove the background image tile scene parameter, if it exists. Upon success, RM_CHILL is returned and the background image scene parameter has been modified. Otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMimage object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. NOTE: internal to this routine, a call to rmNodeSetSceneDepthValue() is performed, effectively coupling framebuffer clears (by image tiling) with depth buffer clears. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneBackgroundImage (RMnode *n, const RMimage *tile) { if (RM_ASSERT(n, "rmNodeSetSceneBackgroundImage() error: input RMnode is NULL. \n") == RM_WHACKED) return(RM_WHACKED); if (n->fbClear == NULL) n->fbClear = private_rmFBClearNew(); /* if there's an existing background image tile parameter, remove it. */ if (n->fbClear->bgImageTile != NULL) rmImageDelete(n->fbClear->bgImageTile); /* if the input isn't null, make a copy and assign it as a scene parameter. */ if (tile != NULL) { float junk; n->fbClear->bgImageTile = rmImageDup(tile); /* if there's no background depth value, create one. this policy may change in the future. */ if (rmNodeGetSceneDepthValue(n, &junk) == RM_WHACKED) { extern float RM_DEFAULT_DEPTH_VALUE; junk = RM_DEFAULT_DEPTH_VALUE; rmNodeSetSceneDepthValue(n, &junk); } } else n->fbClear->bgImageTile = NULL; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneBackgroundImage @pstart RMenum rmNodeGetSceneBackgroundImage (const RMnode *toQuery, RMimage **returnImageTile) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMimage **returnImageTile - a handle to an RMimage handle (return). @aend @dstart Use this routine to obtain the background image scene parameter of an RMnode. Note that a handle to the RMimage is returned, not a copy of the actual pixel data. Upon success, RM_CHILL is returned and a handle to the scene background image is copied into the caller-supplied RMimage handle. Otherwise, RM_WHACKED is returned. Unlike most other rmNodeGetScene*() routines, this routine returns a handle to the actual object contained within the scene graph, rather than returning a copy. Applications should exercise appropriate discretion when using this object. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneBackgroundImage (const RMnode *r, RMimage **tile_return) { if ((RM_ASSERT(r, "rmNodeGetSceneBackgroundImage() error: input RMnode is NULL. \n") == RM_WHACKED) || (RM_ASSERT(r, "rmNodeGetSceneBackgroundImage() error: input pointer to RMimage pointer is NULL. ") == RM_WHACKED)) return(RM_WHACKED); /* detect the absence of any scene parms, or the absence of the background image tile scene parm. */ if ((r->fbClear == NULL) || (r->fbClear->bgImageTile == NULL)) return(RM_WHACKED); *tile_return = r->fbClear->bgImageTile; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneCamera2D @pstart RMenum rmNodeSetSceneCamera2D (RMnode *toModify, const RMcamera2D *newCamera) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMcamera2D *newCamera - a handle to an RMcamera2D object (input). @aend @dstart Assign a 2D camera as a scene parameter to an RMnode. The 2D camera scene parameter defines a rectangular viewing region, and results in the render-time modification of the OpenGL view and projection matrices. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned and the RMnode's scene parameters remain unmodified. Passing in a value of NULL for the RMcamera2D object will effectively remove any existing 2D camera scene parameter from the RMnode toModify. Because this routine makes a copy of the input scene parameter (an RMcamera2D object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneCamera2D (RMnode *n, const RMcamera2D *c) { if (RM_ASSERT(n, "rmNodeSetSceneCamera2D() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if (n->scene_parms->camera2d != NULL) { rmCamera2DDelete(n->scene_parms->camera2d); n->scene_parms->camera2d = NULL; } if (c != NULL) { n->scene_parms->camera2d = rmCamera2DNew(); *(n->scene_parms->camera2d) = *c; } return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneCamera2D @pstart RMenum rmNodeGetSceneCamera2D (const RMnode *toQuery, RMcamera2D **returnCamera) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMcamera2D **returnCamera - a handle to anRMcamera2D object (return). @aend @dstart If a 2D camera is defined for the RMnode, then a copy of the 2D camera is returned in the caller-supplied handle, and RM_CHILL is returned. Otherwise, RM_WHACKED is returned, and the caller supplied RMcamera2D object handle remains unmodified. Because this routine returns a COPY of the RMnode's scene parameter (an RMcamera2D object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmCamera2DDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneCamera2D (const RMnode *n, RMcamera2D **c) { if ((RM_ASSERT(n, "rmNodeGetSceneCamera2D() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(c, "rmNodeGetSceneCamera2D() error: the input pointer to an RMcamera2D pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->camera2d == NULL)) return(RM_WHACKED); *c = rmCamera2DNew(); *(*c) = *(n->scene_parms->camera2d); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneCamera3D @pstart RMenum rmNodeSetSceneCamera3D (RMnode *toModify, const RMcamera3D *newCamera) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMcamera3D *newCamera - a handle to an RMcamera3D (input). @aend @dstart Assign a 3D camera as a scene parameter to an RMnode. The 3D camera defines a viewing volume in world coordinats. Objects that lie within this view volume will be visible when rendered. The 3D camera scene parameter will produce a render-time modification of the OpenGL modelview and projection matrices. The effect of these matrix stack modifications have scope only over the subtree rooted at the RMnode toModify. Passing in a value of NULL for the input RMcamera3D object will effectively remove any existing RMcamera3D scene parameter from the RMnode. Upon success, a copy of the input RMcamera3D object is made (if not NULL), and assigned as a scene parameter to the input RMnode; Otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMcamera3D object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneCamera3D (RMnode *n, const RMcamera3D *c) { if (RM_ASSERT(n, "rmNodeSetSceneCamera3D() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if (n->scene_parms->camera3d != NULL) { rmCamera3DDelete(n->scene_parms->camera3d); n->scene_parms->camera3d = NULL; } if (c != NULL) { n->scene_parms->camera3d = rmCamera3DNew(); *(n->scene_parms->camera3d) = *c; } return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneCamera3D @pstart RMenum rmNodeGetSceneCamera3D (const RMnode *toQuery, RMcamera3D **returnCamera) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMcamera3D **returnCamera - a handle to a caller-supplied RMcamera3D object (modified). @aend @dstart If a 3D camera is defined for the RMnode, then a copy of the 3D camera is created, then returned in the caller-supplied handle, and RM_CHILL is returned. Otherwise, RM_WHACKED is returned and the caller-supplied RMcamera3D handle remains unmodified. Because this routine returns a COPY of the RMnode's scene parameter (an RMcamera3D object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmCamera3DDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneCamera3D (const RMnode *n, RMcamera3D **c) { if ((RM_ASSERT(n, "rmNodeGetSceneCamera3D() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(c, "rmNodeGetSceneCamera3D() error: the input pointer to an RMcamera3D pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->camera3d == NULL)) return(RM_WHACKED); *c = rmCamera3DNew(); *(*c) = *(n->scene_parms->camera3d); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneClipPlane @pstart RMenum rmNodeSetSceneClipPlane (RMnode *toModify, RMenum clipPlaneEnum, const RMclipPlane *newClipPlane) @pend @astart RMnode *toModify - a handle to an RMnode (input). RMenum clipPlaneEnum - an RMenum specifying which clipping plane to modify. Must be one of [RM_SCENE_CLIP_PLANE0..5] (input). const RMclipPlane *newClipPlane - a handle to an RMclipPlane handle (input). @aend @dstart Assigns a clip plane as a scene parameter to an RMnode. This routine will make a copy of the input RMclipPlane object, and assign the copy as a scene parameter to the input RMnode. See rmClipPlaneNew() for more details about how clip planes are specified. Passing in a value of NULL for the newClipPlane parameter will effectively remove the clip plane scene parameter specified by clipPlaneEnum, if it exists. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMclipPlane), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneClipPlane (RMnode *n, RMenum which_clip_plane, const RMclipPlane *ncp) { RMclipPlane **target = NULL, *t; if (RM_ASSERT(n, "rmNodeSetSceneClipPlane() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); switch (which_clip_plane) { case RM_SCENE_CLIP_PLANE0: target = &(n->scene_parms->cp0); break; case RM_SCENE_CLIP_PLANE1: target = &(n->scene_parms->cp1); break; case RM_SCENE_CLIP_PLANE2: target = &(n->scene_parms->cp2); break; case RM_SCENE_CLIP_PLANE3: target = &(n->scene_parms->cp3); break; case RM_SCENE_CLIP_PLANE4: target = &(n->scene_parms->cp4); break; case RM_SCENE_CLIP_PLANE5: target = &(n->scene_parms->cp5); break; default: rmWarning("rmNodeSetSceneClipPlane error: bad clip plane enumerator specified by calling routine. "); return(RM_WHACKED); } /* this conditional should never evaluate to TRUE. */ if (RM_ASSERT(target,"rmNodeSetSceneClipPlane() error: input enumerator specifying a clip plane is invalid.") == RM_WHACKED) return(RM_WHACKED); t = *target; if (t != NULL) { rmClipPlaneDelete(t); *target = NULL; } if (ncp != NULL) { t = *target = rmClipPlaneNew(); memcpy((void *)t, (void *)ncp, sizeof(RMclipPlane)); } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneClipPlane @pstart RMenum rmNodeGetSceneClipPlane (const RMnode *toQuery, RMenum clipPlaneEnum, RMclipPlane **returnClipPlane) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMenum clipPlaneEnum - an RMenum indicating which clip plane is being modified. Must be one of RM_SCENE_CLIP_PLANE[0-5] (input). RMclipPlane **returnClipPlane - a caller-supplied handle to an RMclipPlane handle (return). @aend @dstart Use this routine to obtain one of six possible clip planes from an RMnode's scene parameters. Upon success, a copy of the requested clip plane is created and returned to the caller via the returnClipPlane handle, and RM_CHILL is returned. Otherwise, RM_WHACKED is returned, and the caller supplied RMclipPlane handle remains unmodified. Because this routine returns a COPY of the RMnode's scene parameter (an RMclipPlane object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmClipPlaneDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneClipPlane (const RMnode *n, RMenum which_clip_plane, RMclipPlane **rcp) { RMclipPlane **target=NULL, *t; if ((RM_ASSERT(n, "rmNodeGetSceneClipPlane() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(rcp, "rmNodeGetSceneClipPlane() error: the input pointer to an RMclipPlane pointer is NULL. ") == RM_WHACKED)) return(RM_WHACKED); if (n->scene_parms == NULL) return(RM_WHACKED); switch (which_clip_plane) { case RM_SCENE_CLIP_PLANE0: target = &(n->scene_parms->cp0); break; case RM_SCENE_CLIP_PLANE1: target = &(n->scene_parms->cp1); break; case RM_SCENE_CLIP_PLANE2: target = &(n->scene_parms->cp2); break; case RM_SCENE_CLIP_PLANE3: target = &(n->scene_parms->cp3); break; case RM_SCENE_CLIP_PLANE4: target = &(n->scene_parms->cp4); break; case RM_SCENE_CLIP_PLANE5: target = &(n->scene_parms->cp5); break; default: /* bogus clip plane enum */ rmWarning("rmNodeGetSceneClipPlane() error: bad clip plane enumerator specified by calling routine."); return(RM_WHACKED); } /* this conditional should NEVER evaluate to true. */ if (RM_ASSERT(target,"rmNodeGetSceneClipPlane() error: input enumerator specifying a clipping plane is invalid.") == RM_WHACKED) return(RM_WHACKED); t = rmClipPlaneNew(); memcpy((void *)t, (void *)(*target), sizeof(RMclipPlane)); *rcp = t; /* the app is now responsible for this memory */ return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneDepthImage @pstart RMenum rmNodeSetSceneDepthImage (RMnode *toModify, const RMimage *newDepthImage) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMimage *newDepthImage - a handle to a depth image (input) @aend @dstart Assigns a depth image as a scene parameter for the RMnode. The depth image is similar to the background image tile, but is applied to the depth buffer, rather than the color planes of the framebuffer. Like the background image tile, the depth image scene parameter is tiled to fill the framebuffer, starting from the upper left-hand corner of the viewport. If the size of the depth buffer image and viewport do not match exactly, the "ragged edges" or on the right and the bottom of the viewport. Passing in a value of NULL for the RMimage object will have the effect of removing the background depth image scene parameter, if one exists, from the RMnode. Upon success, a copy of the caller's RMimage object is made, and the copy is assigned as a scene parameter (or, if the input RMimage object is NULL, the NULL is assigned as a depth image scene parameter, effectively turning off that scene parameter), and RM_CHILL is returned; otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMimage), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. Note: as a practical matter, it is suggested that the pixel format of input RMimage objects should be of type RM_FLOAT, and in the range 0..1. By default, depth buffer Pixels in OpenGL range from 0..1 (or perhaps 0..0.9999, depending upon your interpretation), but this range may be manipulated with glPixelTransferf(). As of the time of this writing (May 2000), we have tested background depth images only with RMimage's consisting of RM_FLOAT pixels in the range 0..1 (and they work - refer to the demonstration program "pdb" included with the openrm-demo distribution). @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneDepthImage (RMnode *n, const RMimage *new_depth_image) { if (RM_ASSERT(n, "rmNodeSetSceneDepthImage() error: the input RMnode pointer is NULL.") == RM_WHACKED) return(RM_WHACKED); if (n->fbClear == NULL) n->fbClear = private_rmFBClearNew(); if (n->fbClear->depthImage != NULL) { rmImageDelete(n->fbClear->depthImage); n->fbClear->depthImage = NULL; } if (new_depth_image != NULL) n->fbClear->depthImage = rmImageDup(new_depth_image); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneDepthImage @pstart RMenum rmNodeGetSceneDepthImage (const RMnode *toQuery, RMimage **returnDepthImage) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMimage **returnDepthImage - a handle to a depth image handle (return). @aend @dstart Use this routine to obtain the RMnode's depth image scene parameter. If such a scene parameter exists, the handle of the RMimage (depth image) scene parameter is copied into caller-supplied memory, and RM_CHILL is returned. Otherwise, in the event of an error or the absence of the depth image scene parameter, RM_WHACKED is returned and caller supplied memory remains unmodified. Unlike most other rmNodeGetScene*() routines, this routine returns a handle to the actual RMimage object contained within the scene graph, rather than returning a copy. Applications should exercise appropriate discretion when using this object. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneDepthImage (const RMnode *n, RMimage **depth_image_return) { if ((RM_ASSERT(n, "rmNodeGetSceneDepthImage() error: input RMnode is NULL. \n") == RM_WHACKED) || (RM_ASSERT(depth_image_return, "rmNodeGetSceneDepthImage() error: input pointer to RMimage pointer is NULL. ") == RM_WHACKED)) return(RM_WHACKED); if ((n->fbClear == NULL) || (n->fbClear->depthImage == NULL)) return(RM_WHACKED); *depth_image_return = n->fbClear->depthImage; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneDepthValue @pstart RMenum rmNodeSetSceneDepthValue (RMnode *toModify, const float *newDepthValue) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const float *newDepthValue - a handle to the new depth value for the node (input). @aend @dstart Use this routine to set the scene depth value parameter for an RMnode. The presence of the scene depth value has the effect of clearing the depth buffer to the value of newDepthValue. Passing in a value of NULL for newDepthValue has the effect of disabling depth buffer clears. The input newDepthValue should have the magnitude specified by glPixelTransferf(GL_DEPTH_SCALE,X) and range specified by glPixelTransferf(GL_DEPTH_BIAS,X). In OpenGL, the default depth bias is 0.0 and range/scale is 1.0. Upon success, RM_CHILL is returned and the node's depth value is set. Otherwise, RM_WHACKED is returned. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneDepthValue (RMnode *n, const float *newDepthValue) { if (RM_ASSERT(n, "rmNodeSetSceneDepthValue() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->fbClear == NULL) n->fbClear = private_rmFBClearNew(); if (n->fbClear->depthValue != NULL) { free((void *)(n->fbClear->depthValue)); n->fbClear->depthValue = NULL; } if (newDepthValue != NULL) { n->fbClear->depthValue = rmFloatNew(1); *(n->fbClear->depthValue) = *newDepthValue; } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneDepthValue @pstart RMenum rmNodeGetSceneDepthValue (const RMnode *toQuery, float *returnDepthValue) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). float *returnDepthValue - a handle to a caller-supplied float for the queried depth value (return). @aend @dstart Use this routine to query the scene depth value for a given RMnode. Upon success, RM_CHILL is returned and the node's depth value is copied into the caller-supplied float. If the specified pointers are NULL, or no valid scene depth parameter exists, RM_WHACKED is returned. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneDepthValue (const RMnode *n, float *dr) { if ((RM_ASSERT(n, "rmNodeGetSceneDepthValue() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(dr, "rmNodeGetSceneDepthValue() error: the return float pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->fbClear == NULL) || (n->fbClear->depthValue == NULL)) return(RM_WHACKED); *dr = *(n->fbClear->depthValue); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneFog @pstart RMenum rmNodeSetSceneFog (RMnode *toModify, const RMfog *newFog) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMfog *newFog - a handle to the new fog scene parameters (input). @aend @dstart Use this routine to set the fog scene parameters for an RMnode. If no scene parameters have been defined, then the RMfog object is duplicated into the RMnode. Existing fog parameters are first deleted, thenn replaced with the new fog parameters. Calling this routine with a an argument of NULL for the RMfog object disables the fog scene parameters. When a non-NULL RMfog object is added as a scene parameter to an RMnode, fogging will become enabled. The fogging will have scope only over the subtree rooted at the RMnode toModify. When the RMfog object is NULL, fogging is disabled (unless fogging is enabled at an anscestor node in the scene graph). Upon success, RM_CHILL is returned and the node's fog parameters are set. Otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMfog object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneFog (RMnode *n, const RMfog *newFog) { if (RM_ASSERT(n, "rmNodeSetSceneFog() error: the input RMnode pointer is NULL.") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if (n->scene_parms->fog != NULL) { rmFogDelete(n->scene_parms->fog); n->scene_parms->fog = NULL; } if (newFog != NULL) n->scene_parms->fog = rmFogDup(newFog); private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneFog @pstart RMenum rmNodeGetSceneFog (const RMnode *toQuery, RMfog **returnFog) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMfog **returnFog - a pointer to an RMfog handle (return). @aend @dstart Use this routine to query the fog scene parameters for an RMnode. If no fog scene parameters exists for the RMnode, then RM_WHACKED is returned and no changes will be made to the input returnFog parameter. Upon success, RM_CHILL is returned and a handle to the node's fog scene parameters are copied into the caller-supplied handle. Unlike most other rmNodeGetScene*() routines, this routine returns a handle to the actual RMfog object contained within the scene graph, rather than returning a copy. Applications should exercise appropriate discretion when using this object. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneFog (const RMnode *n, RMfog **returnFog) { if ((RM_ASSERT(n, "rmNodeGetSceneFog() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(returnFog, "rmNodeGetSceneFog() error: the returnFog pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if (n->scene_parms == NULL || n->scene_parms->fog == NULL) return RM_WHACKED; *returnFog = n->scene_parms->fog; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneLight @pstart RMenum rmNodeSetSceneLight (RMnode *toModify, RMenum whichLightEnum, const RMlight *newLight) @pend @astart RMnode *toModify - a handle to an RMnode (modified). RMenum whichLightEnum - an RMenum specifying which light tp modify. Must be one of [RM_LIGHT0..7] (input). const RMlight *newLight - a handle to an RMlight handle (input). @aend @dstart Use this routine to assign a light source as a scene parameter to an RMnode. The light source is specified with an RMlight object (see rmLightNew for more information). Up to eight light sources may be simultaneously active, or specified at an RMnode by the RMenum values RM_LIGHT0, RM_LIGHT1, ... , RM_LIGHT7. When a non-NULL light source is assigned as a scene parameter, that light source becomes active, and has scope over the subtree rooted at the RMnode toModify within the scene graph. Assinging a NULL light source to one of the eight potential light source scene parameters will deactivate that particular light source. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMlight object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneLight (RMnode *n, RMenum which_light, const RMlight *l) { RMlight **target=NULL, *t; if (RM_ASSERT(n, "rmNodeSetSceneLight() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); switch (which_light) { case RM_LIGHT0: target = &(n->scene_parms->lightSources[0]); break; case RM_LIGHT1: target = &(n->scene_parms->lightSources[1]); break; case RM_LIGHT2: target = &(n->scene_parms->lightSources[2]); break; case RM_LIGHT3: target = &(n->scene_parms->lightSources[3]); break; case RM_LIGHT4: target = &(n->scene_parms->lightSources[4]); break; case RM_LIGHT5: target = &(n->scene_parms->lightSources[5]); break; case RM_LIGHT6: target = &(n->scene_parms->lightSources[6]); break; case RM_LIGHT7: target = &(n->scene_parms->lightSources[7]); break; default: /* bogus light enum */ rmWarning("rmNodeSetSceneLight() error: bad light enumerator specified by calling routine."); return(RM_WHACKED); } if (RM_ASSERT(target, "rmNodeSetSceneLight() error: input enumerator specifying a light is invalid.") == RM_WHACKED) return(RM_WHACKED); t = *target; if (t != NULL) { rmLightDelete(t); *target = NULL; } if (l != NULL) { t = *target = rmLightNew(); memcpy((void *)t, (void *)l, sizeof(RMlight)); } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneLight @pstart RMenum rmNodeGetSceneLight (const RMnode *toQuery, RMenum whichLightEnum, RMlight **returnLightCopy) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMenum whichLightEnum - an RMenum indicating which RMlight to query. Must be one of RM_LIGHT0, RM_LIGHT1, ... , RM_LIGHT7 (input). RMlight **returnLightCopy - a caller-supplied handle to an RMlight handle (return). @aend @dstart Use this routine to obtain one of eight possible lights defined as scene parameters for an RMnode. If no such scene parameter is defined, RM_WHACKED is returned, and the caller-supplied pointer to an RMlight pointer remains unmodified. Upon success, RM_CHILL is returned, and a copy of the specified RMlight object is created, and the handle to the new copy is returned via the caller-supplied handle. Applications Because this routine returns a COPY of the RMnode's scene parameter (an RMlight object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmLightDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneLight (const RMnode *n, RMenum which_light, RMlight **l) { RMlight **target=NULL,*t; if ((RM_ASSERT(n, "rmNodeGetSceneLight() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(l, "rmNodeGetSceneLight() error: the input pointer to an RMlight pointer is NULL. ") == RM_WHACKED)) return(RM_WHACKED); if (n->scene_parms == NULL) return(RM_WHACKED); switch (which_light) { case RM_LIGHT0: target = &(n->scene_parms->lightSources[0]); break; case RM_LIGHT1: target = &(n->scene_parms->lightSources[1]); break; case RM_LIGHT2: target = &(n->scene_parms->lightSources[2]); break; case RM_LIGHT3: target = &(n->scene_parms->lightSources[3]); break; case RM_LIGHT4: target = &(n->scene_parms->lightSources[4]); break; case RM_LIGHT5: target = &(n->scene_parms->lightSources[5]); break; case RM_LIGHT6: target = &(n->scene_parms->lightSources[6]); break; case RM_LIGHT7: target = &(n->scene_parms->lightSources[7]); break; default: /* bogus light enum */ rmWarning("rmNodeGetSceneLight() error: bad light enumerator specified by calling routine."); return(RM_WHACKED); } if (RM_ASSERT(*target, "rmNodeGetSceneLight() error: the input node has no light source associated with the input RM_LIGHT* enumerator.") == RM_WHACKED) return(RM_WHACKED); t = rmLightNew(); memcpy((void *)t, (void *)(*target), sizeof(RMlight)); *l = t; /* the app will now be responsible for this memory */ return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneLightModel @pstart RMenum rmNodeSetSceneLightModel (RMnode *toModify, const RMlightModel *newLightModel) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMlightModel *newLightModel - a handle to an RMlightModel (input). @aend @dstart Set the light model used by an RMnode. The RMlightmodel controls the ambient light color, whether two-sided lighting is enabled, and whether the local viewer is enabled for specular calculations. If no light model has been defined, then the RMlightModel object is duplicated into the RMnode. An existing light model is deleted and overwritten with the new light model. Calling this routine with an RMlightModel argument of NULL has the effect of removing any existing light model specification from the input RMnode. A light model that is specified at an ancestor node in the scene graph, if any, will be used to control light model parameters. See rmLightModelNew for details of the RMlightModel parameters. Upon success, RM_CHILL is returned and the RMnode contains the new light model. Otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMlightModel object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneLightModel (RMnode *n, const RMlightModel *lm) { if (RM_ASSERT(n, "rmNodeSetSceneLightModel() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if (n->scene_parms->lmodel != NULL) { rmLightModelDelete(n->scene_parms->lmodel); n->scene_parms->lmodel = NULL; } if (lm != NULL) { n->scene_parms->lmodel = rmLightModelNew(); memcpy((void *)(n->scene_parms->lmodel), (void *)lm, sizeof(RMlightModel)); } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneLightModel @pstart RMenum rmNodeGetSceneLightModel (const RMnode *toQuery, RMlightModel **lightModelReturn) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMlightModel **returnLightModel - a caller-supplied handle to an RMlightModel handle (return). @aend @dstart Obtains a copy of the light model scene parameter for an RMnode. If no such scene parameter exists, RM_WHACKED is returned, and the pointer to the caller-supplied RMlightModel pointer remains unmodified. Otherwise, a copy of the RMnode's RMlightModel parameter is created, the pointer to this new object is copied into caller-supplied memory, and RM_CHILL is returned. Because this routine returns a COPY of the RMnode's scene parameter (an RMlightModel object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmLightModelDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneLightModel (const RMnode *n, RMlightModel **lm) { if ((RM_ASSERT(n, "rmNodeGetSceneLightModel() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(lm, "rmNodeGetSceneLightModel() error: the input pointer to an RMlightModel pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->lmodel == NULL)) return(RM_WHACKED); *lm = rmLightModelNew(); memcpy((void *)(*lm), (void *)(n->scene_parms->lmodel), sizeof(RMlightModel)); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmTextPropsNew @pstart RMtextProps * rmTextPropsNew (void) @pend @astart No arguments. @aend @dstart Creates a new RMtextProps object and returns a handle to the caller. Upon success, the returned handle points to a new RMtextProps object. If resources cannot be allocated, then a NULL handle is returned. The RMtextProps object may be assigned as a scene parameter to RMnodes, where it will control text rendering properties, such as font family, size, italizication, etc. These text properties may be thought of in the same way as other drawing parameters, such as material properties, current color, and so forth. The defaults text rendering properties set by rmTextPropsNew() are controlled by definitions in rmglobals.c, and are:
RMenum RM_DEFAULT_HJUSTIFY    = RM_LEFT;
RMenum RM_DEFAULT_VJUSTIFY    = RM_BOTTOM;
RMenum RM_DEFAULT_FONT_FAMILY = RM_FONT_SANS;
RMenum RM_DEFAULT_FONT_SIZE   = RM_FONT_M;
RMenum RM_DEFAULT_FONT_BOLD   = RM_FALSE;
RMenum RM_DEFAULT_FONT_ITALIC = RM_FALSE;
Use rmTextPropsSetAttribs() to set the attributes of an RMtextProps object, or rmTextPropsGetAttribs() to query attributes. @dend * ---------------------------------------------------- */ RMtextProps * rmTextPropsNew (void) { /* these are set in rmglobals.c */ extern int RM_DEFAULT_FONT_FAMILY, RM_DEFAULT_FONT_SIZE; extern RMenum RM_DEFAULT_FONT_BOLD, RM_DEFAULT_FONT_ITALIC, RM_DEFAULT_HJUSTIFY, RM_DEFAULT_VJUSTIFY; RMtextProps *t; t = private_rmTextPropsNew(); if (RM_ASSERT(t, "rmTextPropsNew() error: malloc failure. ") == RM_WHACKED) return(NULL); rmTextPropsSetAttribs(t, RM_DEFAULT_FONT_FAMILY, RM_DEFAULT_FONT_SIZE, RM_DEFAULT_FONT_BOLD, RM_DEFAULT_FONT_ITALIC, RM_DEFAULT_HJUSTIFY, RM_DEFAULT_VJUSTIFY); return(t); } /* * ---------------------------------------------------- * @Name rmTextPropsDelete @pstart RMenum rmTextPropsDelete (RMtextProps *toDelet) @pend @astart RMtextProps *toDelete - a handle to an RMtextProps object (deleted). @aend @dstart Deletes the resources associated with an RMtextProps object. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. @dend * ---------------------------------------------------- */ RMenum rmTextPropsDelete (RMtextProps *t) { if (RM_ASSERT(t, "rmTextPropsDelete() error: the input RMtextProps object is NULL") == RM_WHACKED) return(RM_WHACKED); return(private_rmTextPropsDelete(t)); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneTextProps @pstart RMenum rmNodeSetSceneTextProps (RMnode *toModify, const RMtextProps *newTextProps) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const RMtextProps *newTextProps - a handle to an RMtextProps object (input). @aend @dstart Assigns an RMtextProps object as a scene parameter for an RMnode. These text properties will control how strings are rendered within the subtree rooted at the RMnode toModify, unless subsequently overridden at a descendent RMnode. The text properties specify a font family, point size, horizontal and vertical justification control, and emboldening and italicization parameters. If the input RMtextProps object is NULL, any existing RMtextProps scene parameter is deleted. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an RMtextProps object), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneTextProps (RMnode *n, const RMtextProps *t) { if (RM_ASSERT(n, "rmNodeSetSceneTextProps() error: the input RMnode is NULL. \n") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if ((n->scene_parms->textProps == NULL) && (t != NULL)) n->scene_parms->textProps = rmTextPropsNew(); if (t != NULL) private_rmTextPropsCopy(t, n->scene_parms->textProps); else { if (n->scene_parms->textProps != NULL) rmTextPropsDelete(n->scene_parms->textProps); t = NULL; } #if 0 /* this code would actually generate OpenGL display lists for the string using the requested font and style. we're going to delay doing this until render time. */ /* register the font, size, embolden, italic with RM's font registry */ if (t != NULL) private_rmPrepareBitmapFont(n->scene_parms->textProps); #endif return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneTextProps @pstart RMenum rmNodeGetSceneTextProps (const RMnode *toQuery, RMtextProps **returnTextProps) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMtextProps **returnTextProps - a caller-supplied handle to an RMtextProps handle (return). @aend @dstart Obtains a copy of the RMtextProps object scene parameter for the RMnode, and returns a handle to the copy in the parameter returnTextProps, and RM_CHILL is returned on the stack. If no such scene parameter exists, or if there is some other error condition encountered, RM_WHACKED is returned on the stack, and the caller-supplied parameter returnTextProps remains unmodified. Because this routine returns a COPY of the RMnode's scene parameter (an RMtextProps object), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmTextProps the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneTextProps (const RMnode *n, RMtextProps **t) { if ((RM_ASSERT(n, "rmNodeGetSceneTextProps() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(t, "rmNodeGetSceneTextProps() error: the input pointer to an RMtextProps pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->textProps == NULL)) return(RM_WHACKED); *t = rmTextPropsNew(); private_rmTextPropsCopy(n->scene_parms->textProps, *t); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeSetSceneTexture @pstart RMenum rmNodeSetSceneTexture (RMnode *toModify, const RMtexture *newTexture) @pend @astart RMnode *n - a handle to an RMnode (modified). RMtexture *t - a handle to an RMtexture (input). @aend @dstart Assigns an RMtexture object as a scene parameter to the RMnode. The presence of a texture scene parameter will cause texture mapping to become active at the RMnode toModify, and will remain active using the supplied texture newTexture over the entire subtree rooted at the RMnode toModify, unless overridden by a different texture at a descendent node within the scene graph. In order for texture mapping to occur at the pixel fragment level, primitives need to have texture coordinates (as well as vertex data). Specifying a value of NULL for the input texture will remove any existing texture scene parameter from the RMnode, effectively disabling texture mapping within the scene graph subtree rooted at toModify. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. Starting with OpenRM version 1.5.1 and later, when you assign an RMtexture as a scene parameter to an RMnode, only a reference to the source RMtexture is copied. In this way, you can use a single RMtexture object as a source texture for an arbitrary number of scene graph nodes without incurring additional memory storage overhead for each instance of the texture. The caveat from an application developer's perspective is that you must treat RMtextures like RMnodes - don't delete them until they are really no longer needed. If you try to rmTextureDelete a texture that has been assigned as a scene parameter, rmTextureDelete will fail - the RMtexture has a reference counter that is incremented or decremented when it is assigned or removed as a scene parameter at the scene graph node level. The simplest way to delete the RMtexture assigned to one or more nodes as a scene parameter is to simply delete the node or tree of nodes. All associated scene parameters will be deleted when their reference counters reach a value of zero. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneTexture (RMnode *n, RMtexture *t) { RMenum rstat; if (RM_ASSERT(n, "rmNodeSetSceneTexture() error: the input RMnode pointer is NULL.") == RM_WHACKED) return RM_WHACKED; /* the index RM_MAX_MULTITEXTURES is reserved for "plain old, non-multitextured textures */ rstat = private_rmNodeSetSceneTexture(n, t, RM_MAX_MULTITEXTURES); return rstat; } /* * ---------------------------------------------------- * @Name rmNodeSetSceneMultiTexture @pstart RMenum rmNodeSetSceneMultiTexture (RMnode *toModify, const RMtexture *newTexture, int textureUnit) @pend @astart RMnode *n - a handle to an RMnode (modified). RMtexture *t - a handle to an RMtexture (input). int textureUnit - an integer value (input). @aend @dstart Similar in function to rmNodeSetSceneTexture, but different in the respect that the RMtexture is assigned to a specific multitexturing texturing unit. Multitexturing the process whereby pixel fragments are colored using texel colors obtained from multiple textures using multiple texture coordinates. It is not supported on all OpenGL platforms. During the rmPipeMakeCurrent() initialization sequence, the underlying OpenGL platform is queried to determine extensions, capabilities and so forth. After rmPipeMakeCurrent(), your application can call rmPipeGetNumMultitextureUnits() to determine the number of OpenGL texture units available. Note that this routine does not perform any error checking with regard to ensuring that the value you provide for textureUnit does not exceed the number of texture units. That sort of problem will result in an runtime error that may be difficult to track down. It is the application's responsiblity to ensure that the value for texturenit is valid for the particular implementation. Valid values for the "textureUnit" parameter are non-negative integers in the range 0..RM_MAX_MULTITEXTURES. Note that RM_MAX_MULTITEXTURES is a compile-time constant, and does not necessarily reflect the actual number of texture units supported by your OpenGL implementation. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneMultiTexture (RMnode *n, RMtexture *t, int textureUnit) { RMenum rstat; if (RM_ASSERT(n, "rmNodeSetSceneMultiTexture() error: the input RMnode pointer is NULL.") == RM_WHACKED) return RM_WHACKED; /* sanity check the input value. Want something between zero and RM_MAX_MULTITEXTURES */ if ((textureUnit < 0) || (textureUnit > (RM_MAX_MULTITEXTURES-1))) { char buf[256]; sprintf(buf, "rmNodeSetSceneMultitexture error - the input value for the textureUnit parameter needs to be between 0 and %d.", RM_MAX_MULTITEXTURES-1); rmError(buf); return RM_WHACKED; } rstat = private_rmNodeSetSceneTexture(n, t, textureUnit); return rstat; } /* * ---------------------------------------------------- * @Name rmNodeGetSceneTexture @pstart RMenum rmNodeGetSceneTexture (const RMnode *toQuery, RMtexture **returnTexture) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). RMtexture **returnTexture - a handle to an RMtexture handle (return). @aend @dstart Use this routine to obtain the handle of the RMtexture scene parameter at an RMnode. If such a scene parameter is present, a handle to the internal RMtexture object is copied into caller-supplied memory (returnTexture), and RM_CHILL is returned on the stack. Otherwise, RM_WHACKED is returned, and caller-supplied memory remains unmodified. This routine will be useful for applications that will use the routine rmNodeUpdateSceneTexture to replace the contents of a particular texture, perhaps on a time-varying basis. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneTexture (const RMnode *n, RMtexture **t) { if ((RM_ASSERT(n, "rmNodeGetSceneTexture() error: input RMnode pointer is NULL.") == RM_WHACKED) || (RM_ASSERT(t, "rmNodeGetSceneTexture() error: input pointer to RMtexture pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->textures[RM_MAX_MULTITEXTURES] == NULL)) return(RM_WHACKED); *t = n->scene_parms->textures[RM_MAX_MULTITEXTURES]; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneMultiTexture @pstart RMenum rmNodeGetSceneMultiTexture (const RMnode *toQuery, int textureIndx, RMtexture **returnTexture) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). int textureIndx - an integer value (input). RMtexture **returnTexture - a handle to an RMtexture handle (return). @aend @dstart Similar in function and return values to rmNodeGetSceneTexture. This routine is used to obtain a handle to the RMtexture that is assigned to a specific multitexturing texture unit. @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneMultiTexture (const RMnode *n, int textureIndx, RMtexture **t) { if ((RM_ASSERT(n, "rmNodeGetSceneMultiTexture() error: input RMnode pointer is NULL.") == RM_WHACKED) || (RM_ASSERT(t, "rmNodeGetSceneMultiTexture() error: input pointer to RMtexture pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((textureIndx < 0) || (textureIndx > (RM_MAX_MULTITEXTURES-1))) { char buf[256]; sprintf(buf,"rmNodeGetSceneMultiTexture error - the input textureIndx has a value of %d, but it should have a value in the range zero..%d \n", textureIndx, RM_MAX_MULTITEXTURES-1); rmWarning(buf); return RM_WHACKED; } if ((n->scene_parms == NULL) || (n->scene_parms->textures[textureIndx] == NULL)) return(RM_WHACKED); *t = n->scene_parms->textures[textureIndx]; return RM_CHILL; } /* * ---------------------------------------------------- * @Name rmNodeSetSceneViewport @pstart RMenum rmNodeSetSceneViewport (RMnode *toModify, const float *newViewport) @pend @astart RMnode *toModify - a handle to an RMnode (modified). const float *newViewport - a handle to an array of four floats, defining a viewport (input) [x, y, w, h]. @aend @dstart The viewport scene parameter defines a pixel rectangle in the window into which the final image is mapped. The four viewport parameters, (x, y, width, height), are passed in as a single array of floats. The (x,y) coordinate specifies the lower left corner of the viewport rectangle. Width and height are the size of the viewport. The input values are specified in normalized device coordinates: Use input values of {0.0, 0.0, 1.0, 1.0} to consume the entire window; an NDC coordinate of (0.5, 0.5) refers to a point in the middle of the display window, regardless of its pixel dimensions. Use this routine to specify a viewport as a scene parameter at an RMnode. Upon success, any existing viewport at the RMnode is removed, then a copy of the input viewport parameters are made, then assigned to the RMnode toModify. Passing in a value of NULL for the viewport parameter will result in the removal of any existing viewport scene parameter from the RMnode. Upon success, RM_CHILL is returned; otherwise, RM_WHACKED is returned. Because this routine makes a copy of the input scene parameter (an viewport specification), callers do not need to manage the input object after a successful return from this routine. This has important ramificiations: 1. Since a copy is made, any changes made to the caller's object will have no effect upon the scene graph, unless this routine is called again to update the scene parameter inside the scene graph; 2. Callers may safely delete their copy of the input object after a successful return from this routine. @dend * ---------------------------------------------------- */ RMenum rmNodeSetSceneViewport (RMnode *n, const float *vp) /* [x, y, w, h], ndc coords */ { if (RM_ASSERT(n, "rmNodeSetSceneViewport() error: the input RMnode pointer is NULL") == RM_WHACKED) return(RM_WHACKED); if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); if (n->scene_parms->viewport != NULL) { rmFloatDelete(n->scene_parms->viewport); n->scene_parms->viewport = NULL; } if (vp != NULL) { n->scene_parms->viewport = rmFloatNew(4); memcpy((void *)(n->scene_parms->viewport), (void *)vp, (sizeof(float) * 4)); } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetSceneViewport @pstart RMenum rmNodeGetSceneViewport (const RMnode *toQuery, float **returnViewport) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). float **returnViewport - a handle to an array of float (returned). @aend @dstart This routine is used to query the viewport scene parameters at an RMnode. If the input RMnode toQuery has a viewport scene parameter, a copy of the viewport is created, then the handle to the copy returned to the caller through the parameter returnViewport, and RM_CHILL is returned on the stack. Otherwise, RM_WHACKED is returned and the caller supplied return parameter returnViewport remains unmodified. Because this routine returns a COPY of the RMnode's scene parameter (an array of floats), two important ramifications should be noted: 1. Since a copy is returned, any changes made to the caller's object will have no effect upon the scene graph, unless the appropriate routine is called again to update the scene parameter inside the scene graph; 2. Callers are responsible for managing the returned object (rmFloatDelete the object when it is no longer needed). @dend * ---------------------------------------------------- */ RMenum rmNodeGetSceneViewport (const RMnode *n, float **vp) /* [x, y, w, h] */ { if ((RM_ASSERT(n, "rmNodeGetSceneViewport() error: the input RMnode pointer is NULL") == RM_WHACKED) || (RM_ASSERT(vp, "rmNodeGetSceneViewport() error: the input pointer to a float pointer is NULL.") == RM_WHACKED)) return(RM_WHACKED); if ((n->scene_parms == NULL) || (n->scene_parms->viewport == NULL)) return(RM_WHACKED); *vp = rmFloatNew(4); memcpy((void *)(*vp), (void *)(n->scene_parms->viewport), sizeof(float)*4); return(RM_CHILL); } /* PRIVATE */ RMtextProps * private_rmDefaultTextProps (RMpipe *p) { /* * create a known and "default" font that will be used when the * app wants to draw text, but fails to provide an RMtextProps * object anywhere in the scene graph. */ RMtextProps *tp; tp = rmTextPropsNew(); rmTextPropsSetAttribs(tp, RM_FONT_SANS, RM_FONT_M, RM_FALSE, RM_FALSE, RM_LEFT, RM_BOTTOM); if (p != NULL) private_rmPrepareBitmapFont(tp,p); return(tp); } /* PRIVATE */ internals_RMsceneParms * private_rmNodeSceneParmsNew (void) { internals_RMsceneParms *t; t = (internals_RMsceneParms *)malloc(sizeof(internals_RMsceneParms)); memset(t, 0, sizeof(internals_RMsceneParms)); t->haveAnyTextures = RM_FALSE; return(t); } /* PRIVATE */ internals_RMfbClear * private_rmFBClearNew (void) { internals_RMfbClear *t; t = (internals_RMfbClear *)malloc(sizeof(internals_RMfbClear)); memset(t, 0, sizeof(internals_RMfbClear)); return(t); } /* PRIVATE */ RMenum private_rmNodeSetSceneTexture(RMnode *n, RMtexture *t, int textureUnit) { if (n->scene_parms == NULL) n->scene_parms = private_rmNodeSceneParmsNew(); /* remove the old texture, if any */ if (n->scene_parms->textures[textureUnit] != NULL) { int refCount = private_rmTextureGetRefCount(n->scene_parms->textures[textureUnit]); /* * 11/21/03 * if the refCount is -1, then the texture isn't a shared texture * and we should delete it. */ if (refCount == -1) rmTextureDelete(n->scene_parms->textures[textureUnit], RM_TRUE); else { /* * otherwise, we want to decrement the reference count, but * clamp the new value to be >= 0. We won't automatically delete * a shared texture - that is the application's responsibility. */ refCount -= 1; if (refCount < 0) refCount = 0; private_rmTextureSetRefCount(n->scene_parms->textures[textureUnit], refCount); } } if (t != NULL) { /* update the RMtexture's context cache ID and data keys if they are not uninitialized. */ if (t->cacheKeyID == RM_CACHEKEY_UNINITIALIZED_VALUE) private_rmTextureSetIDCacheKey(t); if (t->cacheKeyData == RM_CACHEKEY_UNINITIALIZED_VALUE) private_rmTextureSetDataCacheKey(t); /* increment the texture's refcount */ private_rmTextureSetRefCount(t, private_rmTextureGetRefCount(t) + 1); n->scene_parms->textures[textureUnit] = t; } else n->scene_parms->textures[textureUnit] = NULL; { int i; n->scene_parms->haveAnyTextures = RM_FALSE; for (i=0; i <= RM_MAX_MULTITEXTURES; i++) { if (n->scene_parms->textures[i] != NULL) { n->scene_parms->haveAnyTextures = RM_TRUE; break; } } } private_rmNodeAttribMask(n,private_rmNodeComputeAttribMask(n),RM_SET); return RM_CHILL; } /* EOF */