1 /*
2  * Copyright (C) 2001-2005, R3vis Corporation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA,
17  * or visit http://www.gnu.org/copyleft/gpl.html.
18  *
19  * Contributor(s):
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  *
22  * The OpenRM project is located at http://openrm.sourceforge.net/.
23  */
24 /*
25  * $Id: pickListTest.c,v 1.9 2005/06/08 17:07:13 wes Exp $
26  * $Revision: 1.9 $
27  * $Name: OpenRM-1-6-0-2-c $
28  * $Log: pickListTest.c,v $
29  * Revision 1.9  2005/06/08 17:07:13  wes
30  * Code cleanup to eliminate compiler warnings.
31  *
32  * Revision 1.8  2004/02/23 02:56:51  wes
33  * Fixed minor buglet in parseArgs().
34  *
35  * Revision 1.7  2003/04/13 18:13:23  wes
36  * Updated copyright dates.
37  *
38  * Revision 1.6  2003/01/27 05:07:07  wes
39  * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL.
40  *
41  * Revision 1.5  2003/01/16 22:22:45  wes
42  * Updated all source files to reflect new organization of header files: all
43  * headers that were formerly located in include/rmaux, include/rmv and
44  * include/rmi are now located in include/rm.
45  *
46  * Revision 1.4  2002/09/05 15:02:12  wes
47  * Removed temporary calls to test routines in the component manager. These
48  * are no longer needed when dynamic object pools are working.
49  *
50  * Revision 1.3  2002/08/19 00:53:22  wes
51  * Removed reference to RM_COMPONENT_POOL_MANAGER, which was previously
52  * a global variable, and replaced it with a new, experimental API call
53  * to query the size of the component pool.
54  *
55  * Revision 1.2  2002/08/19 00:24:41  wes
56  * RM_COMPONENT_POOL_SIZE is now a global variable, added needed reference.
57  * This should eventually go away, to be replaced with an OpenRM API that
58  * will allow query of the component manager's capabilities.
59  *
60  * Revision 1.1  2002/06/15 17:05:58  wes
61  * Initial entry.
62  *
63  *
64  */
65 
66 /*
67  * usage: pickListTest [-w imgWidthPixels -h imgHeightPixels]
68  *        [-n NN (NN is number of spheres, default is 10,
69  *          max is RM_COMPONENT_POOL_SIZE/2 )]
70  */
71 
72 #include <stdio.h>
73 #ifndef RM_WIN
74 #include <unistd.h>
75 #endif
76 #include <rm/rm.h>
77 #include <rm/rmaux.h>
78 #include "procmode.h"
79 
80 static RMpipe *myPipe=NULL;
81 
82 #define DEFAULT_IMAGE_WIDTH 640
83 #define DEFAULT_IMAGE_HEIGHT 525
84 static int nSpheres = 10;
85 
86 static int imgWidth, imgHeight;
87 static RMenum showText = RM_TRUE;
88 
89 
90 int
myPickFunc(RMpipe * p,int ix,int iy)91 myPickFunc(RMpipe *p,
92 	   int ix, int iy)
93 {
94     RMpick *pickResults;
95     int nPickedObjects;
96     static RMnode *pickedNode = NULL;
97     RMcolor4D pickColor={0.9, 0.9, 0.1, 1.0F};
98 
99     /* this code uses rmFramePickList */
100 
101     nPickedObjects = rmFramePickList(p, rmRootNode(), ix,iy, &pickResults);
102 
103     /* turn off pick color from last time. */
104     if (pickedNode != NULL)
105       rmNodeSetUnlitColor(pickedNode, NULL);
106 
107     if (nPickedObjects > 0)
108     {
109 	int i;
110 	char buf[1024];
111 	char *bigBuf = (char *)malloc(sizeof(char)*nPickedObjects*1024);
112 	char *work;
113 
114 	memset(bigBuf, 0, sizeof(char)*nPickedObjects*1024);
115 
116 	sprintf(buf," there were %d objects picked. They are:\n", nPickedObjects);
117 	strncpy(bigBuf, buf, strlen(buf));
118 	work = bigBuf + strlen(buf);
119 
120 	for (i=0;i<nPickedObjects;i++)
121 	{
122 	    sprintf(buf, " name of object %d is %s, primitive # %d at zval=%f\n",i, rmPickedNodeName(pickResults+i), rmPickedPrimitive(pickResults+i), rmPickedPrimitiveZval(pickResults+i));
123 	    work = strncpy(work, buf, strlen(buf));
124 	    work += strlen(buf);
125 	}
126 
127 	sprintf(buf," name of closest picked object is %s \n",rmPickedNodeName(pickResults));
128 	strncpy(work, buf, strlen(buf));
129 	work += strlen(buf);
130 
131 	rmNotice(bigBuf);
132 
133 
134 	pickedNode = rmPickedNode(pickResults);
135 	rmNodeSetUnlitColor(pickedNode, &pickColor);
136 	rmFrame(p, rmRootNode());
137 	rmPickDelete(pickResults);
138     }
139     else
140     {
141 	rmNotice("no objects picked. try again!");
142 	pickedNode = NULL;
143     }
144 
145     return(1);				 /* necessary, otherwise the
146 					  event loop will exit*/
147 }
148 
149 #define DIVISOR 1./32767.
150 
151 void
ToVertex(int r1,int r2,RMvertex3D * v)152 ToVertex(int r1,
153 	 int r2,
154 	 RMvertex3D *v)
155 {
156     double azimuth, elevation;
157     double ca,sa,se,ce;
158 
159     /* input rand numbers in range 0..32767 */
160 
161     /* convert to range 0..1 */
162     azimuth = (double)r1 * DIVISOR;
163     elevation = (double)r2 * DIVISOR;
164 
165     /* convert azimuth to range 0..2pi */
166     azimuth *= RM_PI * 2.0;
167 
168     /* convert elevation to range -pi/2..pi/2 */
169     elevation = (elevation - 0.5) * RM_PI;
170 
171     ca = cos(azimuth);
172     sa = sin(azimuth);
173     se = sin(elevation);
174     ce = cos(elevation);
175 
176     v->y = se;
177     v->x = ca * ce;
178     v->z = sa * ce;
179 
180     /* MJV */
181 
182     v->x *= 20;
183     v->y *= 2;
184     v->z *= 2;
185 }
186 
187 void
myInitFunc(RMpipe * p,RMnode * addTo)188 myInitFunc(RMpipe *p,
189 	   RMnode *addTo)
190 {
191   RMnode *locRoot;
192   RMvertex3D *v;
193   int i;
194   float radius = 0.2;		/* spheres will be positioned on the
195 				   surface of a hypothetical sphere centered
196 				at the origin, with radius 1.0. this radius
197 				value is 1/100, and is used as the radius
198 				value for all the spheres generated in this
199 				routine. */
200   float bigRadius = 0.5;
201 
202   locRoot = rmNodeNew("objRoot",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
203 
204   v = rmVertex3DNew(nSpheres);
205   /*  srand(time(NULL)); */
206   srand(0);
207 
208   /* generate random points on a the surface of a sphere. these
209      points will be used as the centers of a cloud of spheres.  */
210 
211   for (i=0;i<nSpheres;i++)
212   {
213      int r1,r2;
214      r1 = rand();
215      r2 = rand();
216      ToVertex(r1,r2,v+i);
217   }
218 
219   for (i=0;i<nSpheres;i++)
220   {
221      /*  */
222      RMnode *n;
223      RMprimitive *p;
224      char buf[32];
225 
226      sprintf(buf,"sphere-%d",i);
227      n = rmNodeNew(buf,RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
228      p = rmPrimitiveNew(RM_SPHERES);
229 
230      /* MJV */
231      if (showText == RM_TRUE)
232      {
233        RMprimitive *prim;
234        char *s[1];
235 
236        if ((prim = rmPrimitiveNew(RM_TEXT)) == NULL)
237 	 fprintf(stderr, "prim failed!\n");
238 
239        s[0] = buf;
240        rmPrimitiveSetText(prim, 1, s);
241        rmPrimitiveSetVertex3D(prim, 1, v+i, RM_COPY_DATA, NULL);
242        rmNodeAddPrimitive (n, prim);
243      }
244 
245      rmPrimitiveSetVertex3D(p,1,v+i,RM_COPY_DATA,NULL);
246      if ((i == 0) || (i == nSpheres-1))
247        rmPrimitiveSetRadii(p,1,&bigRadius,RM_COPY_DATA,NULL);
248      else
249        rmPrimitiveSetRadii(p,1,&radius,RM_COPY_DATA,NULL);
250 
251      rmNodeAddPrimitive (n, p);
252 
253      rmNodeComputeBoundingBox(n);
254      rmNodeAddChild(locRoot, n);
255   }
256 
257   rmNodeAddChild(addTo, locRoot);
258   rmNodeUnionAllBoxes(addTo);
259 
260   rmVertex3DDelete(v);
261 
262   /* create a camera, assign it to addTo */
263   {
264      RMcamera3D *c = rmCamera3DNew();
265      RMcolor4D bgColor={.1, .1, .4, 1.};
266 
267      rmCamera3DComputeViewFromGeometry(c, locRoot, imgWidth, imgHeight);
268      rmCamera3DSetHither(c, 0.1); /* MJV */
269      rmNodeSetSceneCamera3D(locRoot, c);
270      rmNodeSetSceneBackgroundColor(locRoot, &bgColor);
271      rmDefaultLighting(addTo);
272   }
273 
274   rmauxSetGeomTransform(locRoot,p);
275   rmauxSetCamera3DTransform(locRoot, p);
276   rmauxSetButtonDownFunc(RM_BUTTON1,RM_NO_MODIFIER, myPickFunc);
277   rmauxSetButtonMotionFunc(RM_BUTTON1,RM_NO_MODIFIER, NULL);
278   rmauxSetButtonUpFunc(RM_BUTTON1,RM_NO_MODIFIER, NULL);
279 
280   rmFrame(p, addTo);
281 }
282 
283 void
myRenderFunc(RMpipe * myPipe,RMnode * subTree)284 myRenderFunc(RMpipe *myPipe,
285 	     RMnode *subTree)
286 {
287     /* insert code to call frame-based renderer here */
288     rmFrame(myPipe, subTree);
289 }
290 
291 
292 void
usage(char * s)293 usage(char *s)
294 {
295     printf("usage: %s [-w imgWidthPixels ] [-h imgHeightPixels] [-n nSpheres (default is %d)] [-notext (turns off text display, default is to display text)] \n",s, nSpheres);
296 }
297 
298 void
parseArgs(int ac,char * av[],int * imgWidth,int * imgHeight,int * nSpheres)299 parseArgs(int ac,
300 	  char *av[],
301 	  int *imgWidth,
302 	  int *imgHeight,
303 	  int *nSpheres)
304 {
305     int i;
306 
307     i = 1;
308     while (i < ac)
309     {
310 	if (strcmp(av[i],"-w") == 0)
311 	{
312 	    i++;
313 	    sscanf(av[i],"%d", imgWidth);
314 	}
315 	else if (strcmp(av[i],"-h") == 0)
316 	{
317 	    i++;
318 	    sscanf(av[i],"%d", imgHeight);
319 	}
320 	else if (strcmp(av[i],"-n") == 0)
321 	{
322 	    i++;
323 	    sscanf(av[i],"%d", nSpheres);
324 	}
325 	else if (strcmp(av[i],"-notext") == 0)
326 	{
327 	    showText = RM_FALSE;
328 	}
329 	else
330 	{
331 	    usage(av[0]);
332 	    exit(-1);
333 	}
334 	i++;
335     }
336 }
337 
338 #ifdef RM_WIN
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)339 int WINAPI WinMain (HINSTANCE hInstance,
340 		    HINSTANCE hPrevInstance,
341                     LPSTR lpszCmdLine, int nCmdShow)
342 {
343     MSG      msg;
344     HWND     hWnd;
345     void *fptr;
346 
347     RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
348     RMenum targetPlatform = RM_PIPE_WGL;
349 
350     imgWidth = DEFAULT_IMAGE_WIDTH;
351     imgHeight = DEFAULT_IMAGE_HEIGHT;
352 
353     parseArgs(__argc, __argv, &imgWidth, &imgHeight, &nSpheres);
354 
355 #else  /* assume RM_X */
356 int
357 main(int argc,
358      char *argv[])
359 {
360     void *msg;			/* needed for rmauxEventLoop
361 				 win32/unix API consistency */
362     RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
363     RMenum targetPlatform = RM_PIPE_GLX;
364 
365     imgWidth = DEFAULT_IMAGE_WIDTH;
366     imgHeight = DEFAULT_IMAGE_HEIGHT;
367 
368     parseArgs(argc, argv, &imgWidth, &imgHeight, &nSpheres);
369 #endif
370 
371     /*
372      * first stage of RM initialization.
373      */
374     rmInit();
375 
376     /*
377      * create the rendering pipe. this step is required in both
378      * Win32 and X.
379      */
380     myPipe = rmPipeNew(targetPlatform);
381 
382     processingMode = RM_PIPE_MULTISTAGE;
383     rmPipeSetProcessingMode(myPipe, processingMode);
384 
385 #ifdef RM_WIN
386     {
387         /*
388 	 * Win32: when a window is created, we have to tell windows the
389 	 * name of the "WndProc," the procedure that gets called by
390 	 * windows with events (the event loop) (contrast to the X model
391 	 * where the name of the event loop is not part of the window).
392 	 * Since we're using RMaux, we know about the event handling
393 	 * procedure named "rmauxWndProc" and we provide that here.
394 	 */
395 
396         fptr = (void *)(rmauxWndProc);
397 	hWnd = rmauxCreateW32Window(myPipe,
398 			       NULL, /* no parent window */
399 			       20,20,imgWidth,imgHeight,"RM for Windows",
400 			       hInstance,fptr);
401 	if (hWnd == 0)
402 	  exit(-1);
403 
404 	/*
405 	 * assign the new window handle to the rendering pipe.
406 	 */
407 	rmPipeSetWindow(myPipe,hWnd, imgWidth, imgHeight);
408     }
409 #endif
410 #ifdef RM_X
411     {
412 	Window w;
413 
414 	w = rmauxCreateXWindow(myPipe,
415 			       (Window)NULL, /* parent window */
416 			       0,0,imgWidth,imgHeight,
417 			       "RM for X-Windows","RM for X-Windows",RM_TRUE);
418 
419 	/*
420 	 * assign the window to the rendering pipe.
421 	 */
422 	rmPipeSetWindow(myPipe,w,imgWidth,imgHeight);
423     }
424 #endif
425 
426     /*
427      * X-ism: once the window is created and assigned to the
428      * rendering pipe, rmPipeMakeCurrent makes the OpenGL rendering context
429      * current for the pipe+window combination.
430      *
431      * this step is required for X. in these demo programs, it is not
432      * strictly required by Win32, as the newly created context is made
433      * current as part of the OpenGL initialization sequence.
434      */
435     rmPipeMakeCurrent(myPipe);
436 
437     rmauxSetInitFunc(myInitFunc);
438     rmauxSetRenderFunc(myRenderFunc);
439 
440     /*
441      * set key handler function so this prog will exit on "q" key.
442      */
443     rmauxSetKeyFunc(myPipe, rmauxDefaultKeyFunc);
444 
445     rmauxEventLoop(myPipe,rmRootNode(), &msg);
446 
447     rmPipeDelete(myPipe);
448     rmFinish();
449 
450     return(1);
451 }
452 /* EOF */
453