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