/* * Copyright (C) 2001-2003, R3vis Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; 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/gpl.html. * * Contributor(s): * Wes Bethel, R3vis Corporation, Marin County, California * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: fogtest.c,v 1.6 2004/01/17 03:45:46 wes Exp $ * Version: $Name: OpenRM-1-5-2-RC1 $ * $Revision: 1.6 $ * $Log: fogtest.c,v $ * Revision 1.6 2004/01/17 03:45:46 wes * Added command-line argument [-fr NN] to enable constant-rate rendering. * * Revision 1.5 2003/04/13 18:13:23 wes * Updated copyright dates. * * Revision 1.4 2003/01/27 05:07:07 wes * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL. * * Revision 1.3 2003/01/16 22:22:45 wes * Updated all source files to reflect new organization of header files: all * headers that were formerly located in include/rmaux, include/rmv and * include/rmi are now located in include/rm. * * Revision 1.2 2002/06/17 00:37:00 wes * Updated copyright line. * * Revision 1.1 2001/10/15 00:23:22 wes * Initial entry. * */ #define NUM_MARKERS 5 #define NUM_LINES 3 #define NUM_POSTS 3 #include <stdio.h> #ifdef RM_X #include <strings.h> #endif #include <stdlib.h> #include <rm/rm.h> #include <rm/rmv.h> #include <rm/rmi.h> #include <rm/rmaux.h> #include "procmode.h" static int imgWidth=640, imgHeight=512; static RMnode *myRoot=NULL; static RMnode *myPostsRoot=NULL; static int doFog = 1; static int frameRate = -1; /* * this is an array of pointers to the post primitives. we create * the array inside the addPostsToFloor() routine, and use the * pointers later during the traversal callback. */ static RMprimitive **postPrims=NULL; static int *postPrimIndices=NULL; static float *lastDistance=NULL; void usage(char *progName) { char buffer[1024]; sprintf(buffer," usage: %s [-w imgWidth (default=640)] [-h imgHeight (default=512)] [-nf (turn off fog)] \n ",progName); rmWarning(buffer); } int parseArgs(int ac, char *av[]) { int i; i = 1; ac--; while (ac > 0) { if (strcmp(av[i],"-w") == 0) { i++; ac--; sscanf(av[i],"%d",&imgWidth); } else if (strcmp(av[i],"-h") == 0) { i++; ac--; sscanf(av[i],"%d",&imgHeight); } else if (strcmp(av[i],"-nf") == 0) { doFog = 0; } else if (strcmp(av[i],"-fr") == 0) { int j; i++; ac--; sscanf(av[i],"%d", &j); if (j > 0) frameRate = j; } else { usage(av[0]); return(-1); } i++; ac--; } return(1); } /* * the scene for this demo program consists of a floor, and * some simple geometric objects. the floor is positioned at * z=0, and is the x/y plane. the range of the floor is from * (-10,-10,0) to (10,10,0). a simple auto-gen'ed texture is * applied to the floor (a checkered pattern). * * the initial location of the camera is at (0,0,1) looking * in the (0,1,0) direction. */ void addFloorTileTexture(RMnode *n) { /* * create an RMimage consisting of a simple checkered pattern, * then create an RMtexture using the new image, add the * texture as a scene parm to the node */ #define USE_MIPMAPS 0 #if USE_MIPMAPS RMimage **mipMaps; int nmipmaps; #endif RMimage *t; int i,j; unsigned char *dst; RMcolor4D blue={0.1,0.1,0.4,1.0}; RMcolor4D white={0.9,0.9,0.9,1.0}; RMtexture *texture; unsigned char ubBlue[4], ubWhite[4]; int rows=256,cols=256; t = rmImageNew(2, cols, rows, 1, RM_IMAGE_RGBA, RM_UNSIGNED_BYTE, RM_COPY_DATA); dst = (unsigned char *)rmImageGetPixelData(t); ubBlue[0] = (unsigned char)(blue.r * 255.0); ubBlue[1] = (unsigned char)(blue.g * 255.0); ubBlue[2] = (unsigned char)(blue.b * 255.0); ubBlue[3] = (unsigned char)(blue.a * 255.0); ubWhite[0] = (unsigned char)(white.r * 255.0); ubWhite[1] = (unsigned char)(white.g * 255.0); ubWhite[2] = (unsigned char)(white.b * 255.0); ubWhite[3] = (unsigned char)(white.a * 255.0); for (j=0;j<rows;j++) { for (i=0;i<cols;i++) { if (j & 0x08) { if (i & 0x08) memcpy(dst,ubBlue,4); else memcpy(dst,ubWhite,4); } else { if (i & 0x08) memcpy(dst,ubWhite,4); else memcpy(dst,ubBlue,4); } dst += 4; } } texture = rmTextureNew(2); #if USE_MIPMAPS nmipmaps = rmuImageBuildMipmaps(t,&mipMaps,RM_SOFTWARE); rmTextureSetImages(texture,mipMaps, nmipmaps, RM_FALSE); rmTextureSetFilterMode(texture,GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST); #else rmTextureSetImages(texture, &t, 1, RM_FALSE); /* * set the OpenGL texture minification mode to GL_LINEAR, * texture magnification mode to GL_NEAREST. see man glTexParameteri. * * when the following line of code is commented out, we're using * the default OpenGL texture filter modes which are GL_NEAREST, GL_NEAREST */ /* rmTextureSetFilterMode(texture,GL_LINEAR, GL_NEAREST); */ #endif rmNodeSetSceneTexture(n,texture); rmTextureDelete(texture, RM_FALSE); } void addFloor(RMnode *addToNode, RMvertex3D *fmin, RMvertex3D *fmax) { RMnode *floor; RMprimitive *p; RMvertex3D v[4]; RMvertex2D tc[4]; RMvertex3D n; floor = rmNodeNew("floor",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); p = rmPrimitiveNew(RM_QUADS); /* * note that we're using the min z coordinate for the entire surface. */ v[0].x = fmin->x; tc[0].x = 0.0; v[0].y = fmin->y; tc[0].y = 0.0; v[0].z = fmin->z; v[1].x = fmax->x; tc[1].x = 1.0; v[1].y = fmin->y; tc[1].y = 0.0; v[1].z = fmin->z; v[2].x = fmax->x; tc[2].x = 1.0; v[2].y = fmax->y; tc[2].y = 1.0; v[2].z = fmin->z; v[3].x = fmin->x; tc[3].x = 0.; v[3].y = fmax->y; tc[3].y = 1.; v[3].z = fmin->z; n.x = n.y = 0.; n.z = 1.0; rmPrimitiveSetVertex3D(p,4,v,RM_COPY_DATA,NULL); rmPrimitiveSetNormal3D(p,1,&n,RM_COPY_DATA,NULL); rmPrimitiveSetTexcoord2D(p,4,tc,RM_COPY_DATA,NULL); addFloorTileTexture(floor); rmNodeAddPrimitive(floor,p); rmNodeAddChild(addToNode,floor); } RMimage * readAVSImage(char *fname) { RMimage *t; int w,h; int i,j,indx, indx2; FILE *f; unsigned char *static_image_data; f = fopen(fname,"r"); if (f == NULL) { fprintf(stderr," can't open the AVS image file named <%s> \n",fname); return(NULL); } { unsigned char buf[4]; read(fileno(f),(void *)buf,4); w = buf[3] | (buf[2] << 8); read(fileno(f),(void *)buf,4); h = buf[3] | (buf[2] << 8); } /* sanity check w,h */ if ((w < 0) || (w > 4096) || (h < 0) || (h > 4096)) { fprintf(stderr," dubious image dimensions: %d, %d, aborting image read. \n",w,h); fclose(f); return(NULL); } static_image_data = (unsigned char *)malloc(sizeof(unsigned char)*w*h*4); /* this reads everything at once */ read(fileno(f),(void *)static_image_data,w*h*4); fclose(f); #define ONE_OVER_255 0.0039215686 /* hack to change from ARGB to RGBA */ indx = 0; indx2 = 3; for (i=0;i<w*h;i++) { unsigned char t; t = static_image_data[indx]; for (j=0;j<3;j++) static_image_data[indx+j] = static_image_data[indx+j+1]; static_image_data[indx+3] = 0xFF; indx += 4; } /* * problem w/RGB mode in glDrawPixels . it looks like it wants all * the image data to be 4-byte word aligned. */ t = rmImageNew(2,w,h,1,RM_IMAGE_RGBA, RM_UNSIGNED_BYTE, RM_COPY_DATA); rmImageSetPixelData(t, (void *)static_image_data, RM_COPY_DATA, NULL); rmImageMirror(t,RM_IMAGE_MIRROR_HEIGHT); free((void *)static_image_data); return(t); } void addCamera(RMnode *addToNode, int imgWidth, int imgHeight) { RMcamera3D *c = rmCamera3DNew(); RMvertex3D eye, at, up; float fov, hither, yon; eye.x = eye.y = 0.; eye.z = 1.0; at = eye; at.y += 1.0; up.x = up.y = 0.; up.z = 1.; fov = 45.0F; hither = 0.25; yon = 20.0; rmCamera3DSetProjection(c,RM_PROJECTION_PERSPECTIVE); rmCamera3DSetEye(c,&eye); rmCamera3DSetUpVector(c,&up); rmCamera3DSetAt(c,&at); rmCamera3DSetFOV(c,fov); rmCamera3DSetHither(c, hither); rmCamera3DSetYon(c,yon); rmCamera3DSetFocalDistance(c,1.0F); rmCamera3DSetAspectRatio(c,(float)imgWidth/(float)imgHeight); rmNodeSetSceneCamera3D(addToNode,c); rmCamera3DDelete(c); } void addLighting(RMnode *toModify) { RMlight *l0; /* * light source is a directional light pointing from the +Z direction */ RMcolor4D diffuse = { .7,.7,.7,1.0}; RMcolor4D specular = { .5,0.5,0.5,1.}; RMcolor4D diffuse2 = { .3, 0.3, 0.5, 1.0 }; RMvertex3D direction = { 0.5, -0.5, 1.0}; l0 = rmLightNew(); rmLightSetType(l0, RM_LIGHT_DIRECTIONAL); rmLightSetColor(l0, NULL, &diffuse, &specular); rmLightSetXYZ (l0, &direction); rmNodeSetSceneLight(toModify, RM_LIGHT0, l0); rmLightDelete(l0); /* then set the light model parms. */ { RMcolor4D defAmbient = { .2,.2,.2,1.0}; RMlightModel *lm; lm = rmLightModelNew(); rmLightModelSetAmbient(lm, &defAmbient); rmLightModelSetTwoSided (lm, RM_FALSE); rmLightModelSetLocalViewer(lm, RM_FALSE); rmNodeSetSceneLightModel(toModify, lm); rmLightModelDelete (lm); } } void addFog(RMnode *n) { RMfog *f; RMcolor4D fogColor={0.15,0.06,0.02,1.0}; f = rmFogNew(); rmFogSetDensity(f,0.15F); rmFogSetMode(f,GL_EXP); #if 0 /* don't use linear fog - most opengl implementations don't do it correctly, whereas most do GL_EXP & GL_EXP2 correctly. */ rmFogSetMode(f,GL_LINEAR); rmFogSetStartEnd(f, 10.0F, 40.0F); #endif rmFogSetColor(f,&fogColor); rmNodeSetSceneFog(n,f); } int myPreTraversalCallback(const RMnode *n, const RMstate *s) { int i; float v[4],d[4]; RMvertex3D c; RMprimitive *p; RMmatrix renderStateViewAndProjectionMatrix; int *indxPtr, indx; int isVisible; #define distanceThreshold 10.0F /* * this routine implements two things: * 1. rudimentary view frustum culling * 2. model property switching/modification based upon view * dependent parms. when a given object comes closer to the * viewer than a predefined threshold (define above, units * measured in world coords) we will change two things about * the object: a) we'll change it's color to yellow, and b) * we'll use a higher-res tesselation of the underlying * procedural model. these two things implement a form of * rudimentary view-dependent LOD control. */ isVisible = rmNodeFrustumCullCallback(n,s); if (isVisible == 0) return 0; /* * for frustum culling, we're going to use the Node's center point. * a more robust test would use an area-based metric (eg, bounding * box or sphere). */ rmNodeGetCenter(n,&c); v[0] = c.x; v[1] = c.y; v[2] = c.z; v[3] = 1.F; /* * transform this point through the combined view+projection matrix * supplied to us via the RMstate object. we don't need to worry * about the model matrix since we're not modifying any model * matrices in this demo. */ { const RMmatrix *mv, *p; mv = rmStateGetModelViewMatrix(s); p = rmStateGetProjectionMatrix(s); rmMatrixMultiply(mv,p,&renderStateViewAndProjectionMatrix); } rmPoint4MatrixTransform(v,&renderStateViewAndProjectionMatrix,d); /* * the coordinate contained in "d" is now in "unscaled" ndc space. * need more documentation here. */ #if 0 if ((d[2] < 0.) || (d[2] > d[3])) /* behind us or too far away */ isVisible = 0; else if ((fabs(d[0]) > d[2]) || (fabs(d[1]) > d[2])) /* outside view volume? */ isVisible = 0; else isVisible = 1; if (isVisible == 0) return(0); /* object "not visible", don't process this node */ #endif indxPtr = (int *)rmNodeGetClientData(n); indx = *indxPtr; p = postPrims[indx]; if (d[2] <= distanceThreshold) { RMcolor4D c={1.0,1.0,0.0,1.0}; /* * only change color when we cross the threshold. when the object * is closer to us than the threshold, we'll ask for a cylinder with * a higher res tesselation level than is used when they're farther * away from us. */ if ((lastDistance[indx] > distanceThreshold) || (lastDistance[indx] == RM_MINFLOAT)) { rmPrimitiveSetColor4D(p,1,&c,RM_COPY_DATA,NULL); rmPrimitiveSetModelFlag(p,RM_CYLINDERS_16); } } else { RMcolor4D c={1.0,1.0,1.0,1.0}; /* * only change color when we cross the threshold */ if ((lastDistance[indx] <= distanceThreshold) || (lastDistance[indx] == RM_MINFLOAT)) { rmPrimitiveSetColor4D(p,1,&c,RM_COPY_DATA,NULL); rmPrimitiveSetModelFlag(p,RM_CYLINDERS_4); } } lastDistance[indx] = d[2]; /* * improvements that could be made here include keeping around info * on each prim so that we wouldn't need to set the color each time * of every single primitive. */ return(1); } RMnode * makePost(int nthPost, /* which post */ RMvertex3D *fmin, /* floor min coordinate */ RMvertex3D *fmax, /* floor max coordinate */ float zlimit, /* the distance between floor and sky */ RMprimitive **appPrimArray, /* the static app RMprim * array */ int *indexList) { RMprimitive *p; RMnode *n; char buf[32]; int r1,r2,r3,r4; RMvertex3D v[2]; RMcolor4D c={1.0F,1.0F,1.0F,1.0F}; float radius,scale; sprintf(buf,"Post%d",nthPost); n = rmNodeNew(buf,RM_RENDERPASS_3D,RM_RENDERPASS_OPAQUE); *appPrimArray = p = rmPrimitiveNew(RM_CYLINDERS); /* * use the client data attribute of RMprimitives to store some * info for later use. we're storing an address which is the * location of an integer, that integer contains an index * into an array of RMprimitive pointers. we'll use that info * during the pretraversal callback if the primitive is visible. */ rmNodeSetClientData(n,(void *)(indexList),NULL); /* rand numbers in range 0..32767 */ r1 = rand() & 0x07FFF; r2 = rand() & 0x07FFF; r3 = rand() & 0x07FFF; r4 = rand() & 0x07FFF; /* * r1 & r2 will give us the x/y coordinate of the post. we need * to convert r1 & r2 from 0..32767 to the x/y range defined * by fmin/fmax. */ scale = (fmax->x - fmin->x)/32767.0F; v[0].x = v[1].x = (float)r1 * scale + fmin->x; scale = (fmax->y - fmin->y)/32767.0F; v[0].y = v[1].y = (float)r2 * scale + fmin->y; v[0].z = fmin->z; /* * r3 gives us the height of the cone. we must convert from * 0..32767 to the range defined by zlimit. */ scale = zlimit/32767.0F; v[1].z = (float)r3 * scale + fmin->z; /* * r4 gives us the radius. we'll convert from 0..32767 to * a maximum of 1/60 the hypotenuse length of the overall grid. * this choice is completely arbitrary. */ scale = (fmax->x - fmin->x)/(32767.0F * 60.0F); radius = (float)r4 * scale; rmPrimitiveSetVertex3D(p,2,v,RM_COPY_DATA,NULL); rmPrimitiveSetRadii(p,1,&radius,RM_COPY_DATA,NULL); /* do color later */ rmPrimitiveSetColor4D(p,1,&c,RM_COPY_DATA,NULL); rmPrimitiveSetModelFlag(p,RM_CYLINDERS_4); rmNodeAddPrimitive(n,p); { RMvertex3D center; center.x = v[0].x + 0.5 * (v[1].x - v[0].x); center.y = v[0].y + 0.5 * (v[1].y - v[0].y); center.z = v[0].z + 0.5 * (v[1].z - v[0].z); rmNodeSetCenter(n,¢er); } rmNodeComputeBoundingBox(n); rmNodeComputeCenterFromBoundingBox(n); rmNodeSetPreTraversalCallback(n,RM_VIEW, myPreTraversalCallback); /* rmNodeSetPreTraversalCallback(n,RM_VIEW, rmNodeFrustumCullCallback); */ return(n); } RMnode * addPostsToFloor(RMnode *addToNode, int nposts, RMvertex3D *fmin, RMvertex3D *fmax, float zlimit) { RMnode *postsRoot; int i; /* * in this routine, we're going to create a bunch of objects that * will sit on the floor - gives us something to look at while we * fly around. each object is going to be added as a node to the * postsRoot object. we're using one node per object so we can play * some games using view-dependent operations. */ postsRoot = rmNodeNew("postsRoot", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); rmNodeAddChild(addToNode, postsRoot); if (postPrimIndices != NULL) free((void *)postPrimIndices); if (postPrims != NULL) free((void *)postPrims); if (lastDistance != NULL) free((void *)lastDistance); postPrims = (RMprimitive **)malloc(sizeof(RMprimitive *)*nposts); postPrimIndices = (int *)malloc(sizeof(int)*nposts); lastDistance = (float *)malloc(sizeof(float)*nposts); /* * */ srand(time(NULL)); for (i=0;i<nposts;i++) { RMnode *post; postPrimIndices[i] = i; lastDistance[i] = RM_MINFLOAT; /* an unlikely-to-occur number */ rmNodeAddChild(postsRoot, makePost(i,fmin,fmax,zlimit,postPrims+i, postPrimIndices+i)); } } void myrenderfunc(RMpipe *p, RMnode *n) { unsigned long sleepMsec = 100; /* usleep(sleepMsec); */ rmFrame(p, n); /* rmSubtreeFrame(p, n); */ } void addText(RMnode *addTo, RMvertex3D *v, char *s) { RMnode *n = rmNodeNew("textNode", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); RMprimitive *p = rmPrimitiveNew(RM_TEXT); RMcolor4D c={1.,1.,1.,1.}; char *strings[1]; strings[0] = s; rmNodeSetUnlitColor(n, &c); rmPrimitiveSetVertex3D(p, 1, v, RM_COPY_DATA, NULL); rmPrimitiveSetText(p, 1, strings); rmNodeAddPrimitive(n, p); rmNodeAddChild(addTo, n); } void addLineSeg(RMnode *addTo, RMvertex3D *ref, float zHeight) { RMnode *n = rmNodeNew("lineNode", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); RMprimitive *p = rmPrimitiveNew(RM_LINES); RMcolor4D c={1.,1.,1.,1.}; RMvertex3D v[2]; rmNodeSetUnlitColor(n, &c); v[0] = *ref; v[0].z = 0.0F; v[1] = *ref; v[1].z = zHeight; rmPrimitiveSetVertex3D(p, 2, v, RM_COPY_DATA, NULL); rmNodeAddPrimitive(n, p); rmNodeAddChild(addTo, n); } void addPost(RMnode *addTo, RMvertex3D *ref, float zHeight) { RMnode *n = rmNodeNew("postNode", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); RMprimitive *p = rmPrimitiveNew(RM_CYLINDERS); RMcolor4D c={1.,1.,1.,1.}; RMvertex3D v[2]; float r = .5F; rmNodeSetUnlitColor(n, &c); v[0] = *ref; v[0].z = 0.0F; v[1] = *ref; v[1].z = zHeight; rmPrimitiveSetVertex3D(p, 2, v, RM_COPY_DATA, NULL); rmPrimitiveSetRadii(p, 1, &r, RM_COPY_DATA, NULL); rmNodeAddPrimitive(n, p); rmNodeAddChild(addTo, n); } void addSprite(RMnode *addTo, RMvertex3D *ref, RMimage *spriteImage) { RMnode *n = rmNodeNew("spriteNode", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); RMprimitive *p = rmPrimitiveNew(RM_SPRITE); RMcolor4D c={1.,1.,1.,1.}; rmNodeSetUnlitColor(n, &c); rmPrimitiveSetVertex3D(p, 1, ref, RM_COPY_DATA, NULL); rmPrimitiveSetSprites(p, 1, &spriteImage); rmNodeAddPrimitive(n, p); rmNodeAddChild(addTo, n); } void addMarker(RMnode *addTo, RMvertex3D *v, float xDelta, float zHeight, int numLines, int numPosts, RMimage *spriteImage) { char buf[32]; RMvertex3D v2; int j; sprintf(buf,"%g",v->y); v2 = *v; v2.z = 1.0; addText(addTo, &v2, buf); for (j=0;j<numLines;j++) { RMvertex3D ref; ref = *v; ref.x = ((float)j/(float)(numLines - 1)) * xDelta + v->x; addLineSeg(addTo,&ref, zHeight); } for (j=0;j<numLines;j++) { RMvertex3D ref; ref = *v; ref.x = ((float)j/(float)(numLines - 1)) * xDelta + v->x; ref.y += 5.0F; /* parameterize!! */ addPost(addTo,&ref, zHeight); } { RMvertex3D ref; ref = *v; ref.x += 0.333 * xDelta; ref.z = 0.1; addSprite(addTo, &ref, spriteImage); ref.x += 0.666 * xDelta; addSprite(addTo, &ref, spriteImage); } v2.x += xDelta; addText(addTo, &v2, buf); } void myInitFunc(RMpipe *p, RMnode *n) { float orientScale, translateScale; RMvertex3D floorMin, floorMax; RMpipe *currentPipe; int imgWidth, imgHeight; int i; RMimage *srcImage = rmiReadJPEG("data/doghead.jpg"); RMimage *spriteImage; currentPipe = p; rmPipeGetWindowSize(currentPipe, &imgWidth, &imgHeight); orientScale = 1./30.0; translateScale = 1./60.0; myRoot = rmNodeNew("myRoot",RM_RENDERPASS_ALL, RM_RENDERPASS_OPAQUE); /* * define the extents of the floor object */ floorMin.x = -10.0; floorMin.y = 0.0; floorMin.z = 0.0F; floorMax.x = 10.0; floorMax.y = 100.0; floorMax.z = 0.0F; addFloor(myRoot,&floorMin, &floorMax); spriteImage = rmImageNew(2, 64, 64, 1, RM_IMAGE_RGB, RM_UNSIGNED_BYTE, RM_COPY_DATA); rmImageResize(srcImage, spriteImage, RM_SOFTWARE, NULL); rmImageMirror(spriteImage,RM_IMAGE_MIRROR_HEIGHT); for (i=0;i<NUM_MARKERS;i++) { float t; RMvertex3D v; t = ((float)i/(float)NUM_MARKERS); v.x = floorMin.x; v.y = (floorMax.y - floorMin.y) * t + floorMin.y; v.z = floorMin.z; addMarker(myRoot, &v, 20.0F, 2.0F, NUM_LINES,NUM_POSTS, spriteImage); } addCamera(rmRootNode(), imgWidth, imgHeight); /* * set handler to reset aspect ratio when the window is resized. */ rmauxSetResizeFunc(p, rmRootNode(), rmauxDefaultResizeFunc); addLighting(rmRootNode()); if (doFog == 1) addFog(rmRootNode()); rmauxFlyUI(rmRootNode(),rmRootNode(),p, orientScale, translateScale); rmNodeAddChild(rmRootNode(), myRoot); /* * modify the rmRootNode() so that it is processed ONLY for * the 3D opaque rendering pass. */ rmNodeSetTraversalMaskDims(rmRootNode(), RM_RENDERPASS_3D); rmNodeSetTraversalMaskOpacity(rmRootNode(), RM_RENDERPASS_OPAQUE); /* * or, we coule accomplish the same thing by modifying the * RMpipe to have only a single rendering pass: 3D, opaque */ #if 0 rmPipeSetRenderPassEnable(p,RM_TRUE, RM_FALSE, RM_FALSE); #endif { /* RMcolor4D bg={0.1,0.1,0.15,1.0}; */ RMcolor4D bg={0.5,0.5,0.5,1.0}; /* * assign a background color to take effect at "MyRoot" */ rmNodeSetSceneBackgroundColor(rmRootNode(), &bg); } { RMvertex3D bmin, bmax; bmin.x = bmin.y = -10.; bmin.z = 0.0; /* temp */ bmax.x = bmax.y = 10.0; bmax.z = 1.0; /* temp */ rmNodeSetBoundingBox(rmRootNode(), &bmin, &bmax); rmNodeComputeCenterFromBoundingBox(rmRootNode()); } if (rmPipeProcessingModeIsMultithreaded(p) == RM_TRUE) rmFrame(p, rmRootNode()); rmFrame(p, rmRootNode()); } #ifdef RM_WIN int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND w; void *fptr; int status; RMpipe *pipe = NULL; RMenum channelFormat = RM_MONO_CHANNEL; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_WGL; if (parseArgs(__argc, __argv) < 0) exit(1); #else /* assume RM_X */ main(int ac, char *av[]) { Window w; RMenum channelFormat = RM_MONO_CHANNEL; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_GLX; RMpipe *pipe=NULL; if (parseArgs(ac,av) < 0) exit(1); #endif rmInit(); pipe = rmPipeNew(targetPlatform); rmPipeSetProcessingMode(pipe, processingMode); rmPipeSetFrameRate(pipe, frameRate); #ifdef RM_WIN fptr = (void *)(rmauxWndProc); w = rmauxCreateW32Window(pipe, NULL, /* no parent window */ 20,20,imgWidth,imgHeight,"Win32 fogtest", hInstance,fptr); if (w == 0) exit(-1); #else w = rmauxCreateXWindow(pipe, (Window)NULL, 0,0,imgWidth,imgHeight, "X11 fogtest","X11 fogtest", RM_TRUE); #endif rmPipeSetWindow(pipe,w,imgWidth,imgHeight); rmauxSetInitFunc(myInitFunc); rmPipeMakeCurrent(pipe); rmauxSetRenderFunc(myrenderfunc); /* * set key handler function so this prog will exit on "q" key. */ rmauxSetKeyFunc(pipe, rmauxDefaultKeyFunc); #ifdef RM_WIN rmauxEventLoop(pipe,rmRootNode(),&msg); #else rmauxEventLoop(pipe,rmRootNode(),NULL); #endif rmPipeDelete(pipe); rmFinish(); #ifdef RM_WIN return(msg.wParam); #else return(1); #endif }