ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ogl.c
Revision: 3.7
Committed: Tue Dec 22 09:40:32 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.6: +46 -34 lines
Log Message:
simplified view conditions with viewflags variable

File Contents

# User Rev Content
1 gwlarson 3.1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ SGI";
5     #endif
6    
7     /*
8     * OpenGL driver for holodeck display.
9     * Based on GLX driver using T-mesh.
10     *
11     * Define symbol STEREO for stereo viewing.
12     * Define symbol DOBJ for display object viewing.
13     */
14    
15     #ifdef NOSTEREO
16     #ifdef STEREO
17     #undef STEREO
18     #else
19     #undef NOSTEREO
20     #endif
21     #endif
22    
23     #include "standard.h"
24    
25     #include <sys/types.h>
26     #include <GL/glx.h>
27     #include <GL/glu.h>
28     #ifdef STEREO
29     #include <X11/extensions/SGIStereo.h>
30     #endif
31    
32     #include "rhd_odraw.h"
33     #ifdef DOBJ
34     #include "rhdobj.h"
35     #endif
36    
37     #include "x11icon.h"
38    
39     #ifndef RAYQLEN
40 gwlarson 3.6 #define RAYQLEN 50000 /* max. rays to queue before flush */
41 gwlarson 3.1 #endif
42    
43 gwlarson 3.3 #ifndef PORTALP
44     #define PORTRED 2 /* portal red color */
45     #define PORTGRN -1 /* portal green left alone */
46     #define PORTBLU 128 /* portal blue color */
47     #define PORTALP -1 /* don't use alpha channel */
48     #endif
49     #define isportal(c) ((PORTRED<0 || (c)[0]==PORTRED) && \
50     (PORTGRN<0 || (c)[1]==PORTGRN) && \
51     (PORTBLU<0 || (c)[2]==PORTBLU) && \
52     (PORTALP<0 || (c)[3]==PORTALP))
53    
54 gwlarson 3.1 #ifndef FEQ
55     #define FEQ(a,b) ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
56     #endif
57    
58 gwlarson 3.7 #define VWHEADLOCK 01 /* head position is locked flag */
59     #define VWPERSP 02 /* perspective view is set */
60     #define VWORTHO 04 /* orthographic view is set */
61     #define VWCHANGE 010 /* view has changed */
62     #define VWSTEADY 020 /* view is now steady */
63     #define VWMAPPED 040 /* window is mapped */
64    
65 gwlarson 3.1 #define GAMMA 1.4 /* default gamma correction */
66    
67     #define FRAMESTATE(s) (((s)&(ShiftMask|ControlMask))==(ShiftMask|ControlMask))
68    
69     #define MOVPCT 7 /* percent distance to move /frame */
70     #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
71     #define MOVDEG (-5) /* degrees to orbit CW/down /frame */
72     #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
73    
74     #define MINWIDTH 480 /* minimum graphics window width */
75     #define MINHEIGHT 400 /* minimum graphics window height */
76    
77     #define VIEWDIST 356 /* assumed viewing distance (mm) */
78    
79     #define BORWIDTH 5 /* border width */
80    
81     #define setstereobuf(bid) (glXWaitGL(), \
82     XSGISetStereoBuffer(ourdisplay, gwind, bid), \
83     glXWaitX())
84    
85     #define ourscreen DefaultScreen(ourdisplay)
86     #define ourroot RootWindow(ourdisplay,ourscreen)
87     #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
88     ButtonPressMask|ButtonReleaseMask)
89    
90     #define levptr(etype) ((etype *)&currentevent)
91    
92     struct driver odev; /* global device driver structure */
93    
94     char odev_args[64]; /* command arguments */
95    
96     static GLfloat *depthbuffer = NULL; /* depth buffer */
97    
98     #ifdef STEREO
99     static VIEW vwright; /* right eye view */
100     static GLfloat *depthright = NULL; /* right depth buffer */
101     #endif
102    
103     static int rayqleft = 0; /* rays left to queue before flush */
104    
105     static XEvent currentevent; /* current event */
106    
107     static unsigned long ourblack=0, ourwhite=~0;
108    
109     static Display *ourdisplay = NULL; /* our display */
110     static XVisualInfo *ourvinf; /* our visual information */
111     static Window gwind = 0; /* our graphics window */
112     static GLXContext gctx; /* our GLX context */
113    
114     static double pwidth, pheight; /* pixel dimensions (mm) */
115    
116     static double dev_zmin, dev_zmax; /* fore and aft clipping plane dist. */
117     static double dev_zrat; /* (1. - dev_zmin/dev_zmax) */
118    
119     #define setzrat() (dev_zrat = 1. - dev_zmin/dev_zmax)
120     #define mapdepth(d) ((d)>0.9995 ? FHUGE : dev_zmin/(1.-(d)*dev_zrat))
121    
122     static int inpresflags; /* input result flags */
123    
124 gwlarson 3.7 static int viewflags; /* what's happening with view */
125 gwlarson 3.1
126     static int resizewindow(), getevent(), getkey(), moveview(), wipeclean(),
127 gwlarson 3.2 xferdepth(), freedepth(), setglortho(),
128 gwlarson 3.1 setglpersp(), getframe(), getmove(), fixwindow(), mytmflags();
129    
130     static double getdistance();
131    
132     #ifdef STEREO
133     static int pushright(), popright();
134     #endif
135    
136 gwlarson 3.2 extern int gmPortals; /* GL portal list id */
137    
138 gwlarson 3.1 extern time_t time();
139    
140    
141     dev_open(id) /* initialize GLX driver */
142     char *id;
143     {
144     extern char *getenv();
145     static RGBPRIMS myprims = STDPRIMS;
146 gwlarson 3.3 #if (PORTALP<0)
147 gwlarson 3.6 static int atlBest[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
148     GLX_RED_SIZE,8, GLX_GREEN_SIZE,8,
149     GLX_BLUE_SIZE,8, GLX_DEPTH_SIZE,15, None};
150     static int atlOK[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
151     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
152     GLX_BLUE_SIZE,4, GLX_DEPTH_SIZE,15, None};
153     #else
154     static int atlBest[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
155     GLX_RED_SIZE,8, GLX_GREEN_SIZE,8,
156     GLX_BLUE_SIZE,8, GLX_ALPHA_SIZE,2,
157 gwlarson 3.1 GLX_DEPTH_SIZE,15, None};
158 gwlarson 3.6 static int atlOK[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
159     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
160     GLX_BLUE_SIZE,4, GLX_ALPHA_SIZE,2,
161     GLX_DEPTH_SIZE,15, None};
162 gwlarson 3.3 #endif
163 gwlarson 3.1 char *ev;
164     double gamval = GAMMA;
165     RGBPRIMP dpri = stdprims;
166     XSetWindowAttributes ourwinattr;
167     XWMHints ourxwmhints;
168     XSizeHints oursizhints;
169     /* check for unsupported stereo */
170     #ifdef NOSTEREO
171     error(INTERNAL, "stereo display driver unavailable");
172     #endif
173     /* open display server */
174     ourdisplay = XOpenDisplay(NULL);
175 gwlarson 3.5 CHECK(ourdisplay==NULL, USER,
176     "cannot open X-windows; DISPLAY variable set?");
177 gwlarson 3.1 #ifdef STEREO
178     switch (XSGIQueryStereoMode(ourdisplay, ourroot)) {
179     case STEREO_TOP:
180     case STEREO_BOTTOM:
181     break;
182     case STEREO_OFF:
183     error(USER,
184 gwlarson 3.5 "wrong video mode: run \"/usr/gfx/setmon -n STR_TOP\" first");
185 gwlarson 3.1 case X_STEREO_UNSUPPORTED:
186     error(USER, "stereo mode not supported on this screen");
187     default:
188     error(INTERNAL, "unknown stereo mode");
189     }
190     #endif
191     /* find a usable visual */
192     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest);
193 gwlarson 3.6 if (ourvinf == NULL)
194     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlOK);
195 gwlarson 3.5 CHECK(ourvinf==NULL, USER, "no suitable visuals available");
196 gwlarson 3.1 /* get a context */
197     gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE);
198     /* set gamma and tone mapping */
199     if ((ev = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
200     || (ev = getenv("DISPLAY_GAMMA")) != NULL)
201     gamval = atof(ev);
202     if ((ev = getenv("DISPLAY_PRIMARIES")) != NULL &&
203     sscanf(ev, "%f %f %f %f %f %f %f %f",
204     &myprims[RED][CIEX],&myprims[RED][CIEY],
205     &myprims[GRN][CIEX],&myprims[GRN][CIEY],
206     &myprims[BLU][CIEX],&myprims[BLU][CIEY],
207     &myprims[WHT][CIEX],&myprims[WHT][CIEY]) >= 6)
208     dpri = myprims;
209     if (tmInit(mytmflags(), dpri, gamval) == NULL)
210     error(SYSTEM, "not enough memory in dev_open");
211     /* open window */
212     ourwinattr.background_pixel = ourblack;
213     ourwinattr.border_pixel = ourblack;
214     ourwinattr.event_mask = ourmask;
215     /* this is stupid */
216     ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
217     ourvinf->visual, AllocNone);
218     gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
219     DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
220     #ifdef STEREO
221     (DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH)/2,
222     #else
223     DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
224     #endif
225     BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual,
226     CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
227 gwlarson 3.5 CHECK(gwind==0, SYSTEM, "cannot create window");
228 gwlarson 3.1 XStoreName(ourdisplay, gwind, id);
229     /* set window manager hints */
230     ourxwmhints.flags = InputHint|IconPixmapHint;
231     ourxwmhints.input = True;
232     ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
233     gwind, x11icon_bits, x11icon_width, x11icon_height);
234     XSetWMHints(ourdisplay, gwind, &ourxwmhints);
235     oursizhints.min_width = MINWIDTH;
236     #ifdef STEREO
237     oursizhints.min_height = MINHEIGHT/2;
238     oursizhints.max_width = DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH;
239     oursizhints.max_height = (DisplayHeight(ourdisplay,ourscreen) -
240     2*BORWIDTH)/2;
241     oursizhints.flags = PMinSize|PMaxSize;
242     #else
243     oursizhints.min_height = MINHEIGHT;
244     oursizhints.flags = PMinSize;
245     #endif
246     XSetNormalHints(ourdisplay, gwind, &oursizhints);
247     /* set GLX context */
248     glXMakeCurrent(ourdisplay, gwind, gctx);
249     glEnable(GL_DEPTH_TEST);
250     glDepthFunc(GL_LEQUAL);
251 gwlarson 3.6 glEnable(GL_DITHER);
252 gwlarson 3.1 glFrontFace(GL_CCW);
253     glDisable(GL_CULL_FACE);
254     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
255     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
256     /* figure out sensible view */
257     pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
258     DisplayWidth(ourdisplay, ourscreen);
259     pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
260     DisplayHeight(ourdisplay, ourscreen);
261     #ifdef STEREO
262     pheight *= 2.;
263     setstereobuf(STEREO_BUFFER_LEFT);
264     #endif
265     checkglerr("setting rendering parameters");
266     copystruct(&odev.v, &stdview);
267     odev.v.type = VT_PER;
268 gwlarson 3.7 viewflags = VWSTEADY; /* view starts static */
269 gwlarson 3.1 /* map the window */
270     XMapWindow(ourdisplay, gwind);
271     dev_input(); /* sets size and view angles */
272     if (!odInit(DisplayWidth(ourdisplay,ourscreen) *
273 gwlarson 3.4 DisplayHeight(ourdisplay,ourscreen) / 4))
274 gwlarson 3.1 error(SYSTEM, "insufficient memory for value storage");
275     odev.name = id;
276     odev.firstuse = 1; /* can't recycle samples */
277     odev.ifd = ConnectionNumber(ourdisplay);
278     }
279    
280    
281     dev_close() /* close our display and free resources */
282     {
283     #ifdef DOBJ
284     dobj_cleanup();
285     #endif
286 gwlarson 3.2 freedepth();
287     gmEndGeom();
288     gmEndPortal();
289 gwlarson 3.1 odDone();
290     glXMakeCurrent(ourdisplay, None, NULL);
291     glXDestroyContext(ourdisplay, gctx);
292     XDestroyWindow(ourdisplay, gwind);
293     gwind = 0;
294     XCloseDisplay(ourdisplay);
295     ourdisplay = NULL;
296     tmDone(NULL);
297     odev.v.type = 0;
298     odev.hres = odev.vres = 0;
299     odev.ifd = -1;
300     }
301    
302    
303     dev_clear() /* clear our representation */
304     {
305     wipeclean();
306     rayqleft = 0; /* hold off update */
307     }
308    
309    
310     int
311     dev_view(nv) /* assign new driver view */
312     register VIEW *nv;
313     {
314     double d;
315    
316     if (nv->type != VT_PER || /* check view legality */
317     nv->horiz > 160. || nv->vert > 160.) {
318     error(COMMAND, "illegal view type/angle");
319     nv->type = odev.v.type;
320     nv->horiz = odev.v.horiz;
321     nv->vert = odev.v.vert;
322     return(0);
323     }
324     if (nv != &odev.v) {
325     /* resize window? */
326     if (!FEQ(nv->horiz,odev.v.horiz) ||
327     !FEQ(nv->vert,odev.v.vert)) {
328     int dw = DisplayWidth(ourdisplay,ourscreen);
329     int dh = DisplayHeight(ourdisplay,ourscreen);
330    
331     dw -= 25; /* for window frame */
332     dh -= 50;
333     #ifdef STEREO
334     dh /= 2;
335     #endif
336     odev.hres = 2.*VIEWDIST/pwidth *
337     tan(PI/180./2.*nv->horiz);
338     odev.vres = 2.*VIEWDIST/pheight *
339     tan(PI/180./2.*nv->vert);
340     if (odev.hres > dw) {
341     odev.vres = dw * odev.vres / odev.hres;
342     odev.hres = dw;
343     }
344     if (odev.vres > dh) {
345     odev.hres = dh * odev.hres / odev.vres;
346     odev.vres = dh;
347     }
348     XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
349     dev_input(); /* get resize event */
350     }
351     copystruct(&odev.v, nv); /* setview() already called */
352     #ifdef STEREO
353     copystruct(&vwright, nv);
354     d = eyesepdist / sqrt(nv->hn2);
355     VSUM(vwright.vp, nv->vp, nv->hvec, d);
356     /* setview(&vwright); -- Unnecessary */
357     #endif
358 gwlarson 3.7 viewflags |= VWCHANGE;
359 gwlarson 3.6 }
360 gwlarson 3.1 wipeclean();
361     return(1);
362     }
363    
364    
365 gwlarson 3.2 dev_section(gfn, pfn) /* add octree for geometry rendering */
366     char *gfn, *pfn;
367 gwlarson 3.1 {
368     extern char *index();
369     char *cp;
370    
371 gwlarson 3.2 if (gfn == NULL) {
372     gmEndGeom();
373     gmEndPortal();
374 gwlarson 3.4 wipeclean(); /* new geometry, so redraw it */
375 gwlarson 3.2 return;
376     }
377     if (access(gfn, R_OK) == 0)
378     gmNewGeom(gfn);
379 gwlarson 3.1 #ifdef DEBUG
380     else {
381 gwlarson 3.2 sprintf(errmsg, "cannot load octree \"%s\"", gfn);
382 gwlarson 3.1 error(WARNING, errmsg);
383     }
384     #endif
385 gwlarson 3.2 if (pfn != NULL)
386     gmNewPortal(pfn);
387 gwlarson 3.1 }
388    
389    
390     dev_auxcom(cmd, args) /* process an auxiliary command */
391     char *cmd, *args;
392     {
393     #ifdef DOBJ
394     if (dobj_command(cmd, args) >= 0)
395     return;
396     #endif
397     sprintf(errmsg, "%s: unknown command", cmd);
398     error(COMMAND, errmsg);
399     }
400    
401    
402     VIEW *
403     dev_auxview(n, hvres) /* return nth auxiliary view */
404     int n;
405     int hvres[2];
406     {
407     hvres[0] = odev.hres; hvres[1] = odev.vres;
408     if (n == 0)
409     return(&odev.v);
410     #ifdef STEREO
411     if (n == 1)
412     return(&vwright);
413     #endif
414     return(NULL);
415     }
416    
417    
418     int
419     dev_input() /* get X11 input */
420     {
421     inpresflags = 0;
422    
423     do
424     getevent();
425    
426     while (XPending(ourdisplay) > 0);
427    
428     odev.inpready = 0;
429    
430     return(inpresflags);
431     }
432    
433    
434     dev_value(c, d, p) /* add a pixel value to our texture */
435     COLR c;
436     FVECT d, p;
437     {
438     #ifdef DOBJ
439     if (dobj_lightsamp != NULL) { /* in light source sampling */
440     (*dobj_lightsamp)(c, d, p);
441     return;
442     }
443     #endif
444     odSample(c, d, p); /* add to display representation */
445     if (!--rayqleft)
446     dev_flush(); /* flush output */
447     }
448    
449    
450     int
451     dev_flush() /* flush output as appropriate */
452     {
453     int ndrawn;
454    
455 gwlarson 3.7 if ((viewflags&(VWMAPPED|VWPERSP)) == (VWMAPPED|VWPERSP)) {
456 gwlarson 3.1 #ifdef STEREO
457     pushright(); /* draw right eye */
458 gwlarson 3.3 ndrawn = gmDrawGeom();
459 gwlarson 3.1 #ifdef DOBJ
460 gwlarson 3.3 ndrawn += dobj_render();
461 gwlarson 3.1 #endif
462 gwlarson 3.6 if (ndrawn && gmPortals)
463     gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
464 gwlarson 3.1 checkglerr("rendering right eye");
465     popright(); /* draw left eye */
466     #endif
467 gwlarson 3.3 ndrawn = gmDrawGeom();
468 gwlarson 3.1 #ifdef DOBJ
469     ndrawn += dobj_render();
470     #endif
471 gwlarson 3.6 if (ndrawn && gmPortals)
472     gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
473     glXSwapBuffers(ourdisplay, gwind);
474 gwlarson 3.1 checkglerr("rendering base view");
475     }
476 gwlarson 3.7 if ((viewflags&(VWMAPPED|VWSTEADY|VWPERSP|VWORTHO)) ==
477     (VWMAPPED|VWSTEADY|VWPERSP)) {
478     /* first time after steady */
479     if (ndrawn)
480     xferdepth(); /* transfer and clear depth */
481     setglortho(); /* set orthographic view */
482    
483     }
484     if ((viewflags&(VWMAPPED|VWSTEADY|VWPERSP|VWORTHO)) ==
485     (VWMAPPED|VWSTEADY|VWORTHO)) {
486     /* else update cones */
487 gwlarson 3.1 #ifdef STEREO
488 gwlarson 3.7 pushright();
489     odUpdate(1); /* draw right eye */
490     popright();
491 gwlarson 3.1 #endif
492 gwlarson 3.7 odUpdate(0); /* draw left eye */
493     glFlush(); /* flush OpenGL */
494     }
495 gwlarson 3.1 rayqleft = RAYQLEN;
496     /* flush X11 and return # pending */
497     return(odev.inpready = XPending(ourdisplay));
498     }
499    
500    
501     checkglerr(where) /* check for GL or GLU error */
502     char *where;
503     {
504     register GLenum errcode;
505    
506     while ((errcode = glGetError()) != GL_NO_ERROR) {
507     sprintf(errmsg, "OpenGL error %s: %s",
508     where, gluErrorString(errcode));
509     error(WARNING, errmsg);
510     }
511     }
512    
513    
514     static
515     xferdepth() /* load and clear depth buffer */
516     {
517     register GLfloat *dbp;
518 gwlarson 3.3 register GLubyte *cbuf;
519 gwlarson 3.1
520 gwlarson 3.3 if (depthbuffer == NULL) { /* allocate private depth buffer */
521 gwlarson 3.1 #ifdef STEREO
522     depthright = (GLfloat *)malloc(
523     odev.hres*odev.vres*sizeof(GLfloat));
524     #endif
525     depthbuffer = (GLfloat *)malloc(
526     odev.hres*odev.vres*sizeof(GLfloat));
527 gwlarson 3.5 CHECK(depthbuffer==NULL, SYSTEM, "out of memory in xferdepth");
528 gwlarson 3.1 }
529 gwlarson 3.3 /* allocate alpha buffer for portals */
530     if (gmPortals)
531 gwlarson 3.6 cbuf = (GLubyte *)malloc(odev.hres*odev.vres *
532 gwlarson 3.3 (4*sizeof(GLubyte)));
533     else
534     cbuf = NULL;
535 gwlarson 3.1 #ifdef STEREO
536     setstereobuf(STEREO_BUFFER_RIGHT);
537     glReadPixels(0, 0, odev.hres, odev.vres,
538     GL_DEPTH_COMPONENT, GL_FLOAT, depthright);
539 gwlarson 3.3 if (cbuf != NULL)
540     glReadPixels(0, 0, odev.hres, odev.vres,
541     GL_RGBA, GL_UNSIGNED_BYTE, cbuf);
542     for (dbp = depthright + odev.hres*odev.vres; dbp-- > depthright; )
543     if (cbuf != NULL && isportal(cbuf+4*(dbp-depthright)))
544     *dbp = FHUGE;
545     else
546     *dbp = mapdepth(*dbp);
547     glClear(GL_DEPTH_BUFFER_BIT);
548 gwlarson 3.1 setstereobuf(STEREO_BUFFER_LEFT);
549     odDepthMap(1, depthright);
550     #endif
551 gwlarson 3.2 /* read back depth buffer */
552 gwlarson 3.1 glReadPixels(0, 0, odev.hres, odev.vres,
553     GL_DEPTH_COMPONENT, GL_FLOAT, depthbuffer);
554 gwlarson 3.3 if (cbuf != NULL)
555 gwlarson 3.2 glReadPixels(0, 0, odev.hres, odev.vres,
556 gwlarson 3.3 GL_RGBA, GL_UNSIGNED_BYTE, cbuf);
557 gwlarson 3.1 for (dbp = depthbuffer + odev.hres*odev.vres; dbp-- > depthbuffer; )
558 gwlarson 3.3 if (cbuf != NULL && isportal(cbuf+4*(dbp-depthbuffer)))
559 gwlarson 3.2 *dbp = FHUGE;
560     else
561     *dbp = mapdepth(*dbp);
562 gwlarson 3.3 glClear(GL_DEPTH_BUFFER_BIT); /* clear system depth buffer */
563     if (cbuf != NULL)
564     free((char *)cbuf); /* free our color buffer */
565 gwlarson 3.1 odDepthMap(0, depthbuffer); /* transfer depth data */
566     }
567    
568    
569 gwlarson 3.2 static
570     freedepth() /* free recorded depth buffer */
571     {
572     if (depthbuffer == NULL)
573     return;
574     #ifdef STEREO
575     odDepthMap(1, NULL);
576     free((char *)depthright);
577     depthright = NULL;
578     #endif
579     odDepthMap(0, NULL);
580     free((char *)depthbuffer);
581     depthbuffer = NULL;
582     }
583    
584    
585 gwlarson 3.1 static double
586     getdistance(dx, dy, direc) /* distance from fore plane along view ray */
587     int dx, dy;
588     FVECT direc;
589     {
590     GLfloat gldepth;
591 gwlarson 3.3 GLubyte glcolor[4];
592 gwlarson 3.1 double dist;
593    
594     if (dx<0 | dx>=odev.hres | dy<0 | dy>=odev.vres)
595     return(FHUGE);
596     if (depthbuffer != NULL)
597     dist = depthbuffer[dy*odev.hres + dx];
598     else {
599     glReadPixels(dx,dy, 1,1, GL_DEPTH_COMPONENT,
600     GL_FLOAT, &gldepth);
601 gwlarson 3.3 if (gmPortals) {
602     glReadPixels(dx,dy, 1,1, GL_RGBA,
603     GL_UNSIGNED_BYTE, glcolor);
604     if (isportal(glcolor))
605     return(FHUGE);
606     }
607     dist = mapdepth(gldepth);
608 gwlarson 3.1 }
609     if (dist >= .99*FHUGE)
610     return(FHUGE);
611     return((dist-odev.v.vfore)/DOT(direc,odev.v.vdir));
612     }
613    
614    
615     #ifdef STEREO
616     static
617     pushright() /* push on right view & buffer */
618     {
619     double d;
620    
621     setstereobuf(STEREO_BUFFER_RIGHT);
622 gwlarson 3.7 if (viewflags & VWPERSP) {
623 gwlarson 3.1 glMatrixMode(GL_MODELVIEW);
624     glPushMatrix();
625     d = -eyesepdist / sqrt(odev.v.hn2);
626     glTranslated(d*odev.v.hvec[0], d*odev.v.hvec[1],
627     d*odev.v.hvec[2]);
628     checkglerr("setting right view");
629     }
630     }
631    
632    
633     static
634     popright() /* pop off right view & buffer */
635     {
636 gwlarson 3.7 if (viewflags & VWPERSP) {
637 gwlarson 3.1 glMatrixMode(GL_MODELVIEW);
638     glPopMatrix();
639     }
640     setstereobuf(STEREO_BUFFER_LEFT);
641     }
642     #endif
643    
644    
645     static int
646     mytmflags() /* figure out tone mapping flags */
647     {
648     extern char *progname;
649     register char *cp, *tail;
650     /* find basic name */
651     for (cp = tail = progname; *cp; cp++)
652     if (*cp == '/')
653     tail = cp+1;
654     for (cp = tail; *cp && *cp != '.'; cp++)
655     ;
656     #ifdef DEBUG
657     if (cp > tail && cp[-1] == 'h')
658     return(TM_F_HUMAN);
659     else
660     return(TM_F_CAMERA);
661     #else
662     if (cp > tail && cp[-1] == 'h')
663     return(TM_F_HUMAN|TM_F_NOSTDERR);
664     else
665     return(TM_F_CAMERA|TM_F_NOSTDERR);
666     #endif
667     }
668    
669    
670     static
671     getevent() /* get next event */
672     {
673     XNextEvent(ourdisplay, levptr(XEvent));
674     switch (levptr(XEvent)->type) {
675     case ConfigureNotify:
676     resizewindow(levptr(XConfigureEvent));
677     break;
678     case UnmapNotify:
679 gwlarson 3.7 viewflags &= ~VWMAPPED;
680 gwlarson 3.1 break;
681     case MapNotify:
682 gwlarson 3.2 odRemap(0);
683 gwlarson 3.7 viewflags |= VWMAPPED;
684 gwlarson 3.1 break;
685     case Expose:
686     fixwindow(levptr(XExposeEvent));
687     break;
688     case KeyPress:
689     getkey(levptr(XKeyPressedEvent));
690     break;
691     case ButtonPress:
692     if (FRAMESTATE(levptr(XButtonPressedEvent)->state))
693     getframe(levptr(XButtonPressedEvent));
694     else
695     getmove(levptr(XButtonPressedEvent));
696     break;
697     }
698     }
699    
700    
701     static
702     draw3dline(wp) /* draw 3d line in world coordinates */
703     register FVECT wp[2];
704     {
705     glVertex3d(wp[0][0], wp[0][1], wp[0][2]);
706     glVertex3d(wp[1][0], wp[1][1], wp[1][2]);
707     }
708    
709    
710     static
711     draw_grids(fore) /* draw holodeck section grids */
712     int fore;
713     {
714     glPushAttrib(GL_LIGHTING_BIT|GL_ENABLE_BIT);
715     glDisable(GL_LIGHTING);
716     if (fore)
717     glColor3ub(0, 255, 255);
718     else
719     glColor3ub(0, 0, 0);
720     glBegin(GL_LINES); /* draw each grid line */
721     gridlines(draw3dline);
722     glEnd();
723     checkglerr("drawing grid lines");
724     glPopAttrib();
725     }
726    
727    
728     static
729     moveview(dx, dy, mov, orb) /* move our view */
730     int dx, dy, mov, orb;
731     {
732     VIEW nv;
733     FVECT odir, v1, wip;
734     double d, d1;
735     register int li;
736     /* start with old view */
737     copystruct(&nv, &odev.v);
738     /* orient our motion */
739     if (viewray(v1, odir, &odev.v,
740     (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
741     return(0); /* outside view */
742     if (mov | orb) { /* moving relative to geometry */
743     d = getdistance(dx, dy, odir); /* distance from front plane */
744     #ifdef DOBJ
745     d1 = dobj_trace(NULL, v1, odir);
746     if (d1 < d)
747     d = d1;
748     #endif
749     if (d >= .99*FHUGE)
750     d = 0.5*(dev_zmax+dev_zmin); /* just guess */
751     VSUM(wip, v1, odir, d);
752     VSUB(odir, wip, odev.v.vp);
753     } else /* panning with constant viewpoint */
754     VCOPY(nv.vdir, odir);
755     if (orb && mov) { /* orbit left/right */
756     spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
757     VSUM(nv.vp, wip, odir, -1.);
758     spinvector(nv.vdir, nv.vdir, nv.vup, d);
759     } else if (orb) { /* orbit up/down */
760     fcross(v1, odir, nv.vup);
761     if (normalize(v1) == 0.)
762     return(0);
763     spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
764     VSUM(nv.vp, wip, odir, -1.);
765     spinvector(nv.vdir, nv.vdir, v1, d);
766     } else if (mov) { /* move forward/backward */
767     d = MOVPCT/100. * mov;
768     VSUM(nv.vp, nv.vp, odir, d);
769     }
770 gwlarson 3.7 if (!mov ^ !orb && viewflags&VWHEADLOCK) { /* restore height */
771 gwlarson 3.1 VSUM(v1, odev.v.vp, nv.vp, -1.);
772     d = DOT(v1, nv.vup);
773     VSUM(nv.vp, nv.vp, odev.v.vup, d);
774     }
775     if (setview(&nv) != NULL)
776     return(0); /* illegal view */
777     dev_view(&nv);
778 gwlarson 3.2 inpresflags |= DFL(DC_SETVIEW);
779 gwlarson 3.1 return(1);
780     }
781    
782    
783     static
784     getframe(ebut) /* get focus frame */
785     XButtonPressedEvent *ebut;
786     {
787     int startx = ebut->x, starty = ebut->y;
788     int endx, endy;
789    
790     XMaskEvent(ourdisplay, ButtonReleaseMask, levptr(XEvent));
791     endx = levptr(XButtonReleasedEvent)->x;
792     endy = levptr(XButtonReleasedEvent)->y;
793     if (endx == startx | endy == starty) {
794     XBell(ourdisplay, 0);
795     return;
796     }
797     if (endx < startx) {register int c = endx; endx = startx; startx = c;}
798     if (endy < starty) {register int c = endy; endy = starty; starty = c;}
799     sprintf(odev_args, "%.3f %.3f %.3f %.3f",
800     (startx+.5)/odev.hres, 1.-(endy+.5)/odev.vres,
801     (endx+.5)/odev.hres, 1.-(starty+.5)/odev.vres);
802     inpresflags |= DFL(DC_FOCUS);
803     }
804    
805    
806     static
807     getmove(ebut) /* get view change */
808     XButtonPressedEvent *ebut;
809     {
810     int movdir = MOVDIR(ebut->button);
811     int movorb = MOVORB(ebut->state);
812 gwlarson 3.2 int ndrawn;
813 gwlarson 3.1 Window rootw, childw;
814     int rootx, rooty, wx, wy;
815     unsigned int statemask;
816    
817     XNoOp(ourdisplay); /* makes sure we're not idle */
818    
819 gwlarson 3.7 viewflags &= ~VWSTEADY; /* flag moving view */
820 gwlarson 3.1 setglpersp(&odev.v); /* start us off in perspective */
821     while (!XCheckMaskEvent(ourdisplay,
822     ButtonReleaseMask, levptr(XEvent))) {
823     /* get cursor position */
824     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
825     &rootx, &rooty, &wx, &wy, &statemask))
826     break; /* on another screen */
827     /* compute view motion */
828     if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) {
829     sleep(1);
830     continue; /* cursor in bad place */
831     }
832     draw_grids(1); /* redraw grid */
833     #ifdef STEREO
834     pushright();
835     draw_grids(1);
836 gwlarson 3.3 ndrawn = gmDrawGeom();
837 gwlarson 3.1 #ifdef DOBJ
838 gwlarson 3.3 ndrawn += dobj_render();
839 gwlarson 3.1 #endif
840 gwlarson 3.6 if (ndrawn && gmPortals)
841     gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
842 gwlarson 3.1 popright();
843     #endif
844     /* redraw octrees */
845 gwlarson 3.3 ndrawn = gmDrawGeom();
846 gwlarson 3.1 #ifdef DOBJ
847 gwlarson 3.2 ndrawn += dobj_render(); /* redraw objects */
848 gwlarson 3.1 #endif
849 gwlarson 3.6 if (ndrawn && gmPortals)
850 gwlarson 3.3 gmDrawPortals(PORTRED, PORTGRN, PORTBLU, PORTALP);
851 gwlarson 3.6 glXSwapBuffers(ourdisplay, gwind);
852     if (!ndrawn)
853 gwlarson 3.2 sleep(1); /* for reasonable interaction */
854 gwlarson 3.1 }
855     if (!(inpresflags & DFL(DC_SETVIEW))) { /* do final motion */
856     movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
857     wx = levptr(XButtonReleasedEvent)->x;
858     wy = levptr(XButtonReleasedEvent)->y;
859     moveview(wx, odev.vres-1-wy, movdir, movorb);
860     }
861 gwlarson 3.7 viewflags |= VWSTEADY; /* done goofing around */
862 gwlarson 3.1 }
863    
864    
865     static
866     setglpersp(vp) /* set perspective view in GL */
867     register VIEW *vp;
868     {
869     double d, xmin, xmax, ymin, ymax;
870     GLfloat vec[4];
871     double depthlim[2];
872     /* set depth limits */
873 gwlarson 3.2 gmDepthLimit(depthlim, odev.v.vp, odev.v.vdir);
874 gwlarson 3.1 if (depthlim[0] >= depthlim[1]) {
875     dev_zmin = 1.;
876     dev_zmax = 100.;
877     } else {
878     dev_zmin = 0.5*depthlim[0];
879 gwlarson 3.2 dev_zmax = 1.75*depthlim[1];
880 gwlarson 3.1 if (dev_zmin > dev_zmax/5.)
881     dev_zmin = dev_zmax/5.;
882     }
883     if (odev.v.vfore > FTINY)
884     dev_zmin = odev.v.vfore;
885     if (odev.v.vaft > FTINY)
886     dev_zmax = odev.v.vaft;
887     if (dev_zmin < dev_zmax/100.)
888     dev_zmin = dev_zmax/100.;
889     setzrat();
890     xmax = dev_zmin * tan(PI/180./2. * odev.v.horiz);
891     xmin = -xmax;
892     d = odev.v.hoff * (xmax - xmin);
893     xmin += d; xmax += d;
894     ymax = dev_zmin * tan(PI/180./2. * odev.v.vert);
895     ymin = -ymax;
896     d = odev.v.voff * (ymax - ymin);
897     ymin += d; ymax += d;
898     /* set view matrix */
899     glMatrixMode(GL_PROJECTION);
900     glLoadIdentity();
901     glFrustum(xmin, xmax, ymin, ymax, dev_zmin, dev_zmax);
902     gluLookAt(odev.v.vp[0], odev.v.vp[1], odev.v.vp[2],
903     odev.v.vp[0] + odev.v.vdir[0],
904     odev.v.vp[1] + odev.v.vdir[1],
905     odev.v.vp[2] + odev.v.vdir[2],
906     odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]);
907     checkglerr("setting perspective view");
908     vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
909     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
910     vec[0] = -odev.v.vdir[0];
911     vec[1] = -odev.v.vdir[1];
912     vec[2] = -odev.v.vdir[2];
913     vec[3] = 0.;
914     glLightfv(GL_LIGHT0, GL_POSITION, vec);
915     vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.;
916     glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
917     glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
918     vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.;
919     glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
920     glEnable(GL_LIGHT0);
921     glEnable(GL_LIGHTING); /* light our GL objects */
922     glShadeModel(GL_SMOOTH);
923 gwlarson 3.7 viewflags &= ~VWORTHO;
924     viewflags |= VWPERSP;
925 gwlarson 3.1 }
926    
927    
928     static
929     setglortho() /* set up orthographic view for cone drawing */
930     {
931 gwlarson 3.6 glDrawBuffer(GL_FRONT); /* use single-buffer mode */
932 gwlarson 3.1 /* set view matrix */
933     glMatrixMode(GL_PROJECTION);
934     glLoadIdentity();
935     glOrtho(0., (double)odev.hres, 0., (double)odev.vres,
936     0.001*OMAXDEPTH, 1.001*(-OMAXDEPTH));
937     checkglerr("setting orthographic view");
938     glDisable(GL_LIGHTING); /* cones are constant color */
939     glShadeModel(GL_FLAT);
940 gwlarson 3.7 viewflags &= ~VWPERSP;
941     viewflags |= VWORTHO;
942 gwlarson 3.1 }
943    
944    
945     static
946     wipeclean() /* prepare for redraw */
947     {
948 gwlarson 3.6 glDrawBuffer(GL_BACK); /* use double-buffer mode */
949     /* clear buffers */
950 gwlarson 3.1 #ifdef STEREO
951     setstereobuf(STEREO_BUFFER_RIGHT);
952 gwlarson 3.6 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
953 gwlarson 3.1 setstereobuf(STEREO_BUFFER_LEFT);
954     #endif
955 gwlarson 3.6 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
956     freedepth();
957 gwlarson 3.7 if ((viewflags&(VWCHANGE|VWSTEADY)) ==
958     (VWCHANGE|VWSTEADY)) { /* clear samples if new */
959 gwlarson 3.1 odClean();
960 gwlarson 3.7 viewflags &= ~VWCHANGE; /* change noted */
961     }
962 gwlarson 3.1 setglpersp(&odev.v); /* reset view & clipping planes */
963     }
964    
965    
966     static
967     getkey(ekey) /* get input key */
968     register XKeyPressedEvent *ekey;
969     {
970     Window rootw, childw;
971     int rootx, rooty, wx, wy;
972     unsigned int statemask;
973     int n;
974     char buf[8];
975    
976     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
977     if (n != 1)
978     return;
979     switch (buf[0]) {
980     case 'h': /* turn on height motion lock */
981 gwlarson 3.7 viewflags |= VWHEADLOCK;
982 gwlarson 3.1 return;
983     case 'H': /* turn off height motion lock */
984 gwlarson 3.7 viewflags &= ~VWHEADLOCK;
985 gwlarson 3.1 return;
986     case 'l': /* retrieve last view */
987     inpresflags |= DFL(DC_LASTVIEW);
988     return;
989     case 'p': /* pause computation */
990     inpresflags |= DFL(DC_PAUSE);
991     return;
992     case 'v': /* spit out view */
993     inpresflags |= DFL(DC_GETVIEW);
994     return;
995     case 'f': /* frame view position */
996     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
997     &rootx, &rooty, &wx, &wy, &statemask))
998     return; /* on another screen */
999     sprintf(odev_args, "%.4f %.4f", (wx+.5)/odev.hres,
1000     1.-(wy+.5)/odev.vres);
1001     inpresflags |= DFL(DC_FOCUS);
1002     return;
1003     case 'F': /* unfocus */
1004     odev_args[0] = '\0';
1005     inpresflags |= DFL(DC_FOCUS);
1006     return;
1007     case '\n':
1008     case '\r': /* resume computation */
1009     inpresflags |= DFL(DC_RESUME);
1010     return;
1011     case CTRL('R'): /* redraw screen */
1012 gwlarson 3.2 odRemap(0);
1013 gwlarson 3.6 glClear(GL_DEPTH_BUFFER_BIT);
1014 gwlarson 3.1 #ifdef STEREO
1015     setstereobuf(STEREO_BUFFER_RIGHT);
1016 gwlarson 3.6 glClear(GL_DEPTH_BUFFER_BIT);
1017 gwlarson 3.1 setstereobuf(STEREO_BUFFER_LEFT);
1018     #endif
1019     return;
1020     case CTRL('L'): /* refresh from server */
1021     if (inpresflags & DFL(DC_REDRAW))
1022     return;
1023     XRaiseWindow(ourdisplay, gwind);
1024     XFlush(ourdisplay);
1025     sleep(1);
1026     wipeclean(); /* fresh display */
1027 gwlarson 3.2 odRemap(1); /* fresh tone mapping */
1028 gwlarson 3.1 dev_flush(); /* draw octrees */
1029     inpresflags |= DFL(DC_REDRAW); /* resend values from server */
1030     rayqleft = 0; /* hold off update */
1031     return;
1032     case 'K': /* kill rtrace process(es) */
1033     inpresflags |= DFL(DC_KILL);
1034     break;
1035     case 'R': /* restart rtrace */
1036     inpresflags |= DFL(DC_RESTART);
1037     break;
1038     case 'C': /* clobber holodeck */
1039     inpresflags |= DFL(DC_CLOBBER);
1040     break;
1041     case 'q': /* quit the program */
1042     inpresflags |= DFL(DC_QUIT);
1043     return;
1044     default:
1045     XBell(ourdisplay, 0);
1046     return;
1047     }
1048     }
1049    
1050    
1051     static
1052     fixwindow(eexp) /* repair damage to window */
1053     register XExposeEvent *eexp;
1054     {
1055     int xmin, ymin, xmax, ymax;
1056    
1057     if (odev.hres == 0 | odev.vres == 0) { /* first exposure */
1058     resizewindow((XConfigureEvent *)eexp);
1059     return;
1060     }
1061     xmin = eexp->x; xmax = eexp->x + eexp->width;
1062     ymin = odev.vres - eexp->y - eexp->height; ymax = odev.vres - eexp->y;
1063     /* clear portion of depth */
1064 gwlarson 3.2 glPushAttrib(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
1065 gwlarson 3.1 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1066     glDepthFunc(GL_ALWAYS);
1067     glBegin(GL_POLYGON);
1068     glVertex3i(xmin, ymin, OMAXDEPTH);
1069     glVertex3i(xmax, ymin, OMAXDEPTH);
1070     glVertex3i(xmax, ymax, OMAXDEPTH);
1071     glVertex3i(xmin, ymax, OMAXDEPTH);
1072     glEnd();
1073     #ifdef STEREO
1074     setstereobuf(STEREO_BUFFER_RIGHT);
1075     glBegin(GL_POLYGON);
1076     glVertex3i(xmin, ymin, OMAXDEPTH);
1077     glVertex3i(xmax, ymin, OMAXDEPTH);
1078     glVertex3i(xmax, ymax, OMAXDEPTH);
1079     glVertex3i(xmin, ymax, OMAXDEPTH);
1080     glEnd();
1081     odRedraw(1, xmin, ymin, xmax, ymax);
1082     setstereobuf(STEREO_BUFFER_LEFT);
1083     #endif
1084 gwlarson 3.2 glPopAttrib();
1085 gwlarson 3.1 odRedraw(0, xmin, ymin, xmax, ymax);
1086     }
1087    
1088    
1089     static
1090     resizewindow(ersz) /* resize window */
1091     register XConfigureEvent *ersz;
1092     {
1093     glViewport(0, 0, ersz->width, ersz->height);
1094    
1095     if (ersz->width == odev.hres && ersz->height == odev.vres)
1096     return;
1097    
1098     odev.hres = ersz->width;
1099     odev.vres = ersz->height;
1100    
1101     odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
1102     odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
1103    
1104 gwlarson 3.2 inpresflags |= DFL(DC_SETVIEW);
1105 gwlarson 3.7 viewflags |= VWCHANGE;
1106 gwlarson 3.1 }