ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ogl.c
Revision: 3.6
Committed: Mon Dec 21 19:17:28 1998 UTC (25 years, 3 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.5: +40 -34 lines
Log Message:
switched to double-buffered display

File Contents

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