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