/* * Copyright (C) 2002-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: pickTest.c,v 1.8 2004/02/23 02:56:51 wes Exp $ * $Revision: 1.8 $ * $Name: OpenRM-1-5-2-RC1 $ * $Log: pickTest.c,v $ * Revision 1.8 2004/02/23 02:56:51 wes * Fixed minor buglet in parseArgs(). * * Revision 1.7 2003/04/13 18:13:23 wes * Updated copyright dates. * * Revision 1.6 2003/01/27 05:07:07 wes * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL. * * Revision 1.5 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.4 2002/09/05 15:02:12 wes * Removed temporary calls to test routines in the component manager. These * are no longer needed when dynamic object pools are working. * * Revision 1.3 2002/08/19 00:53:22 wes * Removed reference to RM_COMPONENT_POOL_MANAGER, which was previously * a global variable, and replaced it with a new, experimental API call * to query the size of the component pool. * * Revision 1.2 2002/08/19 00:24:41 wes * RM_COMPONENT_POOL_SIZE is now a global variable, added needed reference. * This should eventually go away, to be replaced with an OpenRM API that * will allow query of the component manager's capabilities. * * Revision 1.1 2002/06/15 17:05:58 wes * Initial entry. * */ /* * usage: pickTest [-w imgWidthPixels -h imgHeightPixels] * [-n NN (NN is number of spheres, default is 10, * max is RM_COMPONENT_POOL_SIZE/2 )] [-notext (turns off * display of text, default is text display on)] * */ #include <stdio.h> #ifndef RM_WIN #include <unistd.h> #endif #include <rm/rm.h> #include <rm/rmaux.h> #include "procmode.h" static RMpipe *myPipe=NULL; #define DEFAULT_IMAGE_WIDTH 640 #define DEFAULT_IMAGE_HEIGHT 525 static int nSpheres = 20; static int imgWidth, imgHeight; static RMenum showText=RM_TRUE; int myPickFunc(RMpipe *p, int ix, int iy) { RMpick *pickResults; static RMnode *pickedNode = NULL; RMcolor4D pickColor={0.9, 0.9, 0.1, 1.0F}; pickResults = rmFramePick(p, rmRootNode(), ix,iy); /* turn off pick color from last time. */ if (pickedNode != NULL) rmNodeSetUnlitColor(pickedNode, NULL); if (pickResults != NULL) { char buf[1024]; sprintf(buf," name of picked object is %s \n",rmPickedNodeName(pickResults)); rmNotice(buf); pickedNode = rmPickedNode(pickResults); rmNodeSetUnlitColor(pickedNode, &pickColor); rmFrame(p, rmRootNode()); rmPickDelete(pickResults); } else { rmNotice("no objects picked. try again!"); pickedNode = NULL; } return(1); /* necessary, otherwise the event loop will exit*/ } #define DIVISOR 1./32767. void ToVertex(int r1, int r2, RMvertex3D *v) { double azimuth, elevation; double ca,sa,se,ce; /* input rand numbers in range 0..32767 */ /* convert to range 0..1 */ azimuth = (double)r1 * DIVISOR; elevation = (double)r2 * DIVISOR; /* convert azimuth to range 0..2pi */ azimuth *= RM_PI * 2.0; /* convert elevation to range -pi/2..pi/2 */ elevation = (elevation - 0.5) * RM_PI; ca = cos(azimuth); sa = sin(azimuth); se = sin(elevation); ce = cos(elevation); v->y = se; v->x = ca * ce; v->z = sa * ce; /* MJV */ v->x *= 20; v->y *= 2; v->z *= 2; } void myInitFunc(RMpipe *p, RMnode *addTo) { RMnode *locRoot; RMvertex3D *v; RMcolor3D *c; int i; float radius = 0.2; /* spheres will be positioned on the surface of a hypothetical sphere centered at the origin, with radius 1.0. this radius value is 1/100, and is used as the radius value for all the spheres generated in this routine. */ float bigRadius = 0.5; locRoot = rmNodeNew("objRoot",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); v = rmVertex3DNew(nSpheres); /* srand(time(NULL)); */ srand(0); /* generate random points on a the surface of a sphere. these points will be used as the centers of a cloud of spheres. */ for (i=0;i<nSpheres;i++) { int r1,r2; r1 = rand(); r2 = rand(); ToVertex(r1,r2,v+i); } for (i=0;i<nSpheres;i++) { /* */ RMnode *n; RMprimitive *p; char buf[32]; sprintf(buf,"sphere-%d",i); n = rmNodeNew(buf,RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); p = rmPrimitiveNew(RM_SPHERES); /* MJV */ if (showText == RM_TRUE) { RMprimitive *prim; char *s[1]; if ((prim = rmPrimitiveNew(RM_TEXT)) == NULL) fprintf(stderr, "prim failed!\n"); s[0] = buf; rmPrimitiveSetText(prim, 1, s); rmPrimitiveSetVertex3D(prim, 1, v+i, RM_COPY_DATA, NULL); rmNodeAddPrimitive (n, prim); } rmPrimitiveSetVertex3D(p,1,v+i,RM_COPY_DATA,NULL); if ((i == 0) || (i == nSpheres-1)) rmPrimitiveSetRadii(p,1,&bigRadius,RM_COPY_DATA,NULL); else rmPrimitiveSetRadii(p,1,&radius,RM_COPY_DATA,NULL); rmNodeAddPrimitive (n, p); rmNodeComputeBoundingBox(n); rmNodeAddChild(locRoot, n); } rmNodeAddChild(addTo, locRoot); rmNodeUnionAllBoxes(addTo); rmVertex3DDelete(v); /* create a camera, assign it to addTo */ { RMcamera3D *c = rmCamera3DNew(); RMcolor4D bgColor={.1, .1, .4, 1.}; rmCamera3DComputeViewFromGeometry(c, locRoot, imgWidth, imgHeight); rmCamera3DSetHither(c, 0.1); /* MJV */ rmNodeSetSceneCamera3D(locRoot, c); rmNodeSetSceneBackgroundColor(locRoot, &bgColor); rmDefaultLighting(addTo); } rmauxSetGeomTransform(locRoot,p); rmauxSetCamera3DTransform(locRoot, p); rmauxSetButtonDownFunc(RM_BUTTON1,RM_NO_MODIFIER, myPickFunc); rmauxSetButtonMotionFunc(RM_BUTTON1,RM_NO_MODIFIER, NULL); rmauxSetButtonUpFunc(RM_BUTTON1,RM_NO_MODIFIER, NULL); rmFrame(p, addTo); } void myRenderFunc(RMpipe *myPipe, RMnode *subTree) { /* insert code to call frame-based renderer here */ rmFrame(myPipe, subTree); } void usage(char *s) { printf("usage: %s [-w imgWidthPixels ] [-h imgHeightPixels] [-n nSpheres (default is %d)] [-notext (turns off display of text strings, default is to display text)] \n",s, nSpheres); } void parseArgs(int ac, char *av[], int *imgWidth, int *imgHeight, int *nSpheres) { int i; i = 1; while (i < ac) { if (strcmp(av[i],"-w") == 0) { i++; sscanf(av[i],"%d", imgWidth); } else if (strcmp(av[i],"-h") == 0) { i++; sscanf(av[i],"%d", imgHeight); } else if (strcmp(av[i],"-n") == 0) { i++; sscanf(av[i],"%d", nSpheres); } else if (strcmp(av[i],"-notext") == 0) { showText = RM_FALSE; } else { usage(av[0]); exit(-1); } i++; } } #ifdef RM_WIN int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND hWnd; void *fptr; int status; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_WGL; imgWidth = DEFAULT_IMAGE_WIDTH; imgHeight = DEFAULT_IMAGE_HEIGHT; parseArgs(__argc, __argv, &imgWidth, &imgHeight, &nSpheres); #else /* assume RM_X */ int main(int argc, char *argv[]) { void *msg; /* needed for rmauxEventLoop win32/unix API consistency */ int status; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_GLX; imgWidth = DEFAULT_IMAGE_WIDTH; imgHeight = DEFAULT_IMAGE_HEIGHT; parseArgs(argc, argv, &imgWidth, &imgHeight, &nSpheres); #endif /* * first stage of RM initialization. */ rmInit(); /* * create the rendering pipe. this step is required in both * Win32 and X. */ myPipe = rmPipeNew(targetPlatform); processingMode = RM_PIPE_MULTISTAGE; rmPipeSetProcessingMode(myPipe, processingMode); #ifdef RM_WIN { /* * Win32: when a window is created, we have to tell windows the * name of the "WndProc," the procedure that gets called by * windows with events (the event loop) (contrast to the X model * where the name of the event loop is not part of the window). * Since we're using RMaux, we know about the event handling * procedure named "rmauxWndProc" and we provide that here. */ fptr = (void *)(rmauxWndProc); hWnd = rmauxCreateW32Window(myPipe, NULL, /* no parent window */ 20,20,imgWidth,imgHeight,"RM for Windows", hInstance,fptr); if (hWnd == 0) exit(-1); /* * assign the new window handle to the rendering pipe. */ rmPipeSetWindow(myPipe,hWnd, imgWidth, imgHeight); } #endif #ifdef RM_X { Window w; w = rmauxCreateXWindow(myPipe, (Window)NULL, /* parent window */ 0,0,imgWidth,imgHeight, "RM for X-Windows","RM for X-Windows",RM_TRUE); /* * assign the window to the rendering pipe. */ rmPipeSetWindow(myPipe,w,imgWidth,imgHeight); } #endif /* * X-ism: once the window is created and assigned to the * rendering pipe, rmPipeMakeCurrent makes the OpenGL rendering context * current for the pipe+window combination. * * this step is required for X. in these demo programs, it is not * strictly required by Win32, as the newly created context is made * current as part of the OpenGL initialization sequence. */ rmPipeMakeCurrent(myPipe); rmauxSetInitFunc(myInitFunc); rmauxSetRenderFunc(myRenderFunc); /* * set key handler function so this prog will exit on "q" key. */ rmauxSetKeyFunc(myPipe, rmauxDefaultKeyFunc); rmauxEventLoop(myPipe,rmRootNode(), &msg); rmPipeDelete(myPipe); rmFinish(); return(1); } /* EOF */