ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ogl.c
Revision: 3.5
Committed: Mon Dec 21 15:31:49 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.4: +6 -9 lines
Log Message:
replaced error calls with CHECK in some places

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