/* * 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: rmdraw2.c,v 1.20 2005/07/02 17:48:45 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.20 $ * $Log: rmdraw2.c,v $ * Revision 1.20 2005/07/02 17:48:45 wes * Updated rasterpos offset code for sprites to support 3D as well as 2D. * Some minor z-coordinate buglets remain for 3D sprite positioning - see * the comments in code for details. * * Revision 1.19 2005/06/26 18:50:11 wes * Numerous updates: * (1) Correct computation of viewport matrix, stuff into RMstate. * (2) Refine code that repositions the glRasterPosition for RM_SPRITE primitives; * works well in 2D, still needs a little help for 3D. * (3) Update RM_SPRITE draw code to take into account text justification parms. * * Revision 1.18 2005/06/06 02:04:29 wes * Lots of small additions to clean up compiler warnings. * * Revision 1.17 2005/05/28 16:25:57 wes * Fixed bug where the pickable quad associated with bitmap-based * primitives (RM_BITMAP, RM_TEXT, etc.) was incorrectly placed when * text justification attributes RM_CENTER or RM_RIGHT were in effect. * * Revision 1.16 2005/05/16 01:01:37 wes * Update some primitive draw routines to use private_rmSetGLTexCoordFunc * to obtain the correct OpenGL texture coordinate function. * * Revision 1.15 2005/05/15 15:20:42 wes * New internal routine to set the appropriate OpenGL texture coordinate function * as a function of RMprimitive TC data characteristics. * * Revision 1.14 2005/05/06 16:35:26 wes * Fixed buglet whereby prims specified with 0 verts would generate an * incomplete OpenGL display list, thereby causing a domino-effect * of errors. * * Revision 1.13 2005/03/16 16:43:17 wes * Fixed a text rendering bug introduced during code merge. * * 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:23:56 wes * Distro sync and consolidation. * Added support for multitexturing. * * Revision 1.10 2005/02/12 00:54:50 wes * Preliminary multitexturing support for RMprimitives: qmesh, quads, tstrip, * triangles, and indexed triangles. * * Revision 1.9 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.8 2004/09/28 00:45:13 wes * Modified rmQuads to support per-face colors and/or normals. Moved * rmQuads from rmdraw1.c to rmdraw2.c * * Revision 1.7 2004/03/10 01:47:06 wes * Added rendering code for RM_INDEXED_QUAD_STRIP prim type. * * Revision 1.6 2004/02/23 03:04:32 wes * New primitives: RM_QUAD_STRIP, RM_INDEXED_TRIANGLES, RM_INDEXED_QUADS, * RM_INDEXED_TRIANGLE_STRIP. * * Revision 1.5 2004/01/16 16:44:05 wes * Updated copyright line for 2004. * * Revision 1.4 2003/10/03 19:21:17 wes * Improved error checking and reporting in the rmText rendering function. * * Revision 1.3 2003/07/20 14:44:41 wes * Modified some declarations for RM support routines to support per-line * color in the disjoint lines primitives. * * 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.17 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.16 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.15 2002/11/14 15:34:51 wes * Minor editing for beautification. * * Revision 1.14 2002/08/29 22:20:32 wes * * Massive upgrade to accommodate dynamic object reallocation within * the component manager, and within the context cache. Use the * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf * whenever a realloc occurs. With this upgrade, there are no * OpenRM limits on the size of the scene graph. There will be external * limits, such as the amount of RAM and the amount of space available * to your OpenGL implementation. * * Revision 1.13 2002/06/17 00:57:01 wes * Fixed numerical problem related to calcuation of quad used when doing * GL_SELECT on bitmaps, sprites and text. Condensed the code used to * compute and draw those pickable quads; the new routines make use of * the internal routine private_rmNewWCfromDCOffset rather than compute * it separately. Added SHOW_PICKABLE_QUADS #define to draw the pickable * quads during normal rendering for visual reality check. * * Revision 1.12 2002/06/02 15:14:18 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.11 2002/04/30 19:31:22 wes * Fixed a bug in the display of indexed text/bitmap primitives. * * Revision 1.10 2001/10/15 00:04:53 wes * Changed dispatching of characters in rmText from single char at a time * to string at a time. The older code had some debug stuff in it that * checked the raster position after the glVertex2/3f() call, but before * the glBitmap() call. That calling sequence seems to cause problems for * Win32. * * Added an RMstate parm to the parm list for the setup funcs inside * draw routines for lines, text and images. This will cause lighting * to be enabled or disabled as a function of whether or not fogging * is active. It would be nice if fogging could be enabled, but lighting * disabled. * * Revision 1.9 2001/05/26 14:35:49 wes * Added error checking code to rmSprite(). * * Revision 1.8 2001/03/31 17:12:38 wes * v1.4.0-alpha-2 checkin. * * Revision 1.7 2000/12/05 03:01:59 wes * Fixed problem with rmText in which default text properties were * malloc'ed, but never free'd. * * Revision 1.6 2000/12/03 22:34:37 wes * Mods for thread safety- RMpipe added as parm to display list * calls. * * Revision 1.5 2000/08/31 02:07:11 wes * No significant changes. * * Revision 1.4 2000/08/23 23:24:21 wes * DO_LISTS define moved from rmogl.c to rmprivat.h. All display * list code removed from rmBitmap (will be reinserted later). * * Revision 1.3 2000/08/19 14:58:29 wes * Culled unused code. * * 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 "rmprivatps.h" /* * 6/12/02 wes * for debugging purposes, you can set SHOW_PICKABLE_QUADS to a * non-zero value. this will cause the pickable quads associated with * rmText, rmBitmap and rmSprite primitives to be drawn *in addition to* * the source bitmap, text or sprite. usually, * these "helper" objects * are not drawn except during selection mode. */ #define SHOW_PICKABLE_QUADS 0 /*#define SHOW_PICKABLE_QUADS 1 */ /* * this file contains RMprimitive "draw" routines for those * primitives that DO NOT easily map to OpenGL vertex arrays. */ extern void rmuCone(void (*colorfunc)(const float *), float *color, RMvertex3D *p1, RMvertex3D *p2, float radius1 ,int subdivisions, RMpipe *p); /* * Begin glVertex* and pals macro/function layer * * win-32 notes: * * un*x treats glVertex* and cousins as a normal function (pointer). * therefore, it is possible to access those functions through a pointer. * in MS VC, the glVertex* and pals have a verbose declaration which renders * indirect access (via a pointer) next to impossible. * * in order to remedy this situation, we use either macros (UNIX) or * a subroutine layer (win-32) to temporarily work around this problem. * */ #ifdef RM_WIN void rmglVertex3fv (const GLfloat *v) { glVertex3fv(v); } void rmglVertex2fv (const GLfloat *v) { glVertex2fv(v); } void rmglNormal3fv (const GLfloat *v) { glNormal3fv(v); } void rmglColor3fv (const GLfloat *a) { glColor3fv(a); } void rmglColor4fv (const GLfloat *a) { glColor4fv(a); } void rmglRasterPos2fv (const GLfloat *v) { glRasterPos2fv(v); } void rmglRasterPos3fv (const GLfloat *v) { glRasterPos3fv(v); } void rmglTexCoord1fv (const GLfloat *v) { glTexCoord1fv(v); } void rmglTexCoord2fv (const GLfloat *v) { glTexCoord2fv(v); } void rmglTexCoord3fv (const GLfloat *v) { glTexCoord3fv(v); } #endif /* PRIVATE */ void glNoOp (const float *f) { /* do nothing */ f = NULL; /* foil compiler warning */ } /* PRIVATE */ void private_rmSetGLColorFunc (int cvecsize, int ncolors, void (**cfuncptr)(const float *)) { /* set OpenGL color routine as a function of the color vector length */ if (ncolors == 0 || cvecsize == 0) *cfuncptr = glNoOp; else { if (cvecsize == 3) *cfuncptr = rmglColor3fv; else { if (cvecsize == 4) *cfuncptr = rmglColor4fv; else *cfuncptr = glNoOp; /* warning? */ } } } /* PRIVATE */ void private_rmSetGLTexCoordFunc (int tcvecsize, int ntc, void (**tcfuncptr)(const float *)) { /* set OpenGL texture coord routine as a function of tc vector length */ if (ntc == 0 || tcvecsize == 0) *tcfuncptr = glNoOp; else { switch(tcvecsize) { case 2: *tcfuncptr = rmglTexCoord2fv; break; case 3: *tcfuncptr = rmglTexCoord3fv; break; case 1: *tcfuncptr = rmglTexCoord1fv; break; default: rmError("private_rmSetGLTexCoordFunc error: input tcveclen != 1,2, or 3 yet ntc != 0. Please file a bug report. "); break; } } } /* PRIVATE */ void private_rmStateGetTextJustify (const RMstate *s, RMenum *hjustify, RMenum *vjustify) { extern RMenum RM_DEFAULT_HJUSTIFY, RM_DEFAULT_VJUSTIFY; if (s->textProps == NULL) { *hjustify = RM_DEFAULT_HJUSTIFY; *vjustify = RM_DEFAULT_VJUSTIFY; } else { *hjustify = s->textProps->hJustify; *vjustify = s->textProps->vJustify; } } /* precomputed trig tables */ #define TRIG_RES 360 double cos_table[TRIG_RES], sin_table[TRIG_RES]; /* PRIVATE */ void private_initTrigTables (void) { int i; double t, dt; t = 0.0; dt = RM_TWO_PI / (double)TRIG_RES; for (i = 0; i < TRIG_RES; i++, t += dt) { cos_table[i] = cos(t); sin_table[i] = sin(t); } } /* PRIVATE */ static void rmuCircle2d (int subdivisions) { int i; float t, dt; float v[2]; /* draw a unit convex polygon at (0,0) */ if (subdivisions > TRIG_RES) subdivisions = TRIG_RES; t = 0.0; dt = (float)(TRIG_RES) / (float)(subdivisions); glBegin(GL_POLYGON); for (i = 0; i < subdivisions; i++, t += dt) { v[0] = cos_table[(int)t]; v[1] = sin_table[(int)t]; glVertex2fv(v); } glEnd(); } /* PRIVATE */ static void rmuEllipse2d (int subdivisions, float a, /* vertical scale */ float b) /* horizontal scale */ { int i; float t, dt; float v[2]; /* draw a unit convex polygon at (0,0) with the desired scaling */ if (subdivisions > TRIG_RES) subdivisions = TRIG_RES; t = 0.0; dt = (float)(TRIG_RES) / (float)(subdivisions); glBegin(GL_POLYGON); for (i = 0; i < subdivisions; i++, t += dt) { v[0] = cos_table[(int)t] * b; v[1] = sin_table[(int)t] * a; glVertex2fv(v); } glEnd(); } /* PRIVATE */ static void private_rmSetupBitmapPickMatrices (RMstate *s, RMmatrix *vpm, RMmatrix *vpm_inv, RMmatrix *forward, RMmatrix *inv) { RMmatrix m; rmMatrixIdentity(vpm); private_rmComputeViewportMatrix(s->vp, (float)s->w, (float)s->h, vpm); rmMatrixInverse(vpm, vpm_inv); rmMatrixMultiply(&(s->modelView), &(s->projection), &m); *forward = m; rmMatrixInverse(&m, inv); } /* PRIVATE */ static void private_rmDrawBitmapPickableQuads (RMmatrix *vpm, RMmatrix *vpm_invOrig, RMmatrix *forwardOrig, RMmatrix *inv, RMvertex3D *v, int horigin, int vorigin, int bitmap_width, int bitmap_height) { RMvertex3D vnew[4]; private_rmNewWCfromDCOffset(v, -horigin, -vorigin, vnew, vpm, vpm_invOrig, forwardOrig, inv); private_rmNewWCfromDCOffset(v, bitmap_width-horigin, -vorigin, vnew+1, vpm, vpm_invOrig, forwardOrig, inv); private_rmNewWCfromDCOffset(v, bitmap_width-horigin, bitmap_height-vorigin, vnew+2, vpm, vpm_invOrig, forwardOrig, inv); private_rmNewWCfromDCOffset(v, -horigin, bitmap_height-vorigin, vnew+3, vpm, vpm_invOrig, forwardOrig, inv); glBegin(GL_QUADS); glVertex3fv((float *)(vnew)); glVertex3fv((float *)(vnew+1)); glVertex3fv((float *)(vnew+2)); glVertex3fv((float *)(vnew+3)); glEnd(); } /* PRIVATE * draw routine for the app-provided display list primitive */ void rmAppDisplayList OGLPRIMPARMLIST() { #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK) rmGLGetError("rmAppDisplayList() - before calling app display list"); #endif glCallList(p->flags1); /* foil compiler warning */ r = NULL; s = NULL; renderPipe = NULL; rsc = NULL; #if (DEBUG_LEVEL & DEBUG_GLERRORCHECK) rmGLGetError("rmAppDisplayList() - after calling app display list"); #endif } /* PRIVATE * * draw routine for quadmesh routines */ void rmQuadmesh OGLPRIMPARMLIST() { float *nrow0=NULL, *nrow1=NULL; float *vrow0=NULL, *vrow1=NULL; float *crow0=NULL, *crow1=NULL; float *tcrow0 = NULL, *tcrow1 = NULL; int usize, vsize; int *dims; int iv, iu; /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; int listStat; /* vertex, normal, color, tc functions */ void (*vertexfunc)(const float *); void (*normalfunc)(const float *); void (*colorfunc)(const float *); void (*tcfunc)(const float *); int haveMTCs = 0; #if (DEBUG_LEVEL & DEBUG_GLSTATECHECK) private_glStateCheck(s); #endif private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compile warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get texture coord data */ private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); /* get the size info for the qmesh */ private_rmGetBlobData(BLOB_QMESHDIMS_INDEX, p, NULL, NULL, (void *)&dims, NULL); if (p->multiTextureCoordBlobsMask != 0) haveMTCs = 1; vrow0 = v; nrow0 = n; crow0 = c; tcrow0 = tc; usize = dims[0]; vsize = dims[1]; if (vveclen == 3) vertexfunc = rmglVertex3fv; else vertexfunc = rmglVertex2fv; vrow1 = vrow0 + usize*vstride; if (nrow0 != NULL) { nrow1 = nrow0 + usize*nstride; normalfunc = rmglNormal3fv; } else { nrow0 = nrow1 = NULL; normalfunc = glNoOp; } if ((ncolors != usize*vsize) && (cstride != 0)) { rmWarning(" only per-vertex colors are supported with the quadmesh. use quads as an alternative. drawing the quadmesh without colors."); cstride = 0; colorfunc = glNoOp; } else { private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); crow1 = crow0 + (usize * cstride); } if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); tcrow1 = tcrow0 + (usize * tcstride); for (iv = 0; iv < (vsize - 1); iv++) { glBegin(GL_QUAD_STRIP); for (iu = 0; iu < usize; iu++) { (*colorfunc)((float *)(crow1 + (iu * cstride))); (*tcfunc)((float *)(tcrow1 + (iu * tcstride))); (*normalfunc)((float *)(nrow1 + (iu * nstride))); if (haveMTCs) private_dispatchMTCs(renderPipe, p, (iv+1) * usize + iu); (*vertexfunc)((float *)(vrow1 + (iu * vstride))); (*colorfunc)((float *)(crow0 + (iu * cstride))); (*tcfunc)((float *)(tcrow0 + (iu * tcstride))); (*normalfunc)((float *)(nrow0 + (iu * nstride))); if (haveMTCs) private_dispatchMTCs(renderPipe, p, iv * usize + iu); (*vertexfunc)((float *)(vrow0 + (iu * vstride))); } glEnd(); vrow0 = vrow1; vrow1 += usize * vstride; nrow0 = nrow1; nrow1 += usize * nstride; crow0 = crow1; crow1 += usize * cstride; tcrow0 = tcrow1; tcrow1 += usize * tcstride; } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmSpheres OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* radius data */ float *radii = NULL; int rstride, nradii, rveclen; int i, listStat; void (*vertexfunc)(const float *), (*colorfunc)(const float *); float dummy_radius = 0.0; private_lightingStateManip(p, s, rsc, RM_TRUE); private_colorMaterialStateManip(p, s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius data */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (vveclen == 3) vertexfunc = rmglVertex3fv; else if (vveclen == 2) vertexfunc = rmglVertex2fv; if (nradii == 0) { radii = &dummy_radius; rstride = 0; } for (i = 0; i < nverts; i++, v += vstride, radii += rstride, c += cstride) { void rmuSphere(void (*colorfunc) (const float *), float *color, RMvertex3D *p1, float radius, int model_switch, RMpipe *p); if (*radii != 0.0F) { #if 0 /* tmp hack to test improved rendering when transparent. */ /* this actually works surprisingly well..need to promote this approach to a higher level. */ if (s->renderpass == RM_RENDERPASS_TRANSPARENT) { glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); rmuSphere(colorfunc, c, (RMvertex3D *)v, *radii, rmPrimitiveGetModelFlag(p), renderPipe); glCullFace(GL_BACK); rmuSphere(colorfunc, c, (RMvertex3D *)v, *radii, rmPrimitiveGetModelFlag(p), renderPipe); glDisable(GL_CULL_FACE); } else #endif rmuSphere(colorfunc, c, (RMvertex3D *)v, *radii, rmPrimitiveGetModelFlag(p), renderPipe); } else { /* we should be able to detect that the radius values for the entire prim are null and to deal with them differently (more efficiently) than doing them one-by-one here. */ glBegin(GL_POINTS); (*colorfunc)(c); (*vertexfunc)(v); glEnd(); } } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmCones OGLPRIMPARMLIST() { /* for verts */ int vstride, nverts, vveclen; float *v; /* color data */ int cstride, ncolors, cveclen; float *c = NULL; /* radius data */ int rstride, nradii, rveclen; float *radii = NULL; /* cones */ int i, ncones, listStat; float dummy_radius = 0.0; void (*vertexfunc)(const float *), (*colorfunc)(const float *); private_lightingStateManip(p, s, rsc, RM_TRUE); private_colorMaterialStateManip(p, s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); ncones = nverts >> 1; /* each vertex pair defines a cone (base,top) */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius data */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else vertexfunc = rmglVertex2fv; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (radii == NULL) { dummy_radius = 0.0; radii = &dummy_radius; rstride = 0; } for (i = 0; i < ncones; i++, v += 2 * vstride, c += cstride, radii += rstride) { RMvertex3D *p1, *p2; p1 = (RMvertex3D *)v; p2 = (RMvertex3D *)(v + vstride); rmuCone(colorfunc, c, p1, p2, *radii, rmPrimitiveGetModelFlag(p), renderPipe); } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmCylinders OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* radius data */ float *radii = NULL; int rstride, nradii, rveclen; int i, listStat, ncylinders; void (*colorfunc)(const float *); float dummy_radius; private_lightingStateManip(p, s, rsc, RM_TRUE); private_colorMaterialStateManip(p, s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); ncylinders = nverts >> 1; /* each vertex pair defines a cone (base,top) */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius data */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); /* for now, assume 1 radius value per cylinder..so that they're straight (non-tapered) cylinders. also, we assume the layout of vertices is like that of disjoint lines..so that if we have n vertices, we'll render n/2 cylinders. */ if (radii == NULL) { dummy_radius = 0.; radii = &dummy_radius; rstride = 0; } for (i = 0; i < ncylinders; i++, v += 2 * vstride, c += cstride, radii += rstride) { RMvertex3D *p1, *p2; void rmuCylinder(void (*colorfunc)(const float *), float *color, RMvertex3D *p1, RMvertex3D *p2,float radius1, int subdivisions, RMpipe *p); p1 = (RMvertex3D *)v; p2 = (RMvertex3D *)(v + vstride); rmuCylinder(colorfunc, c, p1, p2, *radii, rmPrimitiveGetModelFlag(p), renderPipe); } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmMarkers2D OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* scale data */ float *scales; int sstride, nscales, sveclen; int i, j; void (*vertexfunc)(const float *), (*colorfunc)(const float *); RMinternalMarker2D *m; int nmarker_prims; RMmatrix mx; float m00, m10, m01, m11, m30, m31; /* * 5/11/02 * this code not yet tested - no demo programs that exercise 2d markers. */ private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); if (nverts == 0) return; r = NULL; /* foil compiler warning */ renderPipe = NULL; /* foil compiler warning */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius data */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &sstride, &nscales, (void **)&scales, &sveclen); private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); /* we could check to make sure only 2d vertices are permitted here... */ if (vveclen == 3) vertexfunc = rmglVertex3fv; else vertexfunc = rmglVertex2fv; private_rmPrimitiveGetItem(p, RM_PRIMITIVE_MARKERS2D_PRIM, &nmarker_prims, (void **)&m); rmMatrixIdentity(&mx); /* need to use render state interface here. */ { RMmatrix m; rmMatrixMultiply(&(s->modelView), &(s->projection), &m); rmMatrixInverse(&m, &m); mx.m[0][0] = 1. / m.m[1][1]; mx.m[1][1] = s->aspect_ratio / m.m[0][0]; } m00 = s->model.m[0][0]; m10 = s->model.m[1][0]; m01 = s->model.m[0][1]; m11 = s->model.m[1][1]; m30 = s->model.m[3][0]; m31 = s->model.m[3][1]; if (nmarker_prims != 1) { rmWarning("rmMarkers2D() error: at this time, only one markerprim per RMprimitive is permitted. This restriction will be removed in a future release. Drawing only the first one."); } /* temp - we assume that nmarker_prims == 1. */ for (i = 0; i < nverts; i++, v += vstride, c += cstride, scales += sstride) { float *v2, v3[3]; glPushMatrix(); /* translate to the proper x/y location. this translation accounts for scale, etc in the model-view-projection matrix. the markers will be positioned correctly, but will be rotation-invariant. */ mx.m[3][0] = v[0] * m00 + v[1] * m10 + m30; mx.m[3][1] = v[0] * m01 + v[1] * m11 + m31; glMultMatrixf(&(mx.m[0][0])); (*colorfunc)(c); v2 = (float *)(rmInternalMarker2DGetVerts(m)); glBegin( rmInternalMarker2DGetBFlag(m) ); for (j = 0; j < rmInternalMarker2DGetNpts(m); j++, v2 += 2) { v3[0] = v2[0] * *scales ; v3[1] = v2[1] * *scales ; (*vertexfunc)(v3); } glEnd(); glPopMatrix(); } } /* unit cube geometry */ static RMvertex3D ibox[6][4] = { {{1.0, 0.0, 0.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 0.0}}, /* +x face */ {{0.0, 0.0, 1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 1.0}}, /* -x face */ {{0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 1.0}}, /* +y face */ {{0.0, 0.0, 1.0}, {1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}, /* -y face */ {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}}, /* front face */ {{1.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, {0.0, 1.0, 1.0}, {1.0, 1.0, 1.0}} /* back face */ }; /* unit cube normals */ static RMvertex3D iboxnorms[6] = { {1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, -1.0}, {0.0, 0.0, 1.0} }; /* PRIVATE */ void rmBox3d OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; int i, j, k, listStat; void (*vertexfunc)(const float *), (*colorfunc)(const float *); RMvertex3D *rv; RMvertex3D tbox[6][4]; private_lightingStateManip(p, s, rsc, RM_TRUE); private_colorMaterialStateManip(p, s, rsc); private_textureStateManip(p, s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* an error */ { rmError("rmBox3D() error: box3d primitives MUST have 3d vertices. \n"); return; } rv = (RMvertex3D *)v; for (i = 0; i < (nverts / 2); i++, rv += 2, c += cstride) { float sx, sy, sz; sx = rv[1].x - rv[0].x; sy = rv[1].y - rv[0].y; sz = rv[1].z - rv[0].z; for (k = 0; k < 6; k++) { for (j = 0; j < 4; j++) { tbox[k][j].x = ibox[k][j].x * sx; tbox[k][j].y = ibox[k][j].y * sy; tbox[k][j].z = ibox[k][j].z * sz; } } glPushMatrix(); glTranslatef(rv->x,rv->y,rv->z); /* won't work with 2d vertices */ glBegin(GL_QUADS); (*colorfunc)(c); for (j = 0; j < 6; j++) { /* glColor3fv((float *)&(debug_colors[j])); */ /* debug */ glNormal3fv((float *)&(iboxnorms[j])); for (k = 3; k >= 0; k--) { (*vertexfunc)((float *)&(tbox[j][k])); } } glEnd(); glPopMatrix(); } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmBox3dWire OGLPRIMPARMLIST() { /* for verts */ int vstride, nverts, vveclen; float *v; /* color data */ int cstride, ncolors, cveclen; float *c = NULL; /* box */ int i, listStat; RMvertex3D *rv; void (*vertexfunc)(const float *), (*colorfunc)(const float *); private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); private_textureStateManip(p, s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmSetGLColorFunc(cveclen,ncolors, &colorfunc); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* an error */ { rmError("rmBox3DWire() error: box3dwire primitives MUST have 3d vertices. \n"); return; } rv = (RMvertex3D *)v; for (i = 0; i < (nverts / 2); i++, rv += 2, c += cstride) { float sx, sy, sz; sx = rv[1].x - rv[0].x; sy = rv[1].y - rv[0].y; sz = rv[1].z - rv[0].z; glPushMatrix(); glTranslatef(rv->x, rv->y, rv->z); /* won't work with 2d vertices */ glBegin(GL_LINE_STRIP); (*colorfunc)(c); glVertex3f(0.0F, 0.0F ,0.0F); glVertex3f(sx, 0.0F, 0.0F); glVertex3f(sx, sy, 0.0F); glVertex3f(0.0F, sy, 0.0F); glVertex3f(0.0F, 0.0F, 0.0F); glVertex3f(0.0F, 0.0F, sz); glVertex3f(0.0F, sy, sz); glVertex3f(0.0F, sy, 0.0F); glVertex3f(0.0F, sy, sz); glVertex3f(sx, sy, sz); glVertex3f(sx, sy, 0.0F); glVertex3f(sx, 0.0F, 0.0F); glVertex3f(sx, 0.0F, sz); glVertex3f(sx, sy, sz); glVertex3f(sx, 0.0F, sz); glVertex3f(0.0F, 0.0F, sz); glEnd(); glPopMatrix(); } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmCircle2d OGLPRIMPARMLIST() { /* * TODO: 12/5/99 * circles need to have display-list code added. * * ------ general info * for each of verts, color & texture, we need * 1. stride, for memory accessing * 2. veclen, for proper gl function call * * the main delivery loop is over vertices. we check the number of * colors, norms & textures to ensure that we have either none or * per-vertex of each. */ int i; void (*colorfunc)(const float *); float dummy = 1.0, scale; /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* for radius data */ float *radii= NULL; int rstride, rveclen, nradii; RMmatrix m; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius info */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); if (radii == NULL) { radii = &dummy; rstride = 0; nradii = 0; } /* * do validity checking: * 1. ncolors must be 0 or equal to nverts/2 * 2. ntcoords must be 0 or equal to nverts/2 */ if (ncolors != 0 && ncolors != nverts) { rmError("error: rmCircle2D() only per-circle color is supported. \n"); return; } private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); rmMatrixMultiply(&(s->model), &(s->projection), &m); rmMatrixMultiply(&m, &(s->vpm), &m); scale = RM_MIN(m.m[0][0], m.m[1][1]); for (i = 0; i < nverts; i++, v += vstride, c+= cstride, radii += rstride) { int subdivisions = 9; RMmatrix m; glPushMatrix(); rmMatrixIdentity(&m); m.m[0][0] = m.m[1][1] = m.m[2][2] = *radii; m.m[3][0] = v[0]; m.m[3][1] = v[1]; m.m[3][2] = 0.0F; glMultMatrixf((const GLfloat *)&(m.m[0][0])); (*colorfunc)(c); subdivisions = *radii * scale; /* this formulation results in line segments which are about 3 pixels long */ rmuCircle2d(subdivisions); glPopMatrix(); } r = NULL; /* foil compiler warning */ renderPipe = NULL; /* foil compiler warning */ } /* PRIVATE * * because we use glRect() for drawing 2D boxes, the use of texture coords is not supported */ void rmBox2d OGLPRIMPARMLIST() { /* for verts */ int vstride, nverts, vveclen; float *v, *v2; /* color data */ int cstride, ncolors, cveclen; int i, nboxes, listStat; float *c = NULL; void (*vertexfunc)(const float *), (*colorfunc)(const float *); private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* * do validity checking: * 1. ncolors must be 0 or equal to nverts/2 */ if ((ncolors != 0) && (ncolors != (nverts/2))) { rmError("error: rmBox2D() only per-box color is supported. \n"); return; } if (vveclen == 3) /* why check for 3D vertices on 2D boxes? */ vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); nboxes = nverts / 2; v2 = v + vstride; for (i = 0; i < nboxes; i++, c += cstride) { (*colorfunc)(c); glRectfv((GLfloat *)(v), (GLfloat *)(v2)); v = v2 += vstride; v2 += vstride; } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmEllipse2d OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* for radius data */ float *radii = NULL; int rstride, rveclen, nradii; /* for rotation data */ float *rotdata; int rotstride, rotveclen, nrots; int i; float scale; RMmatrix m; void (*colorfunc)(const float *); float dummy_rotate = 0.0; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get radius info */ private_rmGetBlobData(BLOB_SCALE_INDEX, p, &rstride, &nradii, (void **)&radii, &rveclen); /* rotation data is stuffed into the blob otherwise used for indices. if we ever want to do indexed ellipses (?), then we'll have to use a different data blob. */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &rotstride, &nrots, (void **)&rotdata, &rotveclen); if (rotdata == NULL) { rotdata = &dummy_rotate; rotstride = 0; } private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); rmMatrixMultiply(&(s->model), &(s->projection), &m); rmMatrixMultiply(&m, &(s->vpm), &m); scale = RM_MIN(m.m[0][0], m.m[1][1]); /* careful on rveclen: we assume radius pairs w/o having to explicitly set veclen on the blob */ for (i = 0; i < nverts; i++, v += vstride, c+= cstride, radii += 2, rotdata += rotstride) { RMmatrix m; int subdivisions; float rval; float cval, sval; glPushMatrix(); /* assume input in degrees */ { int idegrees; /* * input rotation value is expressed in terms of 10th's * of degrees. our cos/sin table resolution is 1 degree, so * we just throw away the additional resolution by dividing * by 10. */ idegrees = (int)(*rotdata * 0.10F); idegrees = idegrees % 360; idegrees = (idegrees < 0) ? idegrees + 360 : idegrees; cval = cos_table[idegrees]; sval = sin_table[idegrees]; } rmMatrixIdentity(&m); m.m[0][0] = m.m[1][1] = cval; m.m[0][1] = sval; m.m[1][0] = -sval; m.m[3][0] = v[0]; m.m[3][1] = v[1]; m.m[3][2] = 0.0F; glMultMatrixf((const GLfloat *)&(m.m[0][0])); (*colorfunc)(c); rval = RM_MAX(radii[0], radii[1]); /* radii must be defined */ subdivisions = rval * scale; /* this formulation results in line segments which are about 3 pixels long */ rmuEllipse2d(subdivisions, radii[0], radii[1]); glPopMatrix(); } r = NULL; /* foil compiler warning */ renderPipe = NULL; /* foil compiler warning */ } /* PRIVATE */ void rmSprite OGLPRIMPARMLIST() { /* * display listing is handled a little differently for sprites & * bitmaps. the display list is associated with the RMimage object, * not the RMprimitive based upon the observation that the image * data itself is a higher-payload object than a vertex or two, * and to allow for this code to deal with weird raster position * placement issues that come up in OpenGL when drawing image * based data. */ /* for verts */ float *v; int vstride, nverts, vveclen; void (*vertexfunc)(const float *); int i; RMimage **sprite_list, *sprite; RMmatrix vpm, vpm_inv, forward, inv; float horigin = 0.0F, vorigin = 0.0F; GLenum format, gltype; RMenum hjustify, vjustify; /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); private_lightingStateManip(p, s, rsc, RM_FALSE); if (vveclen == 2) vertexfunc = rmglRasterPos2fv; else /* assume vincr = 3 */ vertexfunc = rmglRasterPos3fv; /* get justification settings specified for text */ private_rmStateGetTextJustify(s, &hjustify, &vjustify); /* * now, grab the sprites. note that indexed sprites are not * currently supported. */ private_rmPrimitiveGetItem(p, RM_PRIMITIVE_SPRITES, &i, (void **)&sprite_list); private_rmSetupBitmapPickMatrices(s, &vpm, &vpm_inv, &forward, &inv); for (i = 0; i < nverts; i++, v += vstride) { float xzoom, yzoom; sprite = sprite_list[i]; if (sprite == NULL) rmError("error in rmSprite() - NULL image pointer encountered in an RM_SPRITE primitive. \n"); rmImageGetPixelZoom(sprite, &xzoom, &yzoom); horigin = 0.0F; if (hjustify == RM_CENTER) horigin = (float)sprite->w * xzoom * 0.5F; else if (hjustify == RM_RIGHT) horigin = (float)sprite->w * xzoom; vorigin = 0.0F; if (vjustify == RM_CENTER) vorigin = (float)sprite->h * yzoom * 0.5F; else if (vjustify == RM_TOP) vorigin = (float)sprite->h * yzoom; if (s->rendermode == GL_SELECT || SHOW_PICKABLE_QUADS) { /* * in pick mode, we have to generate some pickable geometry * since glDrawPixels doesn't generate anything we can pick. * This hunk of code draws pickable geometry. */ int w, h; RMvertex3D t; w = sprite->w * xzoom; h = sprite->h * yzoom; t.x = v[0]; t.y = v[1]; t.z = (vveclen == 2) ? 0.0F : v[2]; private_rmDrawBitmapPickableQuads(&vpm, &vpm_inv, &forward,&inv, &t, horigin, vorigin, w, h); } if ((s->rendermode != GL_SELECT) || (SHOW_PICKABLE_QUADS)) { /* * In rendering mode, compute the pixel location of the * vertex value associated with the sprite. The final pixel * coordinate will reflect the transformation of world * coordinates to pixel coordinates as well as the offset * resulting from the requested justification. */ RMvertex3D dc; RMvertex3D drawVertex; RMvertex3D t; float xmove=0.0F, ymove=0.0F; int adjustRasterpos = 0; t.x = v[0]; t.y = v[1]; t.z = (vveclen == 2) ? 0.0F : v[2]; if (vveclen == 2) private_rmDCFromWC2(&t, &dc, 1, s); else private_rmDCFromWC3(&t, &dc, 1, s); dc.x -= horigin; dc.y -= vorigin; /* check to see if the requested vertex position is outside the viewport. */ if ((dc.x <= 0.0F) || (dc.y <= 0.0F) || /* off to left or bottom */ (dc.x >= s->w) || (dc.y >= s->h)) /* off to top or right */ { RMvertex3D newDC; float dx, dy; /* put the new vertex at the center of the screen */ newDC.x = (float)(s->w) * 0.5; newDC.y = (float)(s->h) * 0.5; newDC.z = dc.z; /* what is the pixel delta from current vertex location in pixel coordinates to pixel coordinates of proposed new vertex? */ dx = newDC.x - dc.x; dy = newDC.y - dc.y; /* * compute the new world coordinate. This approach produces * the correct projected screen location, but the z-coordinate * isn't exactly correct. If you have fog turned on, you may * see a discontinous shade change when the sprite crosses * over the left or bottom window boundary. */ private_rmNewWCfromDCOffset((RMvertex3D *)v, dx, dy, &drawVertex, &vpm, &vpm_inv, &forward, &inv); xmove = -1.0F * dx; ymove = -1.0F * dy; adjustRasterpos = 1; } else { /* * the vertex with justification lies within the viewport. * compute a new world coordinate for use in drawing * the sprite. */ private_rmNewWCfromDCOffset(&t, -horigin, -vorigin, &drawVertex, &vpm, &vpm_inv, &forward, &inv); adjustRasterpos = 0; } (*vertexfunc)((GLfloat *)&drawVertex); /* warning!! generates a bitmap feedback token!! */ if (adjustRasterpos == 1) glBitmap(0, 0, 0, 0, (GLfloat)xmove, (GLfloat)ymove, NULL); glPixelZoom ((GLfloat)xzoom, (GLfloat)yzoom); format = private_rmImageGetOGLFormat(sprite); gltype = private_rmImageGetOGLType(sprite); private_glDrawPixels(private_rmImageGetWidth(sprite), private_rmImageGetHeight(sprite), format, gltype, (const GLvoid *)(private_rmImageGetPixelData(sprite)), sprite); /* all sprite/image display list stuff was ripped out during the SBIR work. */ #if 0 /* try to build a display list for this image */ if (private_rmImageGetDirtyFlag(sprite) == RM_TRUE) { private_rmImageSetDirtyFlag(sprite,RM_FALSE); if (sprite->d1 != -1) { glDeleteLists(sprite->d1, 1); sprite->d1 = -1; } } if (sprite->d1 == -1) { #if DO_LISTS sprite->d1 = glGenLists(1); glNewList(sprite->d1, GL_COMPILE_AND_EXECUTE); #endif /* enable pixel transfer mode if there's a vismap present */ private_glDrawPixels(private_rmImageGetWidth(sprite), private_rmImageGetHeight(sprite), format, gltype, (const GLvoid *)(private_rmImageGetPixelData(sprite)), sprite); /* 10/5/200 all RMimage display list stuff removed during SBIR work.*/ #if DO_LISTS glEndList(); #endif } else glCallList(sprite->d1); #endif } } r = NULL; /* foil compiler warning */ renderPipe = NULL; /* foil compiler warning */ } /* PRIVATE */ void rmBitmap OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; int i; void (*vertexfunc)(const float *); void (*colorfunc)(const float *); RMmatrix vpm, vpm_inv, forward, inv; RMenum hjustify, vjustify; GLfloat horigin, vorigin; int nbitmaps; RMbitmap **bmp_list, *bmp; /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (vveclen == 2) vertexfunc = rmglRasterPos2fv; else /* assume vincr = 3 */ vertexfunc = rmglRasterPos3fv; private_rmStateGetTextJustify(s, &hjustify, &vjustify); private_rmPrimitiveGetItem(p, RM_PRIMITIVE_BITMAPS, &nbitmaps, (void **)&bmp_list); if (nbitmaps != nverts) { rmError(" the number of bitmaps is not the same as the number of vertices in a bitmap primitive. \n"); return; } if (s->rendermode == GL_SELECT || SHOW_PICKABLE_QUADS) { /* * in select mode, we're going to draw a bunch of quads rather * than text bitmaps: bitmaps are not pickable, whereas quads * are. in order to do that, we need some matrices. */ private_rmSetupBitmapPickMatrices(s, &vpm, &vpm_inv, &forward, &inv); } for (i = 0; i < nverts; i++, v += vstride, c += cstride) { int bw, bh, bytes; bmp = bmp_list[i]; rmBitmapGetSize(bmp, &bw, &bh, &bytes); if (c) (*colorfunc)(c); horigin = 0.0F; if (hjustify == RM_CENTER) horigin = (GLfloat)(bw >> 1); else if (hjustify == RM_RIGHT) horigin = (GLfloat)(bw); vorigin = 0.0F; if (vjustify == RM_CENTER) vorigin = (GLfloat)(bh >> 1); else if (vjustify == RM_TOP) vorigin = (GLfloat)(bh); if (s->rendermode == GL_SELECT || SHOW_PICKABLE_QUADS) { /* in select mode, draw quads using the matrices we computed earlier */ RMvertex3D t; t.x = v[0]; t.y = v[1]; if (vveclen == 2) t.z = 0.0F; else t.z = v[2]; private_rmDrawBitmapPickableQuads(&vpm, &vpm_inv, &forward, &inv, &t, horigin, vorigin, bw, bh); } if ((s->rendermode != GL_SELECT) || (SHOW_PICKABLE_QUADS)) { /* otherwise, we're in normal draw mode. spit out the bitmaps */ (*colorfunc)((float *)c); (*vertexfunc)((float *)v); glBitmap((GLsizei)(bw), (GLsizei)(bh), horigin, vorigin, (GLfloat) 0.0F, (GLfloat)0.0F, (const GLubyte *)(private_rmBitmapGetPixelData(bmp))); } } r = NULL; /* foil compiler warning */ renderPipe = NULL; /* foil compiler warning */ } /* PRIVATE */ void rmIndexedBitmap OGLPRIMPARMLIST() { /* * todo: display list stuff. */ rmError(" rmIndexedBitmap is broken. \n"); /* foil compiler warning */ r = NULL; p = NULL; s = NULL; renderPipe = NULL; rsc = NULL; } /* PRIVATE * * draw routine for indexed text prims */ void rmIndexedText OGLPRIMPARMLIST() { rmText(p, r, s, renderPipe, rsc); } /* PRIVATE * * draw routine for text prims */ void rmText OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* index data */ int *indices, istride, nindices, iveclen; int i, j; void (*vertexfunc)(const float *); void (*colorfunc)(const float *); RMenum hjustify, vjustify; int do_indices; RMtextPrim *parray; int numtextprims; RMtextProps *tp; RMfontRegistry *fr; int usingTempTextProps = 0; RMmatrix vpm, vpm_inv, forward, inv; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get index data */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); if (indices != NULL) do_indices = 1; else do_indices = 0; if (vveclen == 3) vertexfunc = rmglRasterPos3fv; else vertexfunc = rmglRasterPos2fv; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (private_rmPrimitiveGetText(p, &numtextprims, &parray) == RM_WHACKED) { rmWarning(" rmText() rendering function error: the input primitive has no text strings defined. \n"); return; /* 9/29/03 - need to verify that a simple return here is OK. */ } /* loop to verify that we have proper width & height info using the current RMtextProps info. */ tp = s->textProps; if (tp == NULL) { tp = private_rmDefaultTextProps(renderPipe); usingTempTextProps = 1; } /* * 10/2000 - thread-safety work: * 1. private_rmPrepareBitmapFont will conditionally build display * lists for the English alphabet using the requested font and style * 2. get the rmFontRegistry handle for that font family on the * named RMpipe - it contains display list indices used for * drawing bitmaps. */ private_rmPrepareBitmapFont(tp, renderPipe); /* build display lists */ fr = private_rmFontRegistryEntry(tp->fontEnum, tp->sizeEnum, tp->italicEnum, tp->boldEnum, renderPipe->contextCache->pipeFontRegistry); /* assertion check on "fr" here? */ for (i = 0; i < numtextprims; i++) { /* * 10/2000 TODO * the following routine computes the character width * and height of a character string when rendered given * font family and style info. this info is needed for * picking (selection) and for justification. in an * earlier (non thread-safe) version of OpenRM, we cached * some info in the RMtextPrim. we need to update this * code so that we need not recompute character width * and height during each frame rendering. */ int indx; if (do_indices == 1) indx = indices[i]; else indx = i; private_rmTextPrimComputeCW(parray + indx, fr, renderPipe); } private_rmStateGetTextJustify(s, &hjustify, &vjustify); /* need w,h of the bitmaps in order to do justification & picking */ if (s->rendermode == GL_SELECT || SHOW_PICKABLE_QUADS) { private_rmSetupBitmapPickMatrices(s, &vpm, &vpm_inv, &forward, &inv); } for (i = 0, j = 0; i < nverts; i++, v += vstride, c += cstride) { int bw, bh; int horigin = 0, vorigin = 0; RMtextPrim *pt; if (do_indices == 1) pt = parray + indices[i]; else pt = parray + i; bw = pt->bw; bh = pt->bh; horigin = 0.0F; if (hjustify == RM_CENTER) horigin = (GLfloat)(bw >> 1); else if (hjustify == RM_RIGHT) horigin = (GLfloat)(bw); vorigin = 0.0F; if (vjustify == RM_CENTER) vorigin = (GLfloat)(bh >> 1); else if (vjustify == RM_TOP) vorigin = (GLfloat)(bh); if (s->rendermode == GL_SELECT || SHOW_PICKABLE_QUADS) { RMvertex3D tv; tv.x = v[0]; tv.y = v[1]; /* 6/12/02 add code so that src z-coord is used if present. this fixes a picking bug. */ if (vveclen == 2) tv.z = 0.0; else tv.z = v[2]; private_rmDrawBitmapPickableQuads(&vpm, &vpm_inv, &forward, &inv, &tv, horigin, vorigin, bw, bh); } /* end selection mode */ if ((s->rendermode == GL_RENDER) || SHOW_PICKABLE_QUADS) { char *str; (*colorfunc)(c); (*vertexfunc)(v); str = pt->string; { if (horigin != 0 || vorigin != 0) { glBitmap(0, 0, 0, 0, -horigin, -vorigin, NULL); } glPushAttrib(GL_LIST_BIT); glListBase(fr->listbase - 32); glCallLists(strlen(str), GL_UNSIGNED_BYTE, str); glPopAttrib(); } } if (do_indices == 1) j++; } /* loop over nverts */ if (usingTempTextProps == 1) rmTextPropsDelete(tp); r = NULL; /* foil compiler warning */ } /* PRIVATE */ void rmIndexedTriangleFan OGLPRIMPARMLIST() { void (*vertexfunc)(const float *), (*colorfunc)(const float *); void (*tcfunc)(const float *), (*normalfunc)(const float *); /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; /* indices */ int *indices; int nindices, iveclen, istride; int i, listStat; /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get indices */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); if ((nindices == 0) || (nverts == 0)) /* check for early termination */ return; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; if (n != NULL) /* assume normals are in R3*/ normalfunc = rmglNormal3fv; else normalfunc = glNoOp; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < nindices; i++) { int indx = indices[i]; (*colorfunc)(c + (indx * cstride)); (*normalfunc)(n + (indx * nstride)); (*tcfunc)(tc + (indx * tcstride)); (*vertexfunc)(v + (indx * vstride)); } glEnd(); private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmIndexedQuads OGLPRIMPARMLIST() { void (*vertexfunc)(const float *), (*colorfunc)(const float *); void (*tcfunc)(const float *), (*normalfunc)(const float *); /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; /* indices */ int *indices; int nindices, iveclen, istride; int i, listStat; /* get indices */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); if ((nindices == 0) || (nverts == 0)) /* check for early termination */ return; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; if (n != NULL) /* assume normals are in R3*/ normalfunc = rmglNormal3fv; else normalfunc = glNoOp; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); glBegin(GL_QUADS); for (i = 0; i < nindices; i++) { int indx = indices[i]; (*colorfunc)(c + (indx * cstride)); (*normalfunc)(n + (indx * nstride)); (*tcfunc)(tc + (indx * tcstride)); (*vertexfunc)(v + (indx * vstride)); } glEnd(); private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmIndexedTriangles OGLPRIMPARMLIST() { void (*vertexfunc)(const float *), (*colorfunc)(const float *); void (*tcfunc)(const float *), (*normalfunc)(const float *); /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; /* indices */ int *indices; int nindices, iveclen, istride; /* multitexturing */ int haveMTCs = 0; int i, listStat; /* get indices */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); if ((nverts == 0) || (nindices == 0)) /* check for early termination */ return; r = NULL; /* foil compiler warning */ private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; if (n != NULL) /* assume normals are in R3 */ normalfunc = rmglNormal3fv; else normalfunc = glNoOp; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); if (p->multiTextureCoordBlobsMask != 0) haveMTCs = 1; glBegin(GL_TRIANGLES); for (i = 0; i < nindices; i++) { int indx = indices[i]; (*colorfunc)(c + (indx * cstride)); (*normalfunc)(n + (indx * nstride)); (*tcfunc)(tc + (indx * tcstride)); if (haveMTCs) private_dispatchMTCs(renderPipe, p, indx); (*vertexfunc)(v + (indx * vstride)); } glEnd(); private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmIndexedQuadStrip OGLPRIMPARMLIST() { void (*vertexfunc)(const float *), (*colorfunc)(const float *); void (*tcfunc)(const float *), (*normalfunc)(const float *); /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; /* indices */ int *indices; int nindices, iveclen, istride; int i, listStat; /* get indices */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); if ((nverts == 0) || (nindices == 0)) /* check for early termination */ return; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; if (n != NULL) /* assume normals are in R3 */ normalfunc = rmglNormal3fv; else normalfunc = glNoOp; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); glBegin(GL_QUAD_STRIP); for (i = 0; i < nindices; i++) { int indx = indices[i]; (*colorfunc)(c + (indx * cstride)); (*normalfunc)(n + (indx * nstride)); (*tcfunc)(tc + (indx * tcstride)); (*vertexfunc)(v + (indx * vstride)); } glEnd(); private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ void rmIndexedTriangleStrip OGLPRIMPARMLIST() { void (*vertexfunc)(const float *), (*colorfunc)(const float *); void (*tcfunc)(const float *), (*normalfunc)(const float *); /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; /* indices */ int *indices; int nindices, iveclen, istride; int i, listStat; /* get indices */ private_rmGetBlobData(BLOB_INDEX_INDEX, p, &istride, &nindices, (void **)&indices, &iveclen); /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); if ((nverts == 0) || (nindices == 0)) /* check for early termination */ return; private_colorMaterialStateManip(p, s, rsc); private_lightingStateManip(p, s, rsc, RM_FALSE); listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); if (vveclen == 3) vertexfunc = rmglVertex3fv; else /* assume vveclen == 2 */ vertexfunc = rmglVertex2fv; if (n != NULL) /* assume normals are in R3 */ normalfunc = rmglNormal3fv; else normalfunc = glNoOp; private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); glBegin(GL_TRIANGLE_STRIP); for (i = 0; i < nindices; i++) { int indx = indices[i]; (*colorfunc)(c + (indx * cstride)); (*normalfunc)(n + (indx * nstride)); (*tcfunc)(tc + (indx * tcstride)); (*vertexfunc)(v + (indx * vstride)); } glEnd(); private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE * * 8/14/04 - updated code to accommodate per-face colors, normals, etc. * When optional data items (colors, normals) are specified per-vertex, * then we use vertex arrays. Otherwise, we use a slower path through * OpenGL. */ void rmQuads OGLPRIMPARMLIST() { /* for verts */ float *v; int vstride, nverts, vveclen; /* color data */ float *c = NULL; int cstride, ncolors, cveclen; /* texture coord data */ float *tc = NULL; int tcstride; int ntc, tcveclen; /* normals */ float *n; int nstride, nveclen, nnormals; int listStat; int perVertexColor=0, perFaceColor=0; int perVertexNormals=0, perFaceNormals=0; int useVertexArrays=1; int haveMTCs = 0; private_lightingStateManip(p,s, rsc, RM_FALSE); private_colorMaterialStateManip(p,s, rsc); listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p); if (listStat == 0) return; r = NULL; /* foil compiler warning */ /* get vertex data */ private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen); /* get color data */ private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen); /* get texture coord data - NOTE: (2/2000) tc's & quads not tested */ private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen); /* get normals info */ private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen); /* * check to see which code path to use */ if (ncolors != 0) { if (ncolors == nverts) perVertexColor = 1; else if ((ncolors << 2) == nverts) { perFaceColor = 1; useVertexArrays = 0; } } if (nnormals != 0) { if (nnormals == nverts) perVertexNormals = 1; else if ((nnormals << 2) == nverts) { perFaceNormals = 1; useVertexArrays = 0; } } if (p->multiTextureCoordBlobsMask != 0) { useVertexArrays = 0; /* slow path until we figure out how to use vertex arrays with MTCs. */ haveMTCs = 1; } if (useVertexArrays == 1) { private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0); glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v); if (ncolors != 0) glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c); if (ntc != 0) glTexCoordPointer(tcveclen, GL_FLOAT,sizeof(float) * tcstride, (const GLvoid *)tc); if (nnormals != 0) glNormalPointer(GL_FLOAT, sizeof(float) * nstride, (const GLvoid *)n); glDrawArrays(GL_QUADS, 0, nverts); } else { /* vertex, normal, color, tc functions */ void (*vertexfunc)(const float *); void (*normalfunc)(const float *); void (*colorfunc)(const float *); void (*tcfunc)(const float *); int i; if (vveclen == 3) vertexfunc = rmglVertex3fv; else vertexfunc = rmglVertex2fv; if (nnormals != 0) normalfunc = rmglNormal3fv; else normalfunc = glNoOp; if (ncolors != 0) private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc); else colorfunc = glNoOp; if (ntc == 0) tcfunc = glNoOp; else private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc); glBegin(GL_QUADS); for (i=0; i < nverts; i++) { if (nnormals != 0) (*normalfunc)(n), n += nstride; if (ncolors != 0) (*colorfunc)(c), c += cstride; if (ntc != 0) (*tcfunc)(tc), tc += tcstride; if (haveMTCs) private_dispatchMTCs(renderPipe, p, i); (*vertexfunc)(v); i++; v += vstride; if (nnormals != 0) (*normalfunc)(n), n += nstride; if (perVertexColor) (*colorfunc)(c), c += cstride; if (ntc != 0) (*tcfunc)(tc), tc += tcstride; if (haveMTCs) private_dispatchMTCs(renderPipe, p, i); (*vertexfunc)(v); i++; v += vstride; if (nnormals != 0) (*normalfunc)(n), n += nstride; if (perVertexColor) (*colorfunc)(c), c += cstride; if (ntc != 0) (*tcfunc)(tc), tc += tcstride; if (haveMTCs) private_dispatchMTCs(renderPipe, p, i); (*vertexfunc)(v); i++; v += vstride; if (nnormals != 0) (*normalfunc)(n), n += nstride; if (perVertexColor) (*colorfunc)(c), c += cstride; if (ntc != 0) (*tcfunc)(tc), tc += tcstride; if (haveMTCs) private_dispatchMTCs(renderPipe, p, i); (*vertexfunc)(v); i++; v += vstride; } glEnd(); } private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat); } /* PRIVATE */ /* * dispatch */ void private_dispatchMTCs(RMpipe *pipe, RMprimitive *prim, int vertexIndx) { int i; int offset; int mask; RMprimitiveDataBlob *b; mask = prim->multiTextureCoordBlobsMask; for (i=0; (i < RM_MAX_MULTITEXTURES) && (mask != 0); i++) { if (mask & 0x1) { GLint target = GL_TEXTURE0_ARB + i; float *f; b = prim->multiTextureCoordBlobs + i; offset = private_rmBlobGetStride(b) / sizeof(float) * vertexIndx; f = (float *)private_rmBlobGetData(b) + offset; switch (private_rmBlobGetVeclen(b)) { case 1: (*(pipe->caps->multiTexCoord1fvARB))(target, f); break; case 2: (*(pipe->caps->multiTexCoord2fvARB))(target, f); break; case 3: (*(pipe->caps->multiTexCoord3fvARB))(target, f); break; default: printf(" private_dispatchMTS - blob vector length is not 1, 2 or 3. \n"); break; } } mask = mask >> 1; } } /* EOF */