1 #include <rm/rm.h>
2 #include <rm/rmaux.h>
3 #include "barrier.h"
4 #include "procmode.h"
5
6 /*
7 * Copyright (C) 2000-2005, R3vis Corporation.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA,
22 * or visit http://www.gnu.org/copyleft/gpl.html.
23 *
24 * Contributor(s):
25 * Wes Bethel, R3vis Corporation, Marin County, California
26 *
27 * The OpenRM project is located at http://openrm.sourceforge.net/.
28 */
29 /*
30 * $Id: rm2screen.c,v 1.14 2005/06/08 16:34:18 wes Exp $
31 * $Revision: 1.14 $
32 * $Name: OpenRM-1-6-0-2-c $
33 * $Log: rm2screen.c,v $
34 * Revision 1.14 2005/06/08 16:34:18 wes
35 * Code cleanup to eliminate compiler warnings. (pthread_setconcurrency remains)
36 *
37 * Revision 1.13 2005/05/16 01:17:24 wes
38 * Removed call to XInitThreads(). It seems to cause problems these days
39 * on 2.6 kernels.
40 *
41 * Revision 1.12 2004/01/17 03:18:20 wes
42 * Updated local SwapBuffers callback so that it matches the prototype
43 * for user-assigned SwapBuffers callbacks.
44 *
45 * Revision 1.11 2003/10/15 05:50:42 wes
46 * Replaced deprecated rmxPipeGetContext() with rmPipeGetContext().
47 *
48 * Revision 1.10 2003/04/13 18:13:23 wes
49 * Updated copyright dates.
50 *
51 * Revision 1.9 2003/01/27 05:07:07 wes
52 * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL.
53 *
54 * Revision 1.8 2003/01/16 22:22:45 wes
55 * Updated all source files to reflect new organization of header files: all
56 * headers that were formerly located in include/rmaux, include/rmv and
57 * include/rmi are now located in include/rm.
58 *
59 * Revision 1.7 2002/08/19 00:25:23 wes
60 * Updated barrier_* calls and type references to local version so as to
61 * avoid name collision with similar structs and calls inside OpenRM.
62 *
63 * Revision 1.6 2002/06/17 00:42:07 wes
64 * Updated copyright line.
65 *
66 * Revision 1.5 2001/07/15 22:33:19 wes
67 * Added rmPipeDelete to the end of all demo progs. For those that use
68 * an initfunc, added a new RMnode * parm (which is unused, except for rm2screen).
69 *
70 * Revision 1.4 2001/06/04 00:58:53 wes
71 * Added call to new rmaux key handler callback.
72 *
73 * Revision 1.3 2001/03/31 16:55:18 wes
74 * Added procmode.h, which defines an RMpipe processing mode used in
75 * most demonstration programs. The default processing mode is
76 * RM_PIPE_MULTISTAGE_VIEW_PARALLEL.
77 *
78 * Revision 1.2 2000/12/03 23:30:23 wes
79 * *** empty log message ***
80 *
81 * Revision 1.1 2000/12/02 17:23:02 wes
82 * Initial entry.
83 *
84 */
85
86
87
88 /*
89 * #define PARALLEL 0 means everything (X, glX, OpenGL) is serialized
90 * #define PARALLEL 1 means everything happens in parallel (unreliable
91 * on some platforms)
92 */
93 #define PARALLEL 0
94
95 /*
96 * use -DSOLARIS on the compile line, or uncomment the following line to
97 * activate solaris-specific calls. you shouldn't have to uncomment
98 * the following line on solaris boxes - the configure script in
99 * rmdemo should generate a -DSOLARIS when run on a SunOS box.
100 */
101
102 /*#define SOLARIS 1 */
103
104 #if 1
105 int window1[] = {0,0,500,500}; /* geom: x,y, w,h */
106 int window2[] = {500,0,500,500}; /* geom: x,y, w,h */
107 char display1[]={":0.0"};
108 char display2[]={":0.0"};
109 #else
110 int window1[] = {0,0,1280,2048}; /* geom: x,y, w,h */
111 int window2[] = {0,0,1280,2048}; /* geom: x,y, w,h */
112 char display1[]={":2.1"};
113 char display2[]={":2.2"};
114 #endif
115
116
117 double frust1[] = {-0.5, 0., -0.25, 0.25, 0.1, 10.0};/* frustum l, r, t, b, n, f */
118 double frust2[] = {0., 0.5, -0.25, 0.25, 0.1, 10.0};/* frustum l, r, t, b, n, f */
119 #if 0
120 double frust1[] = {-0.5, 0., -0.5, 0.5, 0.1, 10.0};/* frustum l, r, t, b, n, f */
121 double frust2[] = {0., 0.5, -0.5, 0.5, 0.1, 10.0};/* frustum l, r, t, b, n, f */
122 #endif
123 pthread_mutex_t *globalMutex=NULL;
124 int globalExit = 0;
125 my_barrier_t serialRenderBarrier;
126
127 typedef struct
128 {
129 int windowGeom[4]; /* input window geom */
130 int myID; /* thread "index" */
131 RMnode *modelRoot; /* the stuff to render */
132 pthread_mutex_t *mutex;
133 double frustum[6];
134 char *display;
135 } thrArgs;
136
137 #if PARALLEL
138 RMenum
mySwapbuffersFunc(const RMpipe * p)139 mySwapbuffersFunc(const RMpipe *p)
140 {
141 glXSwapBuffers(p->xdisplay, p->xdrawable);
142 glFlush();
143 return RM_CHILL;
144 }
145 #endif
146
147 void
setFrustum(double * f)148 setFrustum(double *f)
149 {
150
151 #define FRUST_SCALE .3
152
153 glMatrixMode(GL_PROJECTION);
154 glLoadIdentity();
155 glFrustum(f[0]*FRUST_SCALE, f[1]*FRUST_SCALE,
156 f[2]*FRUST_SCALE, f[3]*FRUST_SCALE, f[4], f[5]);
157 glMatrixMode(GL_MODELVIEW);
158 glLoadIdentity();
159
160 gluLookAt(0., 0., 3.,
161 0.0, 0.0, -1.0,
162 0.0, 1.0, 0.0);
163 }
164
165 void *
threadFunc(void * args)166 threadFunc(void *args)
167 {
168 thrArgs *ta;
169 RMpipe *myPipe=NULL;
170 Window w;
171 char windowTitle[32];
172 pthread_mutex_t *mutex;
173 RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
174
175 ta = (thrArgs *)args;
176 mutex = ta->mutex;
177
178 #if !PARALLEL
179 pthread_mutex_lock(mutex);
180 #endif
181
182 myPipe = rmPipeNew(RM_PIPE_GLX);
183
184 /* status = rmPipeInit(ta->display, RM_MONO_CHANNEL, &myPipe); */
185
186 /*
187 * override default processing mode - always use MULTISTAGE serial
188 * in the worker thread functions.
189 */
190 processingMode = RM_PIPE_MULTISTAGE;
191 rmPipeSetProcessingMode(myPipe, processingMode);
192
193 #if PARALLEL
194 rmPipeSetSwapBuffersFunc(myPipe, mySwapbuffersFunc);
195 #endif
196
197 sprintf(windowTitle,"Window%d", ta->myID);
198
199 w = rmauxCreateXWindow(myPipe,
200 (Window)NULL, /* parent window */
201 ta->windowGeom[0],
202 ta->windowGeom[1],
203 ta->windowGeom[2],
204 ta->windowGeom[3],
205 windowTitle, windowTitle, RM_FALSE);
206 if (w == 0)
207 {
208 fprintf(stderr," error creating window \n");
209 exit(-1);
210 }
211 rmPipeSetWindow(myPipe,w,window1[2],window1[3]);
212
213 XMapWindow(myPipe->xdisplay, myPipe->xdrawable);
214 XSync(myPipe->xdisplay,False);
215
216 rmPipeMakeCurrent(myPipe);
217 rmPipeSetInitMatrixStackMode(myPipe, RM_FALSE);
218
219 setFrustum(ta->frustum);
220 rmFrame(myPipe,ta->modelRoot);
221
222 #if !PARALLEL
223 pthread_mutex_unlock(mutex);
224 #endif
225 sched_yield();
226
227 while (globalExit == 0)
228 {
229 #if !PARALLEL
230 pthread_mutex_lock(mutex);
231 glXMakeCurrent(rmxPipeGetDisplay(myPipe),
232 rmPipeGetWindow(myPipe),
233 rmPipeGetContext(myPipe));
234 #endif
235
236 setFrustum(ta->frustum);
237 rmFrame(myPipe, ta->modelRoot);
238 glFlush();
239
240 #if !PARALLEL
241 pthread_mutex_unlock(mutex);
242 #endif
243 my_barrier_wait(&serialRenderBarrier);
244 sched_yield();
245 }
246
247 rmPipeDelete(myPipe);
248 return(NULL);
249 }
250
251 void
buildCamera(RMnode ** navView)252 buildCamera(RMnode **navView)
253 {
254 /*
255 * create 3 RMnodes, each of which contains a 3D camera.
256 */
257 RMnode *n;
258 RMcamera3D *c;
259 RMvertex3D eye = {0.0, 0.0, 3.0};
260 RMvertex3D up = {0.0, 1.0, 0.0};
261 RMvertex3D navAt= {0.0, 0.0, 0.0} ;
262 float hither=0.1, yon=5.0;
263
264 *navView = n = rmNodeNew("navView", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
265 c = rmCamera3DNew();
266
267 rmCamera3DSetEye(c,&eye);
268 rmCamera3DSetAt(c,&navAt);
269 rmCamera3DSetUpVector(c,&up);
270 rmCamera3DSetHither(c,hither);
271 rmCamera3DSetYon(c,yon);
272 rmCamera3DSetAspectRatio(c,1.0F);
273 rmCamera3DSetProjection(c,RM_PROJECTION_PERSPECTIVE);
274 rmCamera3DSetFOV(c,60.0F);
275
276 rmNodeSetSceneCamera3D(n,c);
277
278 rmCamera3DDelete(c);
279 }
280
281 void
myLighting(RMnode * addToNode)282 myLighting(RMnode *addToNode)
283 {
284 /* set up two lights, one red and one blue */
285 RMlight *l0, *l1;
286 RMcolor4D red = {1.0, 0.1, 0.1, 1.0};
287 RMcolor4D blue= {0.1, 0.1, 1.0, 1.0};
288
289 RMcolor4D specular = {0.5, 0.5, 0.5, 1.0};
290
291 RMvertex3D redDirection = {-3.0, 2.0, 1.0};
292 RMvertex3D blueDirection = {3.0, 2.0, 1.0};
293
294 l0 = rmLightNew();
295 if (l0 == NULL)
296 return;
297
298 rmLightSetType(l0, RM_LIGHT_DIRECTIONAL);
299 rmLightSetColor(l0, NULL, &red, &specular);
300 rmLightSetXYZ (l0, &redDirection);
301
302 l1 = rmLightNew();
303 if (l1 == NULL)
304 return;
305
306 rmLightSetType(l1, RM_LIGHT_DIRECTIONAL);
307 rmLightSetColor(l1, NULL, &blue, &specular);
308 rmLightSetXYZ(l1, &blueDirection);
309
310 rmNodeSetSceneLight(addToNode, RM_LIGHT0, l0);
311 rmNodeSetSceneLight(addToNode, RM_LIGHT1, l1);
312
313 /*
314 * when the lights are added as scene parameters, RM makes a copy
315 * of them, and we don't need our RMlight objects anymore, so we
316 * need to delete them.
317 */
318
319 rmLightDelete(l0);
320 rmLightDelete(l1);
321
322 /* set up the light model/lighting environment */
323 {
324 RMcolor4D defAmbient = {0.5, 0.5, 0.5, 1.0};
325 RMlightModel *lm = rmLightModelNew();
326
327 if (lm == NULL)
328 return;
329
330 rmLightModelSetAmbient(lm, &defAmbient);
331 rmLightModelSetTwoSided (lm, RM_FALSE);
332 rmLightModelSetLocalViewer(lm, RM_FALSE);
333 rmNodeSetSceneLightModel(addToNode, lm);
334
335 rmLightModelDelete (lm);
336 }
337 }
338
339 void
buildInitialSceneGraph(RMnode ** navView,RMnode ** leftView,RMnode ** rightView,RMnode ** model)340 buildInitialSceneGraph(RMnode **navView,
341 RMnode **leftView,
342 RMnode **rightView,
343 RMnode **model)
344 {
345 RMnode *boxNode;
346 RMprimitive *boxPrim;
347 RMvertex3D boxCorners[2] = {{-1.0F, -1.0F, -1.0},{1.0F, 1.0F, 1.0F}};
348 RMcolor4D white={0.9, 0.9, 0.9, 1.0};
349 RMcolor4D gray={0.2, 0.2, 0.2, 1.0};
350 RMcolor4D gray1={0.2, 0.25, 0.2, 1.0};
351 RMcolor4D gray2={0.25, 0.2, 0.2, 1.0};
352
353 buildCamera(navView);
354
355 *leftView = rmNodeNew("leftView", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
356 *rightView = rmNodeNew("rightView", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
357
358 rmNodeSetSceneBackgroundColor(*navView, &gray);
359 myLighting(*navView);
360 rmNodeSetUnlitColor(*navView, &white);
361
362 rmNodeSetSceneBackgroundColor(*leftView, &gray1);
363 myLighting(*leftView);
364 rmNodeSetUnlitColor(*leftView, &white);
365
366 rmNodeSetSceneBackgroundColor(*rightView, &gray2);
367 myLighting(*rightView);
368 rmNodeSetUnlitColor(*rightView, &white);
369
370 *model = boxNode = rmNodeNew("boxNode",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
371 boxPrim = rmPrimitiveNew(RM_BOX3D);
372 rmPrimitiveSetVertex3D(boxPrim, 2, boxCorners, RM_COPY_DATA, NULL);
373 rmNodeAddPrimitive(boxNode, boxPrim);
374 rmNodeComputeBoundingBox(boxNode);
375 rmNodeComputeCenterFromBoundingBox(boxNode);
376
377 rmNodeAddChild(*navView, boxNode);
378 rmNodeAddChild(*leftView, boxNode);
379 rmNodeAddChild(*rightView, boxNode);
380
381 }
382
383 void
myRenderFunc(RMpipe * p,RMnode * n)384 myRenderFunc(RMpipe *p,
385 RMnode *n)
386 {
387
388 rmFrame(p, n); /* render on the navPipe */
389
390 pthread_mutex_unlock(globalMutex); /* release slave rmPipe renderers */
391 my_barrier_wait(&serialRenderBarrier); /* global barrier */
392 pthread_mutex_lock(globalMutex);
393 }
394
395 void
myIdleFunc(RMpipe * p,int ix,int iy)396 myIdleFunc(RMpipe *p,
397 int ix,
398 int iy)
399 {
400 #if !PARALLEL
401 pthread_mutex_unlock(globalMutex);
402 #endif
403 sched_yield();
404 usleep(100);
405 #if !PARALLEL
406 pthread_mutex_lock(globalMutex);
407 #endif
408
409 /* foil compiler warning */
410 ix = iy = 0;
411 p = NULL;
412 }
413
414 void
myInitFunc(RMpipe * p,RMnode * toDraw)415 myInitFunc(RMpipe *p,
416 RMnode *toDraw)
417 {
418
419 rmFrame(p, toDraw);
420 myRenderFunc(p, toDraw);
421 }
422
423
424 int
main(int ac,char * av[])425 main(int ac,
426 char *av[])
427 {
428 pthread_attr_t attr;
429 pthread_t thrID1, thrID2;
430 void *returnVal;
431 thrArgs *threadArgs1, *threadArgs2;
432 RMnode *leftView=NULL, *rightView=NULL, *navView=NULL, *model=NULL;
433 int status;
434 pthread_mutex_t *mutex;
435 RMpipe *navPipe=NULL;
436 Window navWindow;
437 RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
438
439 /* foil compiler warnings */
440 ac = 0;
441 av = NULL;
442
443 /* status = XInitThreads(); */
444
445 #ifdef SOLARIS
446 glXInitThreadsSUN();
447 #else
448 pthread_setconcurrency(12);
449 #endif
450
451 rmInit();
452
453 buildInitialSceneGraph(&navView, &leftView, &rightView,&model);
454
455 /* rmPipeInit(getenv("DISPLAY"), RM_MONO_CHANNEL, &navPipe); */
456 /* rmPipeInit(":0.0", RM_MONO_CHANNEL, &navPipe); */
457 navPipe = rmPipeNew(RM_PIPE_GLX);
458
459 rmPipeSetProcessingMode(navPipe, processingMode);
460
461 #if PARALLEL
462 rmPipeSetSwapBuffersFunc(navPipe, mySwapbuffersFunc);
463 #else
464 my_barrier_init(&serialRenderBarrier, 3);
465 #endif
466
467 navWindow = rmauxCreateXWindow(navPipe, (Window)NULL,
468 500, 600, 200, 200,
469 "Navigate Window", "navWindow", RM_TRUE);
470 rmPipeSetWindow(navPipe, navWindow, 200, 200);
471 rmPipeMakeCurrent(navPipe);
472 rmauxSetGeomTransform(model, navPipe);
473
474 globalMutex = mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
475 status = pthread_mutex_init(mutex,NULL);
476
477 #if !PARALLEL
478 pthread_mutex_lock(mutex);
479 #endif
480
481 threadArgs1 = (thrArgs *)malloc(sizeof(thrArgs));
482 memcpy(threadArgs1->windowGeom, window1, sizeof(int)*4);
483 memcpy(threadArgs1->frustum, frust1, sizeof(double)*6);
484 threadArgs1->myID = 0;
485 threadArgs1->modelRoot = leftView;
486 threadArgs1->mutex = mutex;
487 threadArgs1->display = display1;
488 pthread_attr_init(&attr);
489 pthread_create(&thrID1, &attr, threadFunc, (void *)threadArgs1);
490
491 threadArgs2 = (thrArgs *)malloc(sizeof(thrArgs));
492 memcpy(threadArgs2->windowGeom, window2, sizeof(int)*4);
493 memcpy(threadArgs2->frustum, frust2, sizeof(double)*6);
494 threadArgs2->myID = 1;
495 threadArgs2->modelRoot = rightView;
496 threadArgs2->mutex = mutex;
497 threadArgs2->display = display2;
498
499 pthread_create(&thrID2, &attr, threadFunc, (void *)threadArgs2);
500 /* rmauxSetIdleFunc(navPipe, myIdleFunc); */
501
502 rmauxSetRenderFunc(myRenderFunc);
503 rmauxSetInitFunc(myInitFunc);
504
505 /*
506 * set key handler function so this prog will exit on "q" key.
507 */
508 rmauxSetKeyFunc(navPipe, rmauxDefaultKeyFunc);
509
510 rmauxEventLoop(navPipe, navView, NULL);
511
512 globalExit = 1;
513
514 myRenderFunc(navPipe, navView);
515 pthread_mutex_unlock(mutex);
516
517 status = pthread_join(thrID2, &returnVal);
518 status = pthread_join(thrID1, &returnVal);
519
520 rmPipeDelete(navPipe);
521
522 #if !PARALLEL
523 my_barrier_destroy(&serialRenderBarrier);
524 #endif
525
526 rmFinish();
527
528 return 1;
529 }
530