/* * 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: rmprim.c,v 1.15 2005/06/09 00:45:29 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.15 $ * $Log: rmprim.c,v $ * Revision 1.15 2005/06/09 00:45:29 wes * More compiler warning fixes turned up by Windows build. * * Revision 1.14 2005/06/06 02:04:29 wes * Lots of small additions to clean up compiler warnings. * * Revision 1.13 2005/05/06 16:37:31 wes * Fixed buglet whereby 1D texture coords had the wrong stride assigned. * * Revision 1.12 2005/02/27 19:34:04 wes * Added support for application supplied texture object IDs and display lists. * * Revision 1.11 2005/02/19 16:42:30 wes * Distro sync and consolidation. * Remove dead code. * * Revision 1.10 2005/02/12 00:55:20 wes * Preliminary support for multitexturing. * * 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/03/10 01:46:41 wes * Added RM_INDEXED_QUAD_STRIP primitive type. * * Revision 1.7 2004/02/23 03:04:32 wes * New primitives: RM_QUAD_STRIP, RM_INDEXED_TRIANGLES, RM_INDEXED_QUADS, * RM_INDEXED_TRIANGLE_STRIP. * * Revision 1.6 2004/01/16 16:47:07 wes * Updated copyright line for 2004. * * Revision 1.5 2003/04/05 14:13:07 wes * Add code to rmNodeAddPrimitive that will leave the mutex in an unlocked * state upon detection of an error condition, and premature routine exit. * * Revision 1.4 2003/02/14 00:18:55 wes * Remove dead code. * * Revision 1.3 2003/02/02 17:50:57 wes * Added bounding boxes to RMprimitives, as a supplement to node-level bboxes. * The RMprimitive level bboxes are needed for the retained-mode CR work. * * 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.11 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.10 2003/01/11 18:44:22 wes * Added global control over whether or not display lists are used during * rendering by adding the new RMpipe controls rmPipeSetDisplayListEnable() * and rmPipeGetDisplayListEnable(). * * Revision 1.9 2002/12/02 16:24:56 wes * Bug fixes: * (1) fixed memory leak in rmPrimitiveSetText; * (2) fixed problem with textProps not being applied to 2nd and later * strings in an RM_TEXT text primitive. * * Revision 1.8 2002/09/22 17:34:06 wes * Updated private_rmPrimitiveSetItem() to return the correct status to * parent routines, such as rmPrimitiveSetVertex3D. * * Revision 1.7 2002/06/02 15:16:40 wes * Added RMstateCache code to help eliminate the number of state changes * made during the render traversal. The RMstateCache tracks * the actual OpenGL rendering state w/o the need for querying OpenGL * directly, and is queried by draw code that then decides if any * real state changes are required given the configuration of data * within an RMprimitive. * * Revision 1.6 2002/04/30 19:33:05 wes * Updated copyright dates. * * Revision 1.5 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.4 2000/12/03 22:33:55 wes * Mods for thread-safety. * * Revision 1.3 2000/05/17 14:24:04 wes * Added RM_POLYS (thanks to Matt and Todd of VRCO). * * Revision 1.2 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * 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. * */ #include #include "rmprivat.h" #include /* * this file contains routines that interface to the RMprimitive object. * the trickiest thing about primitives is that large-payload data * in primitives (verts, normals, etc) are stored in "data blobs." * most of the rmPrimitiveSet* routines that cache large-payload data * call an internal routine that maps from the requested data type * (verts, normals, indices, etc) into a "data blob" map. */ /* PRIVATE declarations */ RMenum private_rmPrimitiveSetItem(RMprimitive *p, int tag, int num, int stride, void *stuff, RMenum copy_flag, void (*freefunc)( void *)); RMenum private_rmPrimitiveSetMultiTexcoordBlob(RMprimitive *p, int tcTag, int n, int stride, void *stuff, RMenum copyFlag, void (*freefunc)(void *), int textureUnit); void private_rmPrimitiveSetCacheKey(RMprimitive *p); /* * ---------------------------------------------------- * @Name rmPrimitiveNew @pstart RMprimitive * rmPrimitiveNew (RMenum primType) @pend @astart RMenum primType - an RMenum value specifying the RM primitive type. See below for more information (input). @aend @dstart Use this routine to create a new RMprimitive object of a specified type. Returns a handle to the new RMprimitive upon success, or NULL upon failure. The current list of valid RMenum values for the primType parameter are: RM_LINES, RM_LINE_STRIP, RM_TRIANGLES, RM_TRIANGLE_STRIP, RM_SPHERES, RM_QUADMESH, RM_OCTMESH, RM_TEXT, RM_POINTS, RM_CONES, RM_CYLINDERS, RM_INDEXED_TEXT, RM_QUADS, RM_MARKERS2D, RM_BOX3D_WIRE, RM_CIRCLE2D, RM_ELLIPSE2D, RM_SPRITE, RM_TRIANGLE_FAN, RM_INDEXED_TFAN, RM_POLYS, RM_QUAD_STRIP, RM_INDEXED_QUADS, RM_INDEXED_TRIANGLES, RM_INDEXED_TRIANGLE_STRIP, RM_USERDEFINED_PRIM, RM_APP_DISPLAYLIST. Some of the procedural primitives are assigned default "model flag" attributes (see rmPrimitiveSetModelFlag). These are: RM_SPHERES: RM_SPHERES_32 produces a 32-faced sphere tesselation. RM_OCTMESH: RM_OCTMESH_1 produces a "full resolution" octmesh primitive. RM_CONES: RM_CONES_16 produces a cone consisting of 16 radial subdivisions. RM_CYLINDERS: RM_CYLINDERS_16 produces a cylinder consisting of 16 radial subdivisions. When the RMprimitive is created, it has no vertices, normals, etc. and it is not associated with any scene graph node. Use rmNodeAddPrimitive() to add an RMprimitive to a node. @dend * ---------------------------------------------------- */ RMprimitive * rmPrimitiveNew (RMenum primType) { void (*rfunc)OGLPRIMPARMLIST() = NULL; RMenum (*boxFunc)(RMprimitive *); RMprimitive *t; RMprimitiveDataBlob *b; extern RMenum RM_DEFAULT_PRIMITIVE_DISPLAY_LIST_ENABLE; t = private_rmPrimitiveNew(); if (t == NULL) { rmError("rmPrimitiveNew() error: primitive malloc failure."); return(NULL); } t->clientData = NULL; t->clientDataFreeFunc = NULL; t->p1 = NULL; t->bmin = t->bmax = NULL; t->flags1 = t->model_flag = 0; rmPrimitiveSetDisplayListEnable(t, RM_DEFAULT_PRIMITIVE_DISPLAY_LIST_ENABLE); b = (RMprimitiveDataBlob *)malloc(sizeof(RMprimitiveDataBlob) * RM_MAXBLOBS_PER_PRIMITIVE); memset(b, 0, sizeof(RMprimitiveDataBlob) * RM_MAXBLOBS_PER_PRIMITIVE); t->blobs = b; /* 2/2005 multitexture support */ t->multiTextureCoordBlobs = NULL; t->numMultiTextureCoordBlobs = 0; t->multiTextureCoordBlobsMask = 0; private_rmPrimitiveSetType(t, primType); switch (primType) { case RM_APP_DISPLAYLIST: rfunc = rmAppDisplayList; boxFunc = private_rmPrimitiveNullBoxFunc; break; case RM_LINES: rfunc = rmLinesDisjoint; boxFunc = private_rmPrimitiveComputeGenericBoundingBox; break; case RM_LINE_STRIP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmLineStrip; break; case RM_TRIANGLES: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmTrianglesDisjoint; break; case RM_TRIANGLE_STRIP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmTrianglesConnected; break; case RM_QUAD_STRIP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmQuadStrip; break; case RM_SPHERES: rmPrimitiveSetModelFlag(t, RM_SPHERES_32); boxFunc = private_rmPrimitiveComputeSpheresBoundingBox; rfunc = rmSpheres; break; case RM_QUADMESH: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmQuadmesh; break; case RM_OCTMESH: rmPrimitiveSetModelFlag(t, RM_OCTMESH_1); boxFunc = private_rmPrimitiveComputeOctmeshBoundingBox; rfunc = rmOctmesh; break; case RM_TEXT: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmText; break; case RM_POINTS: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmPoints; break; case RM_CONES: rmPrimitiveSetModelFlag(t, RM_CONES_16); boxFunc = private_rmPrimitiveComputeConesBoundingBox; rfunc = rmCones; break; case RM_CYLINDERS: rmPrimitiveSetModelFlag(t, RM_CYLINDERS_16); boxFunc = private_rmPrimitiveComputeCylindersBoundingBox; rfunc = rmCylinders; break; case RM_INDEXED_TEXT: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedText; break; case RM_QUADS: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmQuads; break; case RM_INDEXED_QUADS: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedQuads; break; case RM_INDEXED_QUAD_STRIP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedQuadStrip; break; case RM_INDEXED_TRIANGLES: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedTriangles; break; case RM_INDEXED_TRIANGLE_STRIP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedTriangleStrip; break; case RM_MARKERS2D: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmMarkers2D; break; case RM_BOX3D: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc= rmBox3d; break; case RM_BOX3D_WIRE: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmBox3dWire; break; case RM_CIRCLE2D: boxFunc = private_rmPrimitiveCompute2DCircleBoundingBox; rfunc = rmCircle2d; break; case RM_BOX2D: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmBox2d; break; case RM_ELLIPSE2D: boxFunc = private_rmPrimitiveCompute2DEllipseBoundingBox; rfunc= rmEllipse2d; break; case RM_SPRITE: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmSprite; break; case RM_BITMAP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmBitmap; break; case RM_INDEXED_BITMAP: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmIndexedBitmap; break; case RM_TRIANGLE_FAN: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; rfunc = rmTriangleFan; break; case RM_INDEXED_TFAN: rfunc = rmIndexedTriangleFan; boxFunc = private_rmPrimitiveComputeGenericBoundingBox; break; case RM_POLYS: rfunc = rmPolys; boxFunc = private_rmPrimitiveComputeGenericBoundingBox; break; default: boxFunc = private_rmPrimitiveComputeGenericBoundingBox; break; } t->primitiveComputeBoundingBoxFunc = boxFunc; rmPrimitiveSetRenderFunc(t, rfunc); return(t); } /* * ---------------------------------------------------- * @Name rmPrimitiveDelete @pstart void rmPrimitiveDelete (RMprimitive *toDelete) @pend @astart RMprimitive *toDelete - a handle to an RMprimitive to delete (modified). @aend @dstart Use this routine to release resources associated with an RMprimitive. If shared data management was specified (when rmPrimitiveSetVertex3D was called, for example), those application callback functions will be invoked to free large-payload memory. @dend * ---------------------------------------------------- */ void rmPrimitiveDelete (RMprimitive *p) { /* ignore NULL prims */ if (p == NULL) return; private_rmPrimitiveDelete(p); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetRenderFunc @pstart RMenum rmPrimitiveSetRenderFunc (RMprimitive *toModify, void (*drawFunc) OGLPRIMPARMLIST() ) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). void (*drawFunc) OGLPRIMPARMLIST() - a callback invoked to draw the primitive (input). @aend @dstart This routine assigns the draw callback to an RMprimitive. When an RMprimitive is created with rmPrimitiveNew(), the draw callback is automatically assigned except when rmPrimitiveNew is invoked with RM_USERDEFINED_PRIM. Applications that want to assign a draw function to an RMprimitive should use this function. This routine returns RM_CHILL upon success, or RM_WHACKED upon failure. The draw callback contains raw OpenGL code that performs the rendering. The parameter list to the draw callback is represented with the macro OGLPRIMPARMLIST(). At this time (June 2002), that macro expands to: (RMprimitive *primToDraw, RMnode *owningNode, RMstate *currentRenderState, RMpipe *renderPipe, RMstateCache *internalStateCache) @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetRenderFunc (RMprimitive *p, void (*renderfunc)OGLPRIMPARMLIST() ) { if (RM_ASSERT(p, "rmPrimitiveSetRenderFunc() error: the input RMprimitive pointer is NULL.") == RM_WHACKED) return(RM_WHACKED); p->renderfunc = renderfunc; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPrimitiveGetRenderFunc @pstart void * rmPrimitiveGetRenderFunc (const RMprimitive *toQuery) @pend @astart const RMprimitive *toQuery - a handle to the RMprimitive object to query (input). @aend @dstart Returns to the caller the handle to the draw callback associated with the input RMprimitive. @dend * ---------------------------------------------------- */ void * rmPrimitiveGetRenderFunc (const RMprimitive *p) { if (RM_ASSERT(p, "rmPrimitiveGetRenderFunc() error: the input RMprimitive is NULL") == RM_WHACKED) return(NULL); return((void *)(p->renderfunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetModelFlag @pstart RMenum rmPrimitiveSetModelFlag (RMprimitive *toModify, int newVal) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int newVal - an integer value specifying a new RMprimitive model flag (see below for more info) (input). @aend @dstart Use this routine to modify the "primitive model flag" for an RMprimitive. Returns RM_CHILL upon success or RM_WHACKED upon failure. The RMprimitive model flag is used to control the rendering resolution of primitives. Only a few RMprimitive types are eligible for this kind of resolution control: RM_SPHERES, RM_CONES, RM_CYLINDERS and RM_OCTMESH. RM_SPHERES model flags: RM_SPHERES_8, RM_SPHERES_32, RM_SPHERES_128, and RM_SPHERES_512. These flags affect the tesselation resolution used when rendering spheres. RM_SPHERES_8 produces an octahedron, and each of the other model flags is a midpoint-subdivision refinement refinement of the octahedron. The RM sphere tesselation model is superior to the one in GLU for two reasons. First, the faces of the tesselation are all equal in area. Second, the faces of the tesselation are triangles, so there are no non-planar faces; gluSphere tesselates a sphere into non-planar quads. Internally, RM builds OpenGL display lists for each sphere tesselation then invokes that display list at render time, positioned and scaled to the specifications of the RMprimitive. RM_CONES and RM_CYLINDERS use the following set: RM_CONES_4, RM_CONES_8, RM_CONES_12, RM_CONES_16, RM_CONES_32, RM_CONES_64, and RM_CONES_128; RM_CYLINDERS_4, RM_CYLINDERS_8, RM_CYLINDERS_12, RM_CYLINDERS_16, RM_CYLINDERS_32, RM_CYLINDERS_64, and RM_CYLINDERS_128. The tesselation of cones and cylinders is nearly identical: the ideal circle (at the base of the cone, and at each end of the cylinder) is discretized with 4, 8, 12, 16, 32, 64 or 128 points, respectively. In the case of cones, a single triangle joints each adjacent pair of sample points with the cone apex, while a cylinder uses a pair of triangles to join each pair of sample points between ends of the cylinder. Internally, RM builds OpenGL display lists (t-fans for cones and t-strips for cylinders). RM_OCTMESH: RM_OCTMESH_1, RM_OCTMESH_2, RM_OCTMESH_4, RM_OCTMESH_8, RM_OCTMESH_16. The octmesh primitive model flag can be considered a "divide by" constant. In other words, if the base resolution of the octmesh grid is 64x64x64 and RM_OCTMESH_2 is used, then the resolution of the polygonalized model will be 32x32x32, but will be fill the space (volume) specified by the octmesh grid. This model flag can accelerate rendering of volume data on pixel-fill limited systems. Note: the model flag values are not RMenum's - they are in fact indices into internal tables. Please don't change the #defines for the the model flags. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetModelFlag (RMprimitive *p, int newval) { if (RM_ASSERT(p, "rmPrimitiveSetModelFlag() error: the input RMprimitive is NULL") == RM_WHACKED) return(RM_WHACKED); p->model_flag = newval; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPrimitiveGetModelFlag @pstart int rmPrimitiveGetModelFlag (const RMprimitive *toQuery) @pend @astart const RMprimitive *toQuery - a handle to an RMprimitive to query (input). @aend @dstart Returns to the caller the current primitive model flag associated with the RMprimitive object. RM_WHACKED is returned for RMprimitives that don't know about model flags. @dend * ---------------------------------------------------- */ int rmPrimitiveGetModelFlag (const RMprimitive *p) { int rstat; if (RM_ASSERT(p, "rmPrimitiveGetModelFlag() error: the input RMprimitive is NULL. \n") == RM_WHACKED) return(RM_WHACKED); switch(private_rmPrimitiveGetType(p)) { case RM_LINES: case RM_LINE_STRIP: case RM_TRIANGLES: case RM_TRIANGLE_STRIP: case RM_TRIANGLE_FAN: case RM_QUADMESH: case RM_POINTS: case RM_BOX3D: case RM_BOX3D_WIRE: case RM_TEXT: case RM_INDEXED_TEXT: case RM_QUADS: case RM_MARKERS2D: case RM_BOX2D: case RM_SPRITE: case RM_BITMAP: case RM_INDEXED_BITMAP: case RM_POLYS: case RM_QUAD_STRIP: case RM_INDEXED_TFAN: case RM_INDEXED_QUADS: case RM_INDEXED_QUAD_STRIP: case RM_INDEXED_TRIANGLES: case RM_INDEXED_TRIANGLE_STRIP: case RM_USERDEFINED_PRIM: rstat = (int)RM_WHACKED; break; case RM_ELLIPSE2D: case RM_CIRCLE2D: case RM_OCTMESH: case RM_CONES: case RM_CYLINDERS: case RM_SPHERES: rstat = private_rmPrimitiveGetModelFlag(p); break; default: /* bogus prim type */ rstat = (int)RM_WHACKED; break; } return(rstat); } /* * ---------------------------------------------------- * @Name rmPrimitiveComputeBoundingBox @pstart RMenum rmPrimitiveComputeBoundingBox (RMprimitive *toModify) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). @aend @dstart Use this routine to automatically compute an RMprimitive's bounding box. This routine returns RM_CHILL upon success, or RM_WHACKED upon failure. Failure will occur if the input RMprimitive is NULL. See the description of rmPrimitiveSetBoundingBox for more details about when an RMprimitive's bounding box should be set, or computed, as well as discussion about the relationship between the RMprimitive and RMnode bounding boxes. Use rmPrimitiveGetBoundingBox() to obtain an RMprimitive's bounding box. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveComputeBoundingBox(RMprimitive *p) { if (RM_ASSERT(p, "rmPrimitiveComputeBoundingBox() error: the input RMprimitive is NULL.") == RM_WHACKED) return(RM_WHACKED); if (p->primitiveComputeBoundingBoxFunc == NULL) return RM_WHACKED; return ((*p->primitiveComputeBoundingBoxFunc)(p)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetBoundingBox @pstart RMenum rmPrimitiveSetBoundingBox (RMprimitive *toModify, const RMvertex3D *bmin, const RMvertex3D *bmax) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). const RMvertex3D *bmin, *bmax - handles to RMvertex3D's. @aend @dstart Use this routine to explicitly set the bounding box at an RMprimitive. The bounding box of the RMprimitive toModify will be set to the RMvertex3D values specified in the input parameters bmin and bmax. Returns RM_CHILL upon success, or RM_WHACKED upon failure. If bmin or bmax are NULL, those portions of the RMprimitive's bounding box are removed, leaving the bounding box in an undefined and uninitialized state. The RMprimitive's bounding box is automatically computed by RM in the following circumstances: 1. list them The relationship between the RMprimitive and RMnode bounding box is ... @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetBoundingBox(RMprimitive *p, const RMvertex3D *bmin, const RMvertex3D *bmax) { if (RM_ASSERT(p, "rmPrimitiveSetBoundingBox() error: the input RMprimitive is NULL.") == RM_WHACKED) return(RM_WHACKED); if (p->bmin != NULL) free((void *)(p->bmin)); if (bmin != NULL) { p->bmin = rmVertex3DNew(1); *(p->bmin) = *bmin; } if (p->bmax != NULL) free((void *)(p->bmax)); if (bmax != NULL) { p->bmax = rmVertex3DNew(1); *(p->bmax) = *bmax; } return RM_CHILL; } /* * ---------------------------------------------------- * @Name rmPrimitiveGetBoundingBox @pstart RMenum rmPrimitiveGetBoundingBox (const RMprimitive *toQuery, RMvertex3D *bminReturn, RMvertex3D *bmaxReturn) @pend @astart const RMprimitive *toQuery - a handle to an RMprimitive (input). RMvertex3D *bminReturn, *bmaxReturn; @aend @dstart Use this routine to obtain an RMprimitive's bounding box. Upon success, RM_CHILL is returned, and the bounding box minimum and maximum are copied into the application-supplied RMvertex3D parameters. If either of the RMprimitive's minimum or maximum bounding box parameters are NULL (i.e., they have not been initialized), this routine will return RM_WHACKED. The application can request one, or both, of the bounding box minimum or maximum values. In other words, the application may specify NULL for either of the minimum or maximum bounding box return parameters. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveGetBoundingBox(const RMprimitive *p, RMvertex3D *bmin, RMvertex3D *bmax) { if (RM_ASSERT(p, "rmPrimitiveGetBoundingBox() error: the input RMprimitive is NULL.") == RM_WHACKED) return(RM_WHACKED); if (p->bmin == NULL) return RM_WHACKED; if (bmin != NULL) *bmin = *(p->bmin); if (p->bmax == NULL) return RM_WHACKED; if (bmax != NULL) *bmax = *(p->bmax); return RM_CHILL; } /* * ---------------------------------------------------- * @Name rmPrimitiveGetType @pstart RMenum rmPrimitiveGetType (const RMprimitive *toQuery) @pend @astart const RMprimitive *toQuery - a handle to an RMprimitive (input). @aend @dstart Returns to the caller the input RMprimitive's "type" RMenum attribute. RM_WHACKED is returned if the input RMprimitive is NULL. For a list of RMprimitive type enums, please see rmPrimitiveNew(). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveGetType (const RMprimitive *t) { if (RM_ASSERT(t, "rmPrimitiveGetType() error: the input RMprimitive is NULL.") == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveGetType(t)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetClientData @pstart RMenum rmPrimitiveSetClientData (RMprimitive *toModify, void *clientData, void (*cdFreeFunc)(RMprimitive *,void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). void *clientData - a handle (input). void (*cdFreeFunc)(RMprimitive *, void *) - a handle to an application callback (input). @aend @dstart This routine stores a memory handle (pointer) in an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. RM basically ignores this handle; it's use, management and so forth is entirely under control of the application. This is a simple mechanism for applications to store a memory handle in an RMprimitive for subsequent use in an application-specific manner. Client data may be stored in both RMprimitives and RMnodes (rmNodeSetClientData). The "client data" handle may be later accessed using rmPrimitiveGetClientData. The callback function will be invoked when the RMprimitive is deleted. The callback takes two parameters, a handle to the RMprimitive containing the client data handle, and the client data handle itself. The callback is provided so that applications may delete the data referenced by the client data handle stored in the RMprimitive. When the input client data handle is NULL, the old handle value is effectively overwritten. Any memory pointed to by the old client data handle will be lost (a potential memory leak). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetClientData (RMprimitive *p, void *cd, void (*cd_free_func)(RMprimitive *,void *)) { if (RM_ASSERT(p, "rmPrimitiveSetClientData() error: the input RMprimitive is NULL") == RM_WHACKED) return(RM_WHACKED); p->clientData = cd; p->clientDataFreeFunc = cd_free_func; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPrimitiveGetClientData @pstart void * rmPrimitiveGetClientData (const RMprimitive *toQuery) @pend @astart const RMprimitive *toQuery - a handle to an RMprimitive (input). @aend @dstart Use this routine to obtain the client data handle stored in an RMprimitive. @dend * ---------------------------------------------------- */ void * rmPrimitiveGetClientData (const RMprimitive *p) { if (RM_ASSERT(p, "rmPrimitiveGetClientData() error: the input RMprimitive is NULL") == RM_WHACKED) return((void *)NULL); return(p->clientData); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetVertex2D @pstart RMenum rmPrimitiveSetVertex2D (RMprimitive *toModify, int nVertices, RMvertex2D *vertexData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nVertices - an integer value, specifies the number of vertices that will be assigned to the RMprimitive (input). RMvertex2D *vertexData - a handle to a flat array of RMvertex2D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetVertex2D is one of a family of routines used to assign data to RMprimitives. This routine assigns raw 2D vertex data to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw vertex data provided in "vertexData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMvertex2D data, but instead will simply copy the handle "vertexData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMvertex2D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMvertex2D is assigned (more precisely, if new vertex data is assigned, regardless of whether or not it is 3D or 2D). The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get vertex" routine. Primitive vertex data should be considered write-only by the application. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetVertex2D (RMprimitive *p, int n, RMvertex2D *v, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)v, copy_flag, freefunc, "rmPrimitiveSetVertex2D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_2DVERTICES, n, sizeof(RMvertex2D), (void *)v, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetVertex3D @pstart RMenum rmPrimitiveSetVertex3D (RMprimitive *toModify, int nVertices, RMvertex3D *vertexData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nVertices - an integer value, specifies the number of vertices that will be assigned to the RMprimitive (input). RMvertex3D *vertexData - a handle to a flat array of RMvertex3D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetVertex3D is one of a family of routines used to assign data to RMprimitives. This routine assigns raw 3D vertex data to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw vertex data provided in "vertexData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMvertex3D data, but instead will simply copy the handle "vertexData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMvertex3D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMvertex3D is assigned (more precisely, if new vertex data is assigned, regardless of whether or not it is 3D or 2D). The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get vertex" routine. Primitive vertex data should be considered write-only by the application. NOTE: some compilers enforce 8-byte alignment/padding of C structures. Since the RMvertex3D object consists of 3 floats, some compilers will pad memory to produce 8-byte alignment. The underlying RM data management infrastructure accomodates this added complexity. However, on such systems, callers that pass in a flat array of floats cast to RMvertex3D * should be aware that the data is considered to be a flat array of RMvertex3D objects inside this routine, not a flat array of floats. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetVertex3D (RMprimitive *p, int n, RMvertex3D *v, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)v, copy_flag, freefunc, "rmPrimitiveSetVertex3D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_3DVERTICES, n, sizeof(RMvertex3D), (void *)v, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetColor3D @pstart RMenum rmPrimitiveSetColor3D (RMprimitive *toModify, int nColors, RMcolor3D *colorData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nColors - an integer value, specifies the number of 3-component colors that will be assigned to the RMprimitive (input). RMcolor3D *vertexData - a handle to a flat array of RMcolor3D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetColor3D is one of a family of routines used to assign data to RMprimitives. This routine assigns raw 3-component color data to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw color data provided in "colorData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMcolor3D data, but instead will simply copy the handle "colorData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMcolor3D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMcolor3D is assigned (more precisely, if new color data is assigned, regardless of whether or not it is 3D or 4D). The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get colors" routine. Primitive color data should be considered write-only by the application. NOTE: some compilers enforce 8-byte alignment/padding of C structures. Since the RMcolor3D object consists of 3 floats, some compilers will pad memory to produce 8-byte alignment. The underlying RM data management infrastructure accomodates this added complexity. However, on such systems, callers that pass in a flat array of floats cast to RMcolor3D * should be aware that the data is considered to be a flat array of RMcolor3D objects inside this routine, not a flat array of floats. In RM, 3-component color data is RGB. 4-component colors are RGBA. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetColor3D (RMprimitive *p, int n, RMcolor3D *v, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)v, copy_flag, freefunc, "rmPrimitiveSetColor3D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_3COLORS, n, sizeof(RMvertex3D), (void *)v, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetColor4D @pstart RMenum rmPrimitiveSetColor4D (RMprimitive *toModify, int nColors, RMcolor4D *colorData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nColors - an integer value, specifies the number of 3-component colors that will be assigned to the RMprimitive (input). RMvertex4D *vertexData - a handle to a flat array of RMcolor4D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetColor4D is one of a family of routines used to assign data to RMprimitives. This routine assigns raw 4-component color data to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw color data provided in "colorData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMcolor4D data, but instead will simply copy the handle "colorData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMcolor4D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMcolor4D is assigned (more precisely, if new color data is assigned, regardless of whether or not it is 3D or 4D). The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get colors" routine. Primitive color data should be considered write-only by the application. In RM, 3-component color data is RGB. 4-component colors are RGBA. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetColor4D (RMprimitive *p, int n, RMcolor4D *v, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)v, copy_flag, freefunc, "rmPrimitiveSetColor4D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_4COLORS, n, sizeof(RMvertex4D), (void *)v, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetRadii @pstart RMenum rmPrimitiveSetRadii (RMprimitive *toModify, int nRadii, float *radii, RMenum copyEnum, void (*freeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nRadii - an integer values specifying the number of input radius values, the length of the radii[] array (input). float *radii - a flat array of floating point values (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*freeFunc)(void *) - a handle to an application callback, required when copyEnum is RM_DONT_COPY_DATA (input). @aend @dstart Use this routine to assign radius values to RMprimitives. Radius values are used by sphere, cone and cylinder primitives. Returns RM_CHILL upon success, or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw radius data provided in "radii." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the radius data, but instead will simply copy the handle "colorData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the radius data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new radius is assigned. The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get radii" routine. Primitive radius data should be considered write-only by the application. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetRadii (RMprimitive *p, int n, float *r, RMenum copy_flag, void (*freefunc)(void *)) { if (( private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetRadii")) ==RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_RADII, n, sizeof(float), (void *)r, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetNormal3D @pstart RMenum rmPrimitiveSetNormal3D (RMprimitive *toModify, int nNormals, RMvertex3D *normalsData, RMenum copyEnum, void (*freeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive to modify (modified). int nNormals - an integer value specifying the number of input normals in the normals[] array (input). RMvertex3D *normalsData - a handle to an RMvertex3D array (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*freeFunc)(void *) - a handle to an application callback, required when copyEnum is RM_DONT_COPY_DATA (input). @aend @dstart This routine is used to assign a flat array of normals to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. In most instances, per-vertex normals are required. Quads and disjoint triangle primitives allow per-face normals. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw normals data provided in "normalsData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMvertex3D data, but instead will simply copy the handle "normalsData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMvertex3D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMvertex3D is assigned. The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get normals" routine. Primitive normal data should be considered write-only by the application. NOTE: some compilers enforce 8-byte alignment/padding of C structures. Since the RMvertex3D object consists of 3 floats, some compilers will pad memory to produce 8-byte alignment. The underlying RM data management infrastructure accomodates this added complexity. However, on such systems, callers that pass in a flat array of floats cast to RMvertex3D * should be aware that the data is considered to be a flat array of RMvertex3D objects inside this routine, not a flat array of floats. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetNormal3D (RMprimitive *p, int n, RMvertex3D *r, RMenum copy_flag, void (*freefunc)(void *)) { if (( private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetNormal3D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_NORMALS, n, sizeof(RMvertex3D), (void *)r, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetTexcoord1D @pstart RMenum rmPrimitiveSetTexcoord1D (RMprimitive *toModify, int nTexCoords, float *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexCoords - an integer value, specifies the number of 1D texture coordinates that will be assigned to the RMprimitive (input). float *texCoordData - a handle to a flat array of float (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetTexcoord1D is one of a family of routines used to assign data to RMprimitives. This routine assigns 1D texture coordinates to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw vertex data provided in "texCoordData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the float data, but instead will simply copy the handle "texCoordData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the texture coordinate data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new texture coordinate data is assigned. The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get texture coordinate" routine. Primitive vertex data should be considered write-only by the application. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetTexcoord1D (RMprimitive *p, int n, float *r, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetTexcoord1D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_1DTCOORDS, n, sizeof(float), (void *)r, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetTexcoord2D @pstart RMenum rmPrimitiveSetTexcoord2D (RMprimitive *toModify, int nTexCoords, RMvertex2D *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexCoords - an integer value, specifies the number of 2D texture coordinates that will be assigned to the RMprimitive (input). RMvertex2D *texCoordData - a handle to a flat array of RMvertex2D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetTexcoord2D is one of a family of routines used to assign data to RMprimitives. This routine assigns 2D texture coordinates to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw vertex data provided in "texCoordData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMvertex2D data, but instead will simply copy the handle "texCoordData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the texture coordinate data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new texture coordinate data is assigned. The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get texture coordinate" routine. Primitive vertex data should be considered write-only by the application. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetTexcoord2D (RMprimitive *p, int n, RMvertex2D *r, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetTexcoord2D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_2DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetTexcoord3D @pstart RMenum rmPrimitiveSetTexcoord3D (RMprimitive *toModify, int nTexcoords, RMvertex3D *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexcoords - an integer value, specifies the number of texture coordinates that will be assigned to the RMprimitive (input). RMvertex3D *texCoordData - a handle to a flat array of RMvertex3D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). @aend @dstart rmPrimitiveSetTexcoord3D is one of a family of routines used to assign data to RMprimitives. This routine assigns raw 3D texture coordinate data to an RMprimitive, returning RM_CHILL upon success or RM_WHACKED upon failure. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw texture coordinate data provided in "texCoordData." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the RMvertex3D data, but instead will simply copy the handle "texCoordData" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the RMvertex3D data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new RMvertex3D is assigned (more precisely, if new texture coordinate data is assigned, regardless of whether or not it is 3D or 2D). The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. There is no corresponding "get texture coordinate" routine. Primitive vertex data should be considered write-only by the application. NOTE: some compilers enforce 8-byte alignment/padding of C structures. Since the RMvertex3D object consists of 3 floats, some compilers will pad memory to produce 8-byte alignment. The underlying RM data management infrastructure accomodates this added complexity. However, on such systems, callers that pass in a flat array of floats cast to RMvertex3D * should be aware that the data is considered to be a flat array of RMvertex3D objects inside this routine, not a flat array of floats. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetTexcoord3D (RMprimitive *p, int n, RMvertex3D *r, RMenum copy_flag, void (*freefunc)(void *)) { if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetTexcoord3D")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_3DTCOORDS, n, sizeof(RMvertex3D), (void *)r, copy_flag, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetMultiTexcoord1D @pstart RMenum rmPrimitiveSetMultiTexcoord1D (RMprimitive *toModify, int nTexCoords, float *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *), int textureUnit) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexCoords - an integer value, specifies the number of 2D texture coordinates that will be assigned to the RMprimitive (input). float *texCoordData - a handle to a flat array of floats (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). int textureUnit - an integer value specifying with which multitexturing unit the texture coordinates will be used. Valid values are in the range zero through RM_MAX_MULTITEXTURES-1. @aend @dstart rmPrimitiveSetMultiTexcoord1D is nearly identical in function and return values to rmPrimitiveSetTexcoord1D. The difference is the ability to assign texture coordinates to a specific texturing unit in a multitexturing environment. Note that while valid values for the input textureUnit parameter are in the range zero through RM_MAX_MULTITEXTURES-1, this routine performs no error checking to verify that the textureUnit input value is valid for a particular OpenGL implementation. The constant RM_MAX_MULTITEXTURES is independent of the actual number of texture units supported by an OpenGL implementation. When multitexturing is supported (use the routine rmPipeGetNumMultitextureUnits to check for the availability on a given OpenGL implementation), the minimum number of texture units to be supported is two; our Quadro4 cards have four texture units; Mesa provides eight texture units. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetMultiTexcoord1D (RMprimitive *p, int n, float *r, RMenum copy_flag, void (*freefunc)(void *), int textureUnit) { RMenum stat; if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetMultiTexcoord1D")) == RM_WHACKED) return(RM_WHACKED); stat = private_rmPrimitiveSetMultiTexcoordBlob(p, RM_PRIMITIVE_MULTI_1DTCOORDS, n, sizeof(float), (void *)r, copy_flag, freefunc, textureUnit); return stat; /* return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_MULTI_2DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc, textureUnit)); */ } /* * ---------------------------------------------------- * @Name rmPrimitiveSetMultiTexcoord2D @pstart RMenum rmPrimitiveSetMultiTexcoord2D (RMprimitive *toModify, int nTexCoords, RMvertex2D *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *), int textureUnit) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexCoords - an integer value, specifies the number of 2D texture coordinates that will be assigned to the RMprimitive (input). RMvertex2D *texCoordData - a handle to a flat array of RMvertex2D objects (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). int textureUnit - an integer value specifying with which multitexturing unit the texture coordinates will be used. Valid values are in the range zero through RM_MAX_MULTITEXTURES-1. @aend @dstart rmPrimitiveSetMultiTexcoord2D is nearly identical in function and return values to rmPrimitiveSetTexcoord2D. The difference is the ability to assign texture coordinates to a specific texturing unit in a multitexturing environment. Note that while valid values for the input textureUnit parameter are in the range zero through RM_MAX_MULTITEXTURES-1, this routine performs no error checking to verify that the textureUnit input value is valid for a particular OpenGL implementation. The constant RM_MAX_MULTITEXTURES is independent of the actual number of texture units supported by an OpenGL implementation. When multitexturing is supported (use the routine rmPipeGetNumMultitextureUnits to check for the availability on a given OpenGL implementation), the minimum number of texture units to be supported is two; our Quadro4 cards have four texture units; Mesa provides eight texture units. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetMultiTexcoord2D (RMprimitive *p, int n, RMvertex2D *r, RMenum copy_flag, void (*freefunc)(void *), int textureUnit) { RMenum stat; if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetMultiTexcoord2D")) == RM_WHACKED) return(RM_WHACKED); stat = private_rmPrimitiveSetMultiTexcoordBlob(p, RM_PRIMITIVE_MULTI_2DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc, textureUnit); return stat; /* return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_MULTI_2DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc, textureUnit)); */ } /* * ---------------------------------------------------- * @Name rmPrimitiveSetMultiTexcoord3D @pstart RMenum rmPrimitiveSetMultiTexcoord3D (RMprimitive *toModify, int nTexCoords, RMvertex3D *texCoordData, RMenum copyEnum, void (*appFreeFunc)(void *), int textureUnit) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nTexCoords - an integer value, specifies the number of 2D texture coordinates that will be assigned to the RMprimitive (input). RMvertex3D *texCoordData - a handle to a flat array of RMvertex3D's. (input) RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback. When "copyEnum" is RM_DONT_COPY_DATA, the application must provide a callback used to release memory when the RMprimitive is delete (input). int textureUnit - an integer value specifying with which multitexturing unit the texture coordinates will be used. Valid values are in the range zero through RM_MAX_MULTITEXTURES-1. @aend @dstart rmPrimitiveSetMultiTexcoord3D is nearly identical in function and return values to rmPrimitiveSetTexcoord3D. The difference is the ability to assign texture coordinates to a specific texturing unit in a multitexturing environment. Note that while valid values for the input textureUnit parameter are in the range zero through RM_MAX_MULTITEXTURES-1, this routine performs no error checking to verify that the textureUnit input value is valid for a particular OpenGL implementation. The constant RM_MAX_MULTITEXTURES is independent of the actual number of texture units supported by an OpenGL implementation. When multitexturing is supported (use the routine rmPipeGetNumMultitextureUnits to check for the availability on a given OpenGL implementation), the minimum number of texture units to be supported is two; our Quadro4 cards have four texture units; Mesa provides eight texture units. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetMultiTexcoord3D (RMprimitive *p, int n, RMvertex3D *r, RMenum copy_flag, void (*freefunc)(void *), int textureUnit) { RMenum stat; if ((private_rmPrimSetAssert(p, n, (void *)r, copy_flag, freefunc, "rmPrimitiveSetMultiTexcoord3D")) == RM_WHACKED) return(RM_WHACKED); stat = private_rmPrimitiveSetMultiTexcoordBlob(p, RM_PRIMITIVE_MULTI_3DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc, textureUnit); return stat; /* return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_MULTI_2DTCOORDS, n, sizeof(RMvertex2D), (void *)r, copy_flag, freefunc, textureUnit)); */ } /* * ---------------------------------------------------- * @Name rmPrimitiveSetIndices @pstart RMenum rmPrimitiveSetIndices (RMprimitive *toModify, int numIndices, int *indicesArray, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int numIndices - an integer value specifying the length of the indicesArray[] array (input). int *indicesArray - a flat array of integer indices (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback, required when copyEnum is RM_DONT_COPY_DATA (input). @aend @dstart Use this routine to set "index values" in an RMprimitive. Returns RM_CHILL upon success, or RM_WHACKED upon failure. Some RMprimitive objects allow the use of "indexed" vertices. At this time (Feb 2004), these include RM_INDEXED_TFAN, RM_INDEXED_TEXT, and RM_INDEXED_BITMAP, RM_INDEXED_QUADS, RM_INDEXED_TRIANGLES, and RM_INDEXED_TRIANGLE_STRIP. (Plans are underway to grow the number of indexed primitives). In non-indexed primitives, the number of objects drawn on screen is a function of the number of vertices in the RMprimitive and the primitive type itself. For example, in RM_TRIANGLES primitives (disjoint triangles), the number of triangles that are drawn is the number of vertices divided by 3. For RM_INDEXED_TRIANGLES, the number of triangles that will be drawn is instead the number of indices divided by 3. For RM_INDEXED_QUADS, the number of quads drawn is the number of indices divided by 4. For RM_INDEXED_TRIANGLE_STRIP, the number of triangles draw is the number of indices-2 (e.g, four indices produces 2 triangles). Each entry in the index array is an index into another array. Index values in the RM_INDEXED_TEXT are offsets into an array of text strings. Index values in RM_INDEXED_BITMAP primitives are offsets into an array of RMbitmap objects. Index values in RM_INDEXED_TFAN are offsets into a vertex array. When "copyEnum" is set to RM_COPY_DATA, RM will make a copy of the raw index data provided in "indexArray." When "copyEnum" is set to RM_DONT_COPY_DATA, RM will not make a copy of the index data, but instead will simply copy the handle "indexArray" into the RMprimitive, and refer to the caller-supplied memory directly in later operations. When RM_DONT_COPY_DATA is specified, applications must supply a callback function that will be invoked when the index data in an RMprimitive is deleted. Such deletion occurs when the RMprimitive itself is deleted, the RMnode containing the RMprimitive is deleted (if the RMprimitive was assigned to an RMnode with rmNodeAddChild()), or if new index is assigned. The application callback takes a single parameter: a handle to the underlying data array that is managed by the application. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetIndices (RMprimitive *t, int npts, int *indices, RMenum copy_enum, void (*freefunc)(void *)) { if (private_rmPrimSetAssert(t, npts, (void *)indices, copy_enum, freefunc, "rmPrimitiveSetIndices") == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem((RMprimitive *)t, RM_PRIMITIVE_INDICES, npts, sizeof(int), (void *)indices, copy_enum, freefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetSprites @pstart RMenum rmPrimitiveSetSprites (RMprimitive *toModify, int nSprites, RMimage **spriteArray) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nSprites - an integer value specifying the number of sprites that will be assigned to an RM_SPRITE primitive (input). RMimage **spriteArray - an array of RMimage handles (input). @aend @dstart RM_SPRITE primitives are image-based primitives consisting of vertex and image data. rmPrimitiveSetSprites is used to assign the image data to the RM_SPRITE primitive. Shared data management of the raw pixel data is specified as an interface to the RMimage object, hence specification of RM_COPY_DATA/RM_DONT_COPY_DATA is not necessary at the RMprimitive level for RM_SPRITES. Inside this routine, all the images in the spriteArray are duplicated with rmImageDup(). Please refer to rmImageDup() for more details about shared data management of pixel data in RMimage objects. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetSprites (RMprimitive *p, int nsprites, RMimage **sprite_array) { if ((private_rmPrimSetAssert(p, nsprites, (void *)sprite_array, RM_COPY_DATA,NULL, "rmPrimitiveSetSprites")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_SPRITES, nsprites, sizeof(RMimage *), sprite_array, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetBitmaps @pstart RMenum rmPrimitiveSetBitmaps (RMprimitive *toModify, int nBitmaps, RMbitmap **bmapArray) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nBitmaps - an integer value specifying the number of RMbitmap objects to assign to an RMprimitive (input). RMbitmap **bmapArray - an array of RMbitmap handles (input). @aend @dstart Primitives of the type RM_BITMAP or RM_INDEXED_BITMAP consist of vertex data and RMbitmap objects (the indexed form also takes indices). Use this routine to assign RMbitmap data to the RMprimitive. It returns RM_CHILL upon success, or RM_WHACKED upon failure. There is no shared data management of RMbitmap data since these objects are small. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetBitmaps (RMprimitive *p, int nbitmaps, RMbitmap **bmaplist) { if ((private_rmPrimSetAssert(p, nbitmaps, (void *)bmaplist, RM_COPY_DATA, NULL, "rmPrimitiveSetBitmaps")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_BITMAPS, nbitmaps, sizeof(RMbitmap), (void *)bmaplist, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetQmeshDims @pstart RMenum rmPrimitiveSetQmeshDims (RMprimitive *toModify, int uSize, int vSize) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int uSize, vSize - integer values specifying the dimensions of a lattice defining a quadmesh (input). @aend @dstart A quadmesh primitive may be considered as a two-dimensional lattice of points. The points themselves may be specified with two or three dimensional coordinate values. This routine is used to specify the number of points in each of the two dimensions of the lattice, and returns RM_CHILL upon success or RM_WHACKED upon failure. Quadmesh primitives require, in addition to a grid size set with rmPrimitiveSetQmeshDims, vertex data set with rmPrimitiveSetVertex3D or rmPrimitiveSetVertex2D. Colors, normals and texture coordinates are all optional. The routines rmPrimitiveSetQmeshDims and rmPrimitiveSetVertex3D/2D may be called in any order, but both must be called before a quadmesh primitive is rendered. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetQmeshDims (RMprimitive *p, int usize, int vsize) { int dims[2]; if (RM_ASSERT(p, "rmPrimitiveSetQmeshDims() error: the input RMprimitive is NULL. ") == RM_WHACKED) return(RM_WHACKED); dims[0] = usize; dims[1] = vsize; return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_QMESHDIMS, 2, sizeof(int), (void *)dims, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetOmeshDims @pstart RMenum rmPrimitiveSetOmeshDims (RMprimitive *toModify, int isize, int jsize, int ksize) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int isize, jsize, ksize - integer values specifying the number of points in a three dimensional hexahedral lattice (input). @aend @dstart The OpenRM Octmesh primitive is logically a three-dimensional, hexahedral lattice. Use this routine to set the dimensions of the lattice. In most cases, "isize" will correspond to the x-axis, "jsize" to the y-axis and "ksize" to the z-axis. In OpenRM, direct volume rendering is achieved with a combination of an octmesh primitive and a 3D texture. The 3D texture provides color and opacity information, while the octmesh primitive specifies the geometric placement and resolution of the underlying 3D lattice. The octmesh primitive is procedural in that texture coordinates are automatically generated at render time. Use rmPrimitiveSetModelFlag to coarsen or refine render-time sampling of the underlying Octmesh grid. (Jan 2000) - use rmPrimitiveSetOmeshMinMaxGrid() to specify the corners of the 3D lattice. Use of rmPrimitiveSetVertex3D on octmesh primitives is not yet implemented. Note: the dimensions of the Octmesh lattice must be specified prior (using this routine, rmPrimitiveSetOmeshDims) prior to the specification of the corners of the lattice (using rmPrimitiveSetOmeshMinMaxGrid). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetOmeshDims (RMprimitive *p, int isize, int jsize, int ksize) { int dims[3]; if (RM_ASSERT(p, "rmPrimitiveSetOmeshDims() error: the input RMprimitive is NULL. ") == RM_WHACKED) return(RM_WHACKED); dims[0] = isize; dims[1] = jsize; dims[2] = ksize; return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_OMESHDIMS, 3, sizeof(int), (void *)dims, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetOmeshMinMaxGrid @pstart RMenum rmPrimitiveSetOmeshMinMaxGrid (RMprimitive *toModify, const RMvertex3D *gridMin, const RMvertex3D *gridMax) @pend @astart RMprimitive *p - a handle to an RMprimitive (modified). const RMvertex3D *gridMin, *gridMax - handles to RMvertex3D objects (input). @aend @dstart Use this routine to set the minimum and maximum coordinates for the 3D lattice that defines an octmesh primitive. The spatial extents of the lattice are specified with this routine, whereas the resolution of the lattice is specified with rmPrimitiveSetOmeshDims(). Returns RM_CHILL upon success, or RM_WHACKED upon failure. Note: the dimensions of the Octmesh lattice must be specified prior (using rmPrimitiveSetOmeshDims) prior to the specification of the corners of the lattice (using rmPrimitiveSetOmeshMinMaxGrid). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetOmeshMinMaxGrid (RMprimitive *p, const RMvertex3D *gridMin, const RMvertex3D *gridMax) { RMvertex3D v[2]; if ((RM_ASSERT(p, "rmPrimitiveSetOmeshMinMaxGrid() error: the input RMprimitive is NULL") == RM_WHACKED ) || (RM_ASSERT(gridMin, "rmPrimitiveSetOmeshMinMaxGrid() error: the input gridMin pointer is NULL") == RM_WHACKED) || (RM_ASSERT(gridMax, "rmPrimitiveSetOmeshMinMaxGrid() error: the input gridMax pointer is NULL") == RM_WHACKED)) return(RM_WHACKED); v[0] = *gridMin; v[1] = *gridMax; return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_OMESH_MINMAX_GRID, 2, sizeof(RMvertex3D), (void *)v, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetMarkerScale @pstart RMenum rmPrimitiveSetMarkerScale (RMprimitive *toModify, int npts, float *scales, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int npts - an integer value specifying the length of the "scales" array (input). float *scales - a flat array of floats, expected to be "npts" in length (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback, required when copyEnum is RM_DONT_COPY_DATA (input). @aend @dstart Use this routine to set the scale values applied to RM "marker primitives." Returns RM_CHILL upon success, or RM_WHACKED upon failure. The "marker primitive" in RM is a procedural primitive built from a number of predefined shapes, such as a triangles, squares, and so forth (see rmv.h). A fully populated marker primitive will consist of some number of vertices (each vertex defines the center point for the procedural marker), optional scale values used to isometrically shrink or expand the underlying marker geometric model, and optional color values. The number of vertices defined by rmPrimitiveSetVertex2D/3D defines the number of marker primitives that will be drawn. The number of marker shapes that are drawn by a given RMprimitive object is either 1 (drawn at many places in the scene, defined by rmPrimitiveSetVertex2D/3D), or the same as the number of vertices defined by rmPrimitiveSetVertex2D/3D. The marker primitives themselves are created by rmInternalMarker2DNew() and assigned to the RMprimitive with rmPrimitiveSetMarkerPrims(). The number of scale values may be either 1, or the same as the number of vertices specified with rmPrimitiveSetVertex2D/3D. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetMarkerScale (RMprimitive *p, int npts, float *s, RMenum copy_enum, void (*appfreefunc)(void *)) { if ((private_rmPrimSetAssert(p, npts, (void *)s, copy_enum, appfreefunc, "rmPrimitiveSetMarkerScale")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem((RMprimitive *)p, RM_PRIMITIVE_MARKERS2D_SCALE, npts, sizeof(float), (void *)s, copy_enum, appfreefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetMarkerPrims @pstart RMenum rmPrimitiveSetMarkerPrims (RMprimitive *toModify, int nMarkerPrims, RMinternalMarker2D **mArray) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nMarkerPrims - an integer value specifying the number of input "marker primitives" in the mArray parameter (input). RMinternalMarker2D **mArray - a handle to a flat array of RMinternalMarker2D handles (input). @aend @dstart Use this routine to assign some number of procedural marker primitives (RMinternalMarker2D) to an RMprimitive. Returns RM_CHILL upon success, or RM_WHACKED upon failure. Use rmInternalMarker2DNew() to create the marker primitives. The "marker primitive" in RM is a procedural primitive built from a number of predefined shapes, such as a triangles, squares, and so forth (see rmv.h). A fully populated marker primitive will consist of some number of vertices (each vertex defines the center point for the procedural marker), optional scale values used to isometrically shrink or expand the underlying marker geometric model, and optional color values. The number of vertices defined by rmPrimitiveSetVertex2D/3D defines the number of marker primitives that will be drawn. The number of marker shapes that are drawn by a given RMprimitive object is either 1 (drawn at many places in the scene, defined by rmPrimitiveSetVertex2D/3D), or the same as the number of vertices defined by rmPrimitiveSetVertex2D/3D. The marker primitives themselves are created by rmInternalMarker2DNew() and assigned to the RMprimitive with rmPrimitiveSetMarkerPrims(). The number of scale values may be either 1, or the same as the number of vertices specified with rmPrimitiveSetVertex2D/3D. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetMarkerPrims (RMprimitive *p, int nmarkerprims, RMinternalMarker2D **marray) { if (RM_ASSERT(p, "rmPrimitiveSetMarkerPrims() error: primitive is NULL") == RM_WHACKED) return(RM_WHACKED); if (!((nmarkerprims != 0) && (marray != NULL))) { rmError("rmPrimitiveSetMarkerPrims() error: null markerprims array pointer and non-zero count"); return(RM_WHACKED); } return(private_rmPrimitiveSetItem((RMprimitive *)p, RM_PRIMITIVE_MARKERS2D_PRIM, nmarkerprims, sizeof(RMinternalMarker2D), (void *)marray, RM_COPY_DATA, NULL)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetEllipse2DRotate @pstart RMenum rmPrimitiveSetEllipse2DRotate (RMprimitive *toModify, int nVals, float *rotationValues, RMenum copyEnum, void (*appFreeFunc)(void *)) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nVals - an integer value specifying the length of the rotationValues[] array (input). float *rotationValues - an array of floats, must be nVals in length (input). RMenum copyEnum - an RMenum value, may be either RM_COPY_DATA or RM_DONT_COPY_DATA (input). void (*appFreeFunc)(void *) - a handle to an application callback, required when copyEnum is RM_DONT_COPY_DATA (input). @aend @dstart Use this routine to set the rotation angles for some number of ellipses in an RM_ELLIPSE2D primitive. Returns RM_CHILL upon success, or RM_WHACKED upon failure. RM ellipse primitives consist of vertices that define the center of each ellipse (rmPrimitiveSetVertex2D), optional per-ellipse color data, optional per-ellipse scale values (2 radius values per ellipse) and an optional per-ellipse rotation value. At render time, for each input vertex, or ellipse center, an idealized ellipse is first scaled, rotated, then translated to the desired location. The per-ellipse rotation value defines a counterclockwise rotation about the Z-axis, where it is assumed that the ellipse is defined in the x/y plane. The rotation values are specified in degrees (not radians). A input rotation value of 90 will cause the ellipse to be rotated 90 degrees counterclockwise. When copyEnum is set to RM_COPY_DATA, the rotation values provided by the caller will be copied. When copyEnum is set to RM_DONT_COPY_DATA, the handle "rotationValues" will be used directly by the RMprimitive. The caller must provide a callback in conjunction with RM_DONT_COPY_DATA that will be invoked when the RMprimitive is deleted. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetEllipse2DRotate (RMprimitive *p, int nvals, float *rots, RMenum copy_enum, void (*appfreefunc)(void *)) { if ((private_rmPrimSetAssert(p, nvals, (void *)rots, copy_enum, appfreefunc, "rmPrimitiveSetEllipse2DRotate")) == RM_WHACKED) return(RM_WHACKED); return(private_rmPrimitiveSetItem(p, RM_PRIMITIVE_INDICES, nvals, sizeof(float), (void *)rots, copy_enum, appfreefunc)); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetText @pstart RMenum rmPrimitiveSetText (RMprimitive *toModify, int nStrings, char *strings[]) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). int nStrings - an integer value specifying the number of text strings in the strings[] array (input). char *strings[] - an array of character strings (input). @aend @dstart Use this routine to assign some number of text strings to an RMprimitive of type RM_TEXT or RM_INDEXED_TEXT. The input text strings are duplicated in the RMprimitive; there is no shared data management. Returns RM_CHILL upon success, or RM_WHACKED upon failure. Text rendering in RM is achieved by creating an RMprimitive of type RM_TEXT or RM_INDEXED_TEXT, supplying text strings and vertex locations to the RMprimitive (colors are optional, but indices are required for the RM_INDEXED_TEXT primitive). This RMprimitive data specifies the location of the text string, along with the text to be rendered. The appearance of the text string, such as typeface, size, italicization and so forth are manipulated through the RMnode scene parameter RMtextProps (see rmTextPropsSetAttribs). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetText (RMprimitive *t, int nstrings, char *strings[]) { int i; RMtextPrim *p; if ((private_rmPrimSetAssert(t, nstrings, (void *)strings, RM_COPY_DATA, NULL, "rmPrimitiveSetText")) == RM_WHACKED) return(RM_WHACKED); /* first, remove any stuff */ if (t->p1) { int i; p = t->p1; /* free each old string */ for (i=0; i<(int)(t->flags1); i++) free((void *)p[i].string); free((void *)t->p1); } p = (RMtextPrim *)malloc(sizeof(RMtextPrim)*nstrings); for (i = 0; i < nstrings; i++) { p[i].string = strdup(strings[i]); p[i].bh = p[i].bw = -1; /* need to have these set */ p[i].ptag = -1; /* mark as uninitialized */ } t->p1 = (void *)p; t->flags1 = nstrings; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetDisplayListEnable @pstart RMenum rmPrimitiveSetDisplayListEnable (RMprimitive *toModify, RMenum newMode) @pend @astart RMprimitive *toModify - a handle to an RMprimitive (modified). RMenum newMode - an RMenum value, may be either RM_TRUE or RM_FALSE (input). @aend @dstart In RM, OpenGL display lists are automatically built and cached on a per-primitive basis. In some cases, the application may wish to override this behavior, and inhibit the automatic construction of display lists. Primitive which are dynamic, such as those that have geometry, colors, etc. that change often (like every frame) should not be display-listed. The cost of building and storing the display list will not be recouped by the shortened rendering time unless the display list is used in many frames. Specify RM_TRUE for newMode to enable display lists for the RMprimitive toModify, otherwise, specify RM_FALSE to disable display list building for the RMprimitive. Applications can control use of display lists in two ways: at the RMpipe level, and at the RMprimitive level. At the RMpipe level, you can enable or disable use of display lists for all RMprimitives drawn on RMpipe using the routine rmPipeSetDisplayListEnable. At the RMprimitive level, you can enable or disable the use of display lists for a single primitive using rmPrimitiveSetDisplayListEnable(). The RMprimitive display list policy does not override the display list policy set at the RMpipe level. In other words, if the policy at the RMpipe level is set to RM_FALSE, then no display lists will be used, even if the policy at the RMprimitive level is set to RM_TRUE. On the other hand, if the policy at the RMpipe level is set to RM_TRUE, a policy at the RMprimitive level of RM_FALSE will result on no display lists being used for the one RMprimitive. In order for display lists to be used at any given RMprimitive, the logical AND of RMpipe and RMprimitive display list policies must be RM_TRUE. Returns RM_CHILL upon success, or RM_WHACKED upon failure. (Jan 2000) At this time, there is no corresponding "get display list enable" routine. See also rmPipeSetDisplayListEnable(). @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetDisplayListEnable (RMprimitive *p, RMenum newMode) { if (RM_ASSERT(p, "rmPrimitiveSetDisplayListEnable() error: the input RMprimitive pointer is NULL. ") == RM_WHACKED) return(RM_WHACKED); if ((newMode != RM_TRUE) && (newMode != RM_FALSE)) { rmError("rmPrimitiveDisplayListEnable() error: the input newMode enumerator is neither RM_TRUE nor RM_FALSE."); return(RM_WHACKED); } /* * bookkeeping chores: * if the new mode is RM_FALSE, delete any existing display list, * and set the "compiled render function" pointer to NULL. */ private_rmPrimitiveSetDisplayListEnable(p, newMode); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeAddPrimitive @pstart RMenum rmNodeAddPrimitive (RMnode *addTo, RMprimitive *src) @pend @astart RMnode *addTo - a handle to an RMnode (modified). RMprimitive *src - a handle to an RMprimitive (input). @aend @dstart This routine adds an RMprimitive to an RMnode. Returns RM_CHILL upon success, or RM_WHACKED upon failure. Each RMnode may contain an arbitrary number of RMprimitive objects. Each of the RMprimitive objects is added to the RMnode using rmNodeAddPrimitive. The list of RMprimitives in an RMnode is a flat array, and this array grows to accomodate new RMprimitives as they are added. January 2000 - at this time, there is no corresponding "delete primitive from an RMnode" operation. The closest equivalent is rmNodeDelete(). Applications that anticipate the need to delete RMprimitives should carefully consider the subject of scene graph design, and use RMnodes that contain just a single primitive; the delete operations should be performed at the RMnode level, not the RMprimitive level. February 2001 - this routine is thread safe: multiple application threads may simultaneously call this routine to add primitives to the same node. Thread safety is provided by mutex locks in the component manager. NOTE: Applications SHOULD NOT use an RMprimitive in multiple RMnodes in order to accomplish instancing. Instancing is properly achieved in RM by instancing at the RMnode level, not the RMprimitive level. @dend * ---------------------------------------------------- */ RMenum rmNodeAddPrimitive (RMnode *n, RMprimitive *prim) { extern RMcompMgrHdr *global_RMnodePool; if (RM_ASSERT(n, "rmNodeAddPrimitive() error: input node is NULL\n") == RM_WHACKED) return(RM_WHACKED); if (rmMutexLock(global_RMnodePool->guard) == RM_WHACKED) { rmError("rmNodeAddPrimitive() error: problem locking guard mutex in component manager. "); return(RM_WHACKED); } if ((n->prims = (void **)realloc(n->prims, sizeof(void *) * (n->nprims + 1))) == NULL) { rmError("rmNodeAddPrimitive() error: realloc failure. the primitive list at this node is now in an undetermined state, and may contain garbage. "); if (rmMutexUnlock(global_RMnodePool->guard) == RM_WHACKED) { rmError("rmNodeAddPrimitive() error: problem unlocking guard mutex in component manager. "); return(RM_WHACKED); } return(RM_WHACKED); } n->prims[n->nprims] = prim; n->nprims++; if (rmMutexUnlock(global_RMnodePool->guard) == RM_WHACKED) { rmError("rmNodeAddPrimitive() error: problem unlocking guard mutex in component manager. "); return(RM_WHACKED); } return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetPrimitive @pstart RMprimitive * rmNodeGetPrimitive (const RMnode *toQuery, int indx) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). int indx - an integer value interpreted as an index (input). @aend @dstart Returns to the caller the RMprimitive handle of the i'th primitive in an RMnode. @dend * ---------------------------------------------------- */ RMprimitive * rmNodeGetPrimitive (const RMnode *m, int j) { if (RM_ASSERT(m, "rmNodeGetPrimitive() error: input node is NULL. \n") == RM_WHACKED) return(NULL); if (m->prims == NULL) return(NULL); if ((j < 0) || (j >= m->nprims)) /* error? warning? */ return(NULL); return(m->prims[j]); } /* * ---------------------------------------------------- * @Name rmNodeSetClientData @pstart RMenum rmNodeSetClientData (RMnode *toModify, void *clientData, void (*cdFreeFunc)(RMnode *,void *)) @pend @astart RMnode *toModify - a handle to an RMnode (modified). void *clientData - a handle (input). void (*cdFreeFunc)(RMnode *,void *) - a handle to an application callback (input). @aend @dstart Applications may store a handle to arbitrary memory in RMnodes or RMprimitives. This routine is used to place a handle to arbitrary memory in an RMnode, and returns RM_CHILL upon success or RM_WHACKED upon failure. Client data may be stored in both RMprimitives and RMnodes (rmNodeSetClientData). The "client data" handle may be later accessed using rmNodeGetClientData. The callback function will be invoked when the RMnode is deleted. The callback takes two parameters, a handle to the RMnode containing the client data handle, and the client data handle itself. The callback is provided so that applications may delete the data referenced by the client data handle stored in the RMnode. When the input client data handle is NULL, the old handle value is effectively overwritten. Any memory pointed to by the old client data handle will be lost (a potential memory leak). @dend * ---------------------------------------------------- */ RMenum rmNodeSetClientData (RMnode *n, void *cd, void (*cd_free_func)(RMnode *,void *)) { if (RM_ASSERT(n, "rmNodeeSetClientData() error: the input RMnode is NULL") == RM_WHACKED) return(RM_WHACKED); n->clientData = cd; n->clientDataFreeFunc = cd_free_func; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmNodeGetClientData @pstart void * rmNodeGetClientData (const RMnode *toQuery) @pend @astart const RMnode *toQuery - a handle to an RMnode (input). @aend @dstart Use this routine to obtain the client data handle stored in an RMnode. @dend * ---------------------------------------------------- */ void * rmNodeGetClientData (const RMnode *n) { if (RM_ASSERT(n, "rmNodeGetClientData() error: the input RMnode is NULL") == RM_WHACKED) return((void *)NULL); return(n->clientData); } /* * ---------------------------------------------------- * @Name rmPrimitiveSetAppDisplayList @pstart RMenum rmPrimitiveSetAppDisplayList (RMprimitive *toModify, GLuint appDisplayList) @pend @astart RMprimitive *toModify - a handle to an RMprimitive object (input). GLuint appDisplayList - a GLuint value (input). @aend @dstart Use this routine to assign a GL display list ID to an RMprimitive of type RM_APP_DISPLAYLIST. This type of RMprimitive is intended to be used by applications that need to create an OpenGL display list, perhaps using third-party modeling tools, and then have the display list contents rendered within an RM Scene Graph. Upon success, RM_CHILL is returned, while RM_WHACKED is returned upon failure. Restrictions apply when using application-defined display lists: (1) Applications are completely responsible for ensuring that the GLuint assigned as a display list ID is indeed valid. (2) After invoking the application-supplied display list, the the OpenGL state must be in exactly the same condition as it was before the display list was invoked. Failure to adhere to this rule will likely cause rendering errors that result from RM's inability to know about state changes made by the application display list. @dend * ---------------------------------------------------- */ RMenum rmPrimitiveSetAppDisplayList(RMprimitive *toModify, GLuint displayListID) { if (RM_ASSERT(toModify, "rmPrimitiveSetAppDisplayList() error: the input RMprimitive is NULL") == RM_WHACKED) return RM_WHACKED; if (private_rmPrimitiveGetType(toModify) != RM_APP_DISPLAYLIST) { rmError("rmPrimitiveSetAppDisplayList() error - the input primitive is not of type RM_APP_DISPLAYLIST"); return RM_WHACKED; } toModify->flags1 = displayListID; return RM_CHILL; } RMenum private_rmPrimitiveSetMultiTexcoordBlob(RMprimitive *p, int tcTag, int num, int stride, void *stuff, RMenum copyFlag, void (*freefunc)(void *), int textureUnit) /* * 2/2005. * Unlike private_rmPrimitiveSetItem, which is intended to be a reasonably * general interface to map the most common primitive elements into a * finite number of data blobs, this routine instead accesses blob array * specifically set aside for multitexture TCs. We still use the blob * interface for setting/getting stuff in the data blobs, but the * more general approach doesn't work so well for multitexture TCs. */ { /* * input validity checking - * 1. textureUnit. We can only check for 0 <= textureUnit <= RM_MAX_MULTITEXTURES. * we can't compare against the number of multitexture units supported * by the OpenGL implementation here - that's a render-time check. */ RMprimitiveDataBlob *b; int newMask; int numMTCs, i, junk; if ((textureUnit < 0) || (textureUnit >= RM_MAX_MULTITEXTURES)) { rmWarning("private_rmPrimitiveSetMultiTexcoordBlob error() - the input textureUnit is either less than zero or greater than or equal to RM_MAX_MULTITEXTURES. Failing to assign multitexture coords as requested. "); return RM_WHACKED; } private_rmPrimitiveSetCacheKey(p); /* * RMprimitives don't start out with prealloced blobs for multitexture TCs. * create a pile of blobs if none exist. */ if (p->multiTextureCoordBlobs == NULL) { p->multiTextureCoordBlobs = (RMprimitiveDataBlob *)malloc(sizeof(RMprimitiveDataBlob) * RM_MAX_MULTITEXTURES); memset(p->multiTextureCoordBlobs, 0, sizeof(RMprimitiveDataBlob) * RM_MAX_MULTITEXTURES); } /* we directly access the MTC blobs based upon textureUnit */ b = &(p->multiTextureCoordBlobs[textureUnit]); if ((copyFlag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copyFlag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("private_rmPrimitiveSetMultiTexcoordBlob: a freefunc is required when you use RM_DONT_COPY_DATA."); return RM_WHACKED; } /* use normal interface to set data in the blob */ private_rmBlobSetNthings(b ,num); private_rmBlobSetStride(b, stride); private_rmBlobSetData(b, num, stride, stuff, copyFlag); switch (tcTag) { case RM_PRIMITIVE_MULTI_1DTCOORDS: private_rmBlobSetVeclen(b, 1); break; case RM_PRIMITIVE_MULTI_2DTCOORDS: private_rmBlobSetVeclen(b, 2); break; case RM_PRIMITIVE_MULTI_3DTCOORDS: private_rmBlobSetVeclen(b, 3); break; } /* update the mask to reflect the addition of new MTC's */ newMask = 1 << textureUnit; /* we might be writing over the MTCs for a texture unit set during a previous invocation (app data update) */ junk = p->multiTextureCoordBlobsMask |= newMask; /* count up the number of MTC blobs */ for (i=0, numMTCs=0; (i> 1; } /* and set the field indicating the number of MTC blobs */ p->numMultiTextureCoordBlobs = numMTCs; return RM_CHILL; } /* PRIVATE * * the following is a private, interal routine used to interface between * application level API and the guts of the RMprimitive "blob model" * of data management. */ RMenum private_rmPrimitiveSetItem (RMprimitive *p, /* primitive to add to */ int tag, /* definition */ int num, /* how many */ int stride, /* size of individual thing in bytes -stride*/ void *stuff, /* pointer to the stuff */ RMenum copy_flag, /* RM_COPY_DATA/RM_DONT_COPY_DATA */ void (*freefunc)(void *)) /* free function for prim */ { /* * Tue Sep 30 20:36:53 PDT 1997 - added clutch code that sits * between RMvertex3D and true float[]'s - to avoid padding magic * that happens on some compilers. */ /* * Fri Oct 2 08:42:46 PDT 1998 - copy flag and client data free * func added. some compilers on 64bit OS's pad structures to 8-byte * boundaries. therefore, an RMvertex3D structure that consists of * 3 floats is padded out to the next 8-byte boundary. OpenGL * vertex arrays allow for this kind of thing with a stride * parameter. * * Sat Oct 28 10:53:57 PDT 2000 - all prims get their cache key * updated whenever anything in the prim is set. */ int blob_index; RMenum rstat = RM_CHILL; RMprimitiveDataBlob *b; private_rmPrimitiveSetCacheKey(p); switch (tag) { case RM_PRIMITIVE_3DVERTICES: case RM_PRIMITIVE_2DVERTICES: { blob_index = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, blob_index); private_rmBlobSetNthings(b, num); private_rmBlobSetStride(b, stride); private_rmBlobSetVeclen(b, (tag == RM_PRIMITIVE_3DVERTICES) ? 3 : 2); private_rmBlobSetData(b, num, stride, stuff, copy_flag); private_rmBlobSetType(b, blob_index); if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("rmPrimitiveSetItem: a freefunc is required when you use RM_DONT_COPY_DATA."); rstat = RM_WHACKED; } } break; case RM_PRIMITIVE_4COLORS: case RM_PRIMITIVE_3COLORS: { blob_index = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, blob_index); private_rmBlobSetNthings(b ,num); private_rmBlobSetStride(b, stride); private_rmBlobSetData(b, num, stride, stuff, copy_flag); private_rmBlobSetVeclen(b, (tag == RM_PRIMITIVE_4COLORS) ? 4 : 3); private_rmBlobSetType(b, blob_index); if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("rmPrimitiveSetItem: a freefunc is required when you use RM_DONT_COPY_DATA."); rstat = RM_WHACKED; } break; } case RM_PRIMITIVE_1DTCOORDS: case RM_PRIMITIVE_2DTCOORDS: case RM_PRIMITIVE_3DTCOORDS: case RM_PRIMITIVE_NORMALS: { int veclen = 0; /* init satisfies gcc warning */ blob_index = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, blob_index); private_rmBlobSetNthings(b, num); private_rmBlobSetStride(b, stride); private_rmBlobSetData(b, num, stride, stuff, copy_flag); /* set veclen */ if ((tag == RM_PRIMITIVE_NORMALS) || (tag == RM_PRIMITIVE_3DTCOORDS)) veclen = 3; else if (tag == RM_PRIMITIVE_2DTCOORDS) veclen = 2; else if (tag == RM_PRIMITIVE_1DTCOORDS) veclen = 1; private_rmBlobSetVeclen(b, veclen); if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("rmPrimitiveSetItem: a freefunc is required when you use RM_DONT_COPY_DATA."); rstat = RM_WHACKED; } break; } case RM_PRIMITIVE_OMESHDIMS: case RM_PRIMITIVE_QMESHDIMS: { blob_index = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, blob_index); private_rmBlobSetNthings(b, num); private_rmBlobSetStride(b, stride ); private_rmBlobSetData(b, num, stride, stuff, copy_flag); if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("rmPrimitiveSetItem: a freefunc is required when you use RM_DONT_COPY_DATA."); rstat = RM_WHACKED; } break; } case RM_PRIMITIVE_MARKERS2D_SCALE: case RM_PRIMITIVE_CYLINDER_RADII: case RM_PRIMITIVE_CONE_RADII: case RM_PRIMITIVE_RADII: case RM_PRIMITIVE_INDICES: { blob_index = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, blob_index); private_rmBlobSetNthings(b, num); private_rmBlobSetStride(b, stride); private_rmBlobSetData(b, num, stride, stuff, copy_flag); /* set veclength */ if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc != NULL)) private_rmBlobSetFreefunc(b, freefunc); else if ((copy_flag == RM_DONT_COPY_DATA) && (freefunc == NULL)) { rmError("rmPrimitiveSetItem: a freefunc is required when you use RM_DONT_COPY_DATA."); rstat = RM_WHACKED; } break; } case RM_PRIMITIVE_OMESH_MINMAX_GRID: { /* * the omesh min-max grid is expanded to a rectilinear * grid here. we go from two RMvertex's to an array of * floats, the length of which is usize+vsize+wsize; * * the dimensions of the octmesh MUST be defined before * the grid is defined, otherwise this hunk of code fails. * * we ignore the copy flag passed in to this routine, and * create our own "copy" of the grid via the expansion from * corner points to 3 rectilinear arrays. */ int i, *dims; float t, dt, *f, *xspacing, *yspacing, *zspacing; RMvertex3D *gmin,*gmax; RMprimitiveDataBlob *s; /* check to see if usize, vsize and wsize are set */ i = private_rmBlobIndexFromPrimAtom(RM_PRIMITIVE_OMESHDIMS); s = private_rmBlobFromIndex(p, i); { int npts = private_rmBlobGetNthings(s); dims = (int *)private_rmBlobGetData(s); if ((dims == NULL) || (npts != 3)) { rmError(" the size of the Octmesh must be defined prior to setting the grid. Skipping the assignment of the grid. \n"); return(RM_WHACKED); } } /* malloc the hunk of memory used to hold the expanded grid */ f = (float *)malloc(sizeof(float) * (dims[0] + dims[1] + dims[2])); xspacing = f; yspacing = xspacing + dims[0]; zspacing = yspacing + dims[1]; gmin = (RMvertex3D *)stuff; gmax = gmin + 1; /* ?? */ /* do the x axis */ t = gmin->x; dt = (gmax->x - gmin->x) / (dims[0] - 1); for (i = 0; i < dims[0]; i++, t += dt) xspacing[i] = t; /* do the y axis */ t = gmin->y; dt = (gmax->y - gmin->y) / (dims[1]- 1); for (i = 0; i < dims[1]; i++, t += dt) yspacing[i] = t; /* do the z-axis */ t = gmin->z; dt = (gmax->z - gmin->z) / (dims[2] - 1); for (i = 0; i < dims[2]; i++, t += dt) zspacing[i] = t; i = private_rmBlobIndexFromPrimAtom(tag); b = private_rmBlobFromIndex(p, i); private_rmBlobSetType(b, i); private_rmBlobSetNthings(b, (dims[0] + dims[1] + dims[2])); private_rmBlobSetStride(b, sizeof(float)); private_rmBlobSetData(b, (dims[0] + dims[1] + dims[2]), sizeof(float), f, RM_COPY_DATA); free(f); break; } case RM_PRIMITIVE_MARKERS2D_PRIM: { RMinternalMarker2D **m; if (p->p1) free(p->p1); /* hack - we assume that there is only one of these things that is being passed in. */ m = (RMinternalMarker2D **)stuff; p->p1 = (void *)rmInternalMarker2DNew(m[0]->npts, m[0]->gl_begin_flag, m[0]->vlist); p->flags1 = num; rstat = RM_CHILL; break; } case RM_PRIMITIVE_SPRITES: { int i; RMimage **img, **src; /* * in sprite primitives, we use p1 to point to a list of * RMimages's. the flags1 field is set in this chunk of * code to reflect the actual number of cached sprites. * we use this internal field so that we can properly * free up old sprite's. */ if (rmPrimitiveGetType(p) != RM_SPRITE) { rmError("error trying to add sprites to a non-sprite primitive type."); return(RM_WHACKED); } if (p->p1) { /* free up old one's */ img = (RMimage **) (p->p1); for (i = 0; i < (int)(p->flags1); i++) rmImageDelete(img[i]); free((void *)(img)); p->flags1 = 0; } /* now build a new list, duplicating the input images */ src = (RMimage **)stuff; img = (RMimage **)malloc(sizeof(RMimage *)*num); for (i = 0; i < num; i++) img[i] = rmImageDup(src[i]); p->p1 = (void *)img; p->flags1 = num; break; } case RM_PRIMITIVE_BITMAPS: { /* * the "p1" field is used as a pointer to a list of bitmaps. * the "flags1" field is used to hold the count of bitmaps * in the p1 field. */ int i; RMbitmap **src, **bmp; i = rmPrimitiveGetType(p); if ((i != RM_BITMAP) && (i != RM_INDEXED_BITMAP) && (i != RM_TEXT) && (i != RM_INDEXED_TEXT)) { rmError("attempting to add bitmaps to a primitive which is not of type RM_BITMAP or RM_BITMAP_INDICES. \n"); return(RM_WHACKED); } if (p->p1) { /* free the old ones. */ bmp = (RMbitmap **) (p->p1); for (i = 0; i < (int)(p->flags1); i++) rmBitmapDelete(bmp[i]); free((void *)(bmp)); p->flags1 = 0; } /* now build a new list, duplicating the input images */ src = (RMbitmap **)stuff; bmp = (RMbitmap **)malloc(sizeof(RMbitmap *)*num); for (i = 0; i < num; i++) bmp[i] = rmBitmapDup(src[i]); p->p1 = (void *)bmp; p->flags1 = num; break; } default: rmWarning(" undefined primitive type used in private_rmPrimitiveSetItem() "); rstat = RM_WHACKED; break; } return(rstat); } /* PRIVATE * * this private routine is used by some of the draw functions to * get at specific parts of the RMprimitive data. vertices, colors, * indices, etc are all handled by the blob data model, and attempting * to access those items with this routine will produce an error message. */ RMenum private_rmPrimitiveGetItem (RMprimitive *p, int tag, int *num, void **stuff) { RMenum rstat = RM_WHACKED; switch (tag) { case RM_PRIMITIVE_3DVERTICES: case RM_PRIMITIVE_2DVERTICES: case RM_PRIMITIVE_2DTCOORDS: case RM_PRIMITIVE_4COLORS: case RM_PRIMITIVE_3COLORS: case RM_PRIMITIVE_NORMALS: case RM_PRIMITIVE_MARKERS2D_SCALE: case RM_PRIMITIVE_CYLINDER_RADII: case RM_PRIMITIVE_CONE_RADII: case RM_PRIMITIVE_RADII: case RM_PRIMITIVE_QMESHDIMS: case RM_PRIMITIVE_OMESHDIMS: case RM_PRIMITIVE_BITMAP_INDICES: { fprintf(stderr," improper use of RMprimitiveGetItem! \n"); break; } case RM_PRIMITIVE_RENDERFUNC: { if (p->renderfunc) { *stuff = (void *)(p->renderfunc); rstat = RM_CHILL; } else rstat = RM_WHACKED; } break; case RM_PRIMITIVE_MARKERS2D_PRIM: case RM_PRIMITIVE_SPRITES: case RM_PRIMITIVE_BITMAPS: case RM_PRIMITIVE_TEXTPRIM: { if (p->p1) { *num = p->flags1; *stuff = p->p1; rstat = RM_CHILL; } else *num = 0; } break; } return(rstat); } /* PRIVATE */ RMenum private_rmPrimitiveGetText (RMprimitive *t, int *nstringsReturn, RMtextPrim **primsReturn) { /* this routine needs some work */ if ((t->flags1 != 0) && (t->p1 != NULL)) { *nstringsReturn = t->flags1; *primsReturn = (RMtextPrim *)(t->p1); return(RM_CHILL); } else return(RM_WHACKED); } /* PRIVATE */ void private_rmBlobSetType (RMprimitiveDataBlob *b, int newtype) { /* * the intent is to store in "blobtype" the RM_PRIMITIVE_* tag * assigned by the user. we need this info because, to some extent, * the user data is homogonized in the cast-to-blob process. some * primitive rendering & mem. mgt handling code in RM needs this * info. */ b->blobtype = newtype; } /* PRIVATE */ int private_rmBlobGetType (RMprimitiveDataBlob *b) { return(b->blobtype); } /* PRIVATE */ void private_rmBlobSetNthings (RMprimitiveDataBlob *b, int num) { b->nthings = num; } /* PRIVATE */ int private_rmBlobGetNthings (RMprimitiveDataBlob *b) { return(b->nthings); } /* PRIVATE */ void private_rmBlobSetStride (RMprimitiveDataBlob *b, int stride) { b->stride = stride; } /* PRIVATE */ void private_rmBlobSetVeclen (RMprimitiveDataBlob *b, int veclen) { b->veclen = veclen; } /* PRIVATE */ int private_rmBlobGetVeclen (RMprimitiveDataBlob *b) { return(b->veclen); } /* PRIVATE */ void private_rmBlobSetData (RMprimitiveDataBlob *b, int num, int stride, void *stuff, RMenum copy_flag) { /* * first, free up old stuff. if RM is responsible for the data, do * a free(). if the app is repsonsible, invoke the appfreefunc(). */ if ((b->copyflag == RM_COPY_DATA) && (b->ptr != NULL)) free(b->ptr); else if ((b->copyflag == RM_DONT_COPY_DATA) && (b->appfreefunc != NULL)) (*(b->appfreefunc))(b->ptr); if (copy_flag == RM_COPY_DATA) { int nbytes; nbytes = stride*num; b->ptr = (void *)malloc(nbytes); b->copyflag = copy_flag; memcpy(b->ptr, stuff, nbytes); } else { b->ptr = stuff; b->copyflag = copy_flag; } } /* PRIVATE */ void private_rmBlobSetFreefunc (RMprimitiveDataBlob *b, void (*freefunc)(void *)) { b->appfreefunc = freefunc; } /* PRIVATE */ int private_rmBlobGetStride (RMprimitiveDataBlob *b) { return(b->stride); } /* PRIVATE */ void * private_rmBlobGetData (RMprimitiveDataBlob *b) { return(b->ptr); } /* PRIVATE */ int private_rmBlobIndexFromPrimAtom (int tag) { int rstat; /* * this code translates from an RM_PRIMITIVE_* tag to a blob tag. * this is used by rm routines that need to stuff app's prim data * into blobs */ switch(tag) { case RM_PRIMITIVE_3DVERTICES: case RM_PRIMITIVE_2DVERTICES: rstat = BLOB_VERTEX_INDEX; break; case RM_PRIMITIVE_OMESH_MINMAX_GRID: rstat = BLOB_OMESH_RECTGRID_INDEX; break; case RM_PRIMITIVE_4COLORS: case RM_PRIMITIVE_3COLORS: rstat = BLOB_COLOR_INDEX; break; case RM_PRIMITIVE_NORMALS: rstat = BLOB_NORMAL_INDEX; break; case RM_PRIMITIVE_1DTCOORDS: case RM_PRIMITIVE_2DTCOORDS: case RM_PRIMITIVE_3DTCOORDS: rstat = BLOB_TC_INDEX; break; case RM_PRIMITIVE_MARKERS2D_SCALE: case RM_PRIMITIVE_CYLINDER_RADII: case RM_PRIMITIVE_CONE_RADII: case RM_PRIMITIVE_RADII: rstat = BLOB_SCALE_INDEX; break; case RM_PRIMITIVE_QMESHDIMS: rstat = BLOB_QMESHDIMS_INDEX; break; case RM_PRIMITIVE_OMESHDIMS: rstat = BLOB_OMESHDIMS_INDEX; break; case RM_PRIMITIVE_INDICES: rstat = BLOB_INDEX_INDEX; break; default: rstat = RM_WHACKED; break; /* no texture coords yet */ } return(rstat); } /* PRIVATE */ RMprimitiveDataBlob * private_rmBlobFromIndex (RMprimitive *p, int tag) { /* used by rm routines that need to get at the data in blobs */ RMprimitiveDataBlob *b; switch (tag) { case BLOB_VERTEX_INDEX: case BLOB_OMESH_RECTGRID_INDEX: b = &(p->blobs[0]); break; case BLOB_COLOR_INDEX: b = &(p->blobs[1]); break; case BLOB_TC_INDEX: b = &(p->blobs[3]); break; case BLOB_NORMAL_INDEX: b = &(p->blobs[2]); break; case BLOB_QMESHDIMS_INDEX: case BLOB_OMESHDIMS_INDEX: case BLOB_INDEX_INDEX: b = &(p->blobs[4]); break; case BLOB_SCALE_INDEX: b = &(p->blobs[5]); break; default: b = NULL; fprintf(stderr, "private_rmBlobFromIndex() code not finished or unrecognized blob type \n"); break; } return(b); } /* PRIVATE * * the following is a convenience routine used by most of the methods * that assign data to RMprimitives. it is a way to do sanity checking * of input parameters, and avoids a lot of duplicated code. it's a * compact, reusable routine for performing input validation. */ RMenum private_rmPrimSetAssert (RMprimitive *t, int n, void *dataptr, RMenum copyEnum, void (*freefunc)(), const char *rname) { char buf[256]; sprintf(buf, "%s error: the input primitive is NULL", rname); if (RM_ASSERT(t, buf) == RM_WHACKED) return(RM_WHACKED); sprintf(buf, "%s error: non-zero data count but have NULL data pointer.", rname); if (((n != 0) && (dataptr == NULL)) == 1) { rmError(buf); return(RM_WHACKED); } sprintf(buf, "%s error: when the copy enum is set to RM_DONT_COPY_DATA, the application MUST provide a free function ", rname); if ((freefunc == NULL) && (copyEnum == RM_DONT_COPY_DATA)) { rmError(buf); return(RM_WHACKED); } return(RM_CHILL); } /* private */ RMenum private_rmPrimitiveComputeGenericBoundingBox(RMprimitive *p) { int nverts, stride; float *v; RMprimitiveDataBlob *b; RMvertex3D tmin, tmax; b = private_rmBlobFromIndex(p, BLOB_VERTEX_INDEX); v = (float *)private_rmBlobGetData(b); nverts = private_rmBlobGetNthings(b); stride = private_rmBlobGetStride(b); rmPointMinMax(v, nverts, private_rmBlobGetVeclen(b), stride, &tmin, &tmax); rmPrimitiveSetBoundingBox(p, &tmin, &tmax); return(RM_CHILL); } /* private */ RMenum private_rmPrimitiveComputeSpheresBoundingBox(RMprimitive *p) { int j, rstride, nradii, rveclen, vstride, nvertices, vveclen; float *radii, *vertices; RMvertex3D smin, smax; RMvertex3D boxMin, boxMax; private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nvertices, (void **)&vertices, &vveclen); private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); /* compute bounding boxes for all spheres */ for (j = 0; j < nvertices; j++, vertices += vstride, radii += rstride) { /* extents = center +/- radius */ memcpy((void *)&smin, vertices, sizeof(RMvertex3D)); smax = smin; smin.x -= *radii; smin.y -= *radii; smin.z -= *radii; smax.x += *radii; smax.y += *radii; smax.z += *radii; /* tally sphere bounding boxes */ if (j == 0) { boxMin = smin; boxMax = smax; } else rmUnionBoundingBoxes(&boxMin, &boxMax, &smin, &smax, &boxMin, &boxMax); } /* just scan through all the vertices to find min/max */ rmPrimitiveSetBoundingBox(p, &boxMin, &boxMax); return RM_CHILL; } /* private */ RMenum private_rmPrimitiveComputeCylindersBoundingBox(RMprimitive *p) { /* * we assume that the bbox for a cylinder is "almost the same as" * the union of the bbox formed by two spheres of radius R at * each end of the cylinder. */ int j, rstride, nradii, rveclen, vstride, nvertices, vveclen; float *radii, *vertices; RMvertex3D s1min, s1max, s2min, s2max; RMvertex3D boxMin, boxMax; /* get vertex and radius blob info */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nvertices, (void **)&vertices, &vveclen); private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); /* compute bounding boxes for all cylinders */ for (j = 0; j < nvertices/2; j++, vertices += vstride, radii += rstride) { /* extents = center +/- radius */ memcpy((void *)&s1min, vertices, sizeof(RMvertex3D)); vertices += vstride; s1max = s1min; memcpy((void *)&s2min, vertices, sizeof(RMvertex3D)); s2max = s2min; s1min.x -= *radii; s1min.y -= *radii; s1min.z -= *radii; s1max.x += *radii; s1max.y += *radii; s1max.z += *radii; s2min.x -= *radii; s2min.y -= *radii; s2min.z -= *radii; s2max.x += *radii; s2max.y += *radii; s2max.z += *radii; /* tally sphere bounding boxes */ if (j == 0) { rmUnionBoundingBoxes(&s1min, &s1max, &s2min, &s2max, &boxMin, &boxMax); } else { rmUnionBoundingBoxes(&boxMin, &boxMax, &s1min, &s1max, &boxMin, &boxMax); rmUnionBoundingBoxes(&boxMin, &boxMax, &s2min, &s2max, &boxMin, &boxMax); } } rmPrimitiveSetBoundingBox(p, &boxMin, &boxMax); return(RM_CHILL); } /* private */ RMenum private_rmPrimitiveComputeConesBoundingBox(RMprimitive *p) { /* * we assume that the bbox for a cone can be estimated as the * combination of a sphere centered at the base of the cone, and the * line segment formed by the two cone endpoints. */ int j, rstride, nradii, rveclen, vstride, nvertices, vveclen; float *radii, *vertices; RMvertex3D s1min, s1max, s2min, s2max; RMvertex3D boxMin, boxMax; /* get vertex and radius blob info */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nvertices, (void **)&vertices, &vveclen); private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); /* compute bounding boxes for all cones */ for (j = 0; j < nvertices/2; j++, vertices += vstride, radii += rstride) { /* extents = center +/- radius */ memcpy((void *)&s1min, vertices, sizeof(RMvertex3D)); vertices += vstride; s1max = s1min; memcpy((void *)&s2min, vertices, sizeof(RMvertex3D)); s2max = s2min; s1min.x -= *radii; s1min.y -= *radii; s1min.z -= *radii; s1max.x += *radii; s1max.y += *radii; s1max.z += *radii; /* tally sphere bounding boxes */ if (j == 0) { rmUnionBoundingBoxes(&s1min, &s1max, &s2min, &s2max, &boxMin, &boxMax); } else { rmUnionBoundingBoxes(&boxMin, &boxMax, &s1min, &s1max, &boxMin, &boxMax); rmUnionBoundingBoxes(&boxMin, &boxMax, &s2min, &s2max, &boxMin, &boxMax); } } rmPrimitiveSetBoundingBox(p, &boxMin, &boxMax); return(RM_CHILL); } /* private */ RMenum private_rmPrimitiveComputeOctmeshBoundingBox(RMprimitive *p) { float *v; RMprimitiveDataBlob *b; RMvertex3D tmin, tmax; RMenum haveValidOctmeshBox=RM_FALSE; /* this doesn't work for the weird octmesh grid types */ b = private_rmBlobFromIndex(p, BLOB_VERTEX_INDEX); v = (float *)private_rmBlobGetData(b); switch(private_rmBlobGetType(b)) { /* 2/1/03 - the only support grid type for octmeshes is the minmax grid. that grid is converted into a rectilinear form when the app sets the grid corners. */ case BLOB_OMESH_RECTGRID_INDEX: { int *dims, i; RMprimitiveDataBlob *s; int npts; i = private_rmBlobIndexFromPrimAtom(RM_PRIMITIVE_OMESHDIMS); s = private_rmBlobFromIndex(p, i); npts = private_rmBlobGetNthings(s); dims = (int *)private_rmBlobGetData(s); if (dims == NULL) /* no size info, can't compute size so leave it unchanged*/ return(RM_WHACKED); haveValidOctmeshBox = RM_TRUE; tmin.x = tmax.x = v[0]; for (i = 1; i < dims[0]; i++) { if (v[i] < tmin.x) tmin.x = v[i]; if (v[i] > tmax.x) tmax.x = v[i]; } v += dims[0]; tmin.y = tmax.y = v[0]; for (i = 1; i < dims[1]; i++) { if (v[i] < tmin.y) tmin.y = v[i]; if (v[i] > tmax.y) tmax.y = v[i]; } v += dims[1]; tmin.z = tmax.z = v[0]; for (i = 1; i < dims[2]; i++) { if (v[i] < tmin.z) tmin.z = v[i]; if (v[i] > tmax.z) tmax.z = v[i]; } break; } default: /* bogus blob type */ break; } /* end blobtype switch */ if (haveValidOctmeshBox == RM_TRUE) { rmPrimitiveSetBoundingBox(p, &tmin, &tmax); return RM_CHILL; } else { rmWarning("private_rmPrimitiveComputeOctmeshBoundingBox() - unable to obtain valid octmesh grid data. "); return RM_WHACKED; } } /* private */ RMenum private_rmPrimitiveCompute2DCircleBoundingBox(RMprimitive *p) { /* just scan through all the vertices to find min/max */ rmNotice("private_rmPrimitiveCompute2DCircleBoundingBox(RMprimitive *p) - no code yet."); p = NULL; /* foil compiler warning */ return RM_WHACKED; } /* private */ RMenum private_rmPrimitiveCompute2DEllipseBoundingBox(RMprimitive *p) { /* just scan through all the vertices to find min/max */ rmNotice("private_rmPrimitiveCompute2DEllipseBoundingBox(RMprimitive *p) - no code yet. "); p = NULL; /* foil compiler warning */ return RM_WHACKED; } /* private */ RMenum private_rmPrimitiveNullBoxFunc(RMprimitive *p) { /* */ p = NULL; /* foil compiler warning */ return RM_WHACKED; } /* EOF */