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

# 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 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 #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 static int viewflags; /* what's happening with view */
125
126 static int resizewindow(), getevent(), getkey(), moveview(), wipeclean(),
127 xferdepth(), freedepth(), setglortho(),
128 setglpersp(), getframe(), getmove(), fixwindow(), mytmflags();
129
130 static double getdistance();
131
132 #ifdef STEREO
133 static int pushright(), popright();
134 #endif
135
136 extern int gmPortals; /* GL portal list id */
137
138 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 #if (PORTALP<0)
147 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 GLX_DEPTH_SIZE,15, None};
158 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 #endif
163 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 CHECK(ourdisplay==NULL, USER,
176 "cannot open X-windows; DISPLAY variable set?");
177 #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 "wrong video mode: run \"/usr/gfx/setmon -n STR_TOP\" first");
185 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 if (ourvinf == NULL)
194 ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlOK);
195 CHECK(ourvinf==NULL, USER, "no suitable visuals available");
196 /* 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 CHECK(gwind==0, SYSTEM, "cannot create window");
228 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 glEnable(GL_DITHER);
252 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 viewflags = VWSTEADY; /* view starts static */
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 viewflags |= VWCHANGE;
359 }
360 wipeclean();
361 return(1);
362 }
363
364
365 dev_section(gfn, pfn) /* add octree for geometry rendering */
366 char *gfn, *pfn;
367 {
368 extern char *index();
369 char *cp;
370
371 if (gfn == NULL) {
372 gmEndGeom();
373 gmEndPortal();
374 wipeclean(); /* new geometry, so redraw it */
375 return;
376 }
377 if (access(gfn, R_OK) == 0)
378 gmNewGeom(gfn);
379 #ifdef DEBUG
380 else {
381 sprintf(errmsg, "cannot load octree \"%s\"", gfn);
382 error(WARNING, errmsg);
383 }
384 #endif
385 if (pfn != NULL)
386 gmNewPortal(pfn);
387 }
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 if ((viewflags&(VWMAPPED|VWPERSP)) == (VWMAPPED|VWPERSP)) {
456 #ifdef STEREO
457 pushright(); /* draw right eye */
458 ndrawn = gmDrawGeom();
459 #ifdef DOBJ
460 ndrawn += dobj_render();
461 #endif
462 if (ndrawn && gmPortals)
463 gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
464 checkglerr("rendering right eye");
465 popright(); /* draw left eye */
466 #endif
467 ndrawn = gmDrawGeom();
468 #ifdef DOBJ
469 ndrawn += dobj_render();
470 #endif
471 if (ndrawn && gmPortals)
472 gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
473 glXSwapBuffers(ourdisplay, gwind);
474 checkglerr("rendering base view");
475 }
476 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 #ifdef STEREO
488 pushright();
489 odUpdate(1); /* draw right eye */
490 popright();
491 #endif
492 odUpdate(0); /* draw left eye */
493 glFlush(); /* flush OpenGL */
494 }
495 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 register GLubyte *cbuf;
519
520 if (depthbuffer == NULL) { /* allocate private depth buffer */
521 #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 CHECK(depthbuffer==NULL, SYSTEM, "out of memory in xferdepth");
528 }
529 /* allocate alpha buffer for portals */
530 if (gmPortals)
531 cbuf = (GLubyte *)malloc(odev.hres*odev.vres *
532 (4*sizeof(GLubyte)));
533 else
534 cbuf = NULL;
535 #ifdef STEREO
536 setstereobuf(STEREO_BUFFER_RIGHT);
537 glReadPixels(0, 0, odev.hres, odev.vres,
538 GL_DEPTH_COMPONENT, GL_FLOAT, depthright);
539 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 setstereobuf(STEREO_BUFFER_LEFT);
549 odDepthMap(1, depthright);
550 #endif
551 /* read back depth buffer */
552 glReadPixels(0, 0, odev.hres, odev.vres,
553 GL_DEPTH_COMPONENT, GL_FLOAT, depthbuffer);
554 if (cbuf != NULL)
555 glReadPixels(0, 0, odev.hres, odev.vres,
556 GL_RGBA, GL_UNSIGNED_BYTE, cbuf);
557 for (dbp = depthbuffer + odev.hres*odev.vres; dbp-- > depthbuffer; )
558 if (cbuf != NULL && isportal(cbuf+4*(dbp-depthbuffer)))
559 *dbp = FHUGE;
560 else
561 *dbp = mapdepth(*dbp);
562 glClear(GL_DEPTH_BUFFER_BIT); /* clear system depth buffer */
563 if (cbuf != NULL)
564 free((char *)cbuf); /* free our color buffer */
565 odDepthMap(0, depthbuffer); /* transfer depth data */
566 }
567
568
569 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 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 GLubyte glcolor[4];
592 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 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 }
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 if (viewflags & VWPERSP) {
623 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 if (viewflags & VWPERSP) {
637 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 viewflags &= ~VWMAPPED;
680 break;
681 case MapNotify:
682 odRemap(0);
683 viewflags |= VWMAPPED;
684 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 if (!mov ^ !orb && viewflags&VWHEADLOCK) { /* restore height */
771 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 inpresflags |= DFL(DC_SETVIEW);
779 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 int ndrawn;
813 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 viewflags &= ~VWSTEADY; /* flag moving view */
820 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 ndrawn = gmDrawGeom();
837 #ifdef DOBJ
838 ndrawn += dobj_render();
839 #endif
840 if (ndrawn && gmPortals)
841 gmDrawPortals(PORTRED,PORTGRN,PORTBLU,PORTALP);
842 popright();
843 #endif
844 /* redraw octrees */
845 ndrawn = gmDrawGeom();
846 #ifdef DOBJ
847 ndrawn += dobj_render(); /* redraw objects */
848 #endif
849 if (ndrawn && gmPortals)
850 gmDrawPortals(PORTRED, PORTGRN, PORTBLU, PORTALP);
851 glXSwapBuffers(ourdisplay, gwind);
852 if (!ndrawn)
853 sleep(1); /* for reasonable interaction */
854 }
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 viewflags |= VWSTEADY; /* done goofing around */
862 }
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 gmDepthLimit(depthlim, odev.v.vp, odev.v.vdir);
874 if (depthlim[0] >= depthlim[1]) {
875 dev_zmin = 1.;
876 dev_zmax = 100.;
877 } else {
878 dev_zmin = 0.5*depthlim[0];
879 dev_zmax = 1.75*depthlim[1];
880 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 viewflags &= ~VWORTHO;
924 viewflags |= VWPERSP;
925 }
926
927
928 static
929 setglortho() /* set up orthographic view for cone drawing */
930 {
931 glDrawBuffer(GL_FRONT); /* use single-buffer mode */
932 /* 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 viewflags &= ~VWPERSP;
941 viewflags |= VWORTHO;
942 }
943
944
945 static
946 wipeclean() /* prepare for redraw */
947 {
948 glDrawBuffer(GL_BACK); /* use double-buffer mode */
949 /* clear buffers */
950 #ifdef STEREO
951 setstereobuf(STEREO_BUFFER_RIGHT);
952 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
953 setstereobuf(STEREO_BUFFER_LEFT);
954 #endif
955 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
956 freedepth();
957 if ((viewflags&(VWCHANGE|VWSTEADY)) ==
958 (VWCHANGE|VWSTEADY)) { /* clear samples if new */
959 odClean();
960 viewflags &= ~VWCHANGE; /* change noted */
961 }
962 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 viewflags |= VWHEADLOCK;
982 return;
983 case 'H': /* turn off height motion lock */
984 viewflags &= ~VWHEADLOCK;
985 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 odRemap(0);
1013 glClear(GL_DEPTH_BUFFER_BIT);
1014 #ifdef STEREO
1015 setstereobuf(STEREO_BUFFER_RIGHT);
1016 glClear(GL_DEPTH_BUFFER_BIT);
1017 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 odRemap(1); /* fresh tone mapping */
1028 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 glPushAttrib(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
1065 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 glPopAttrib();
1085 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 inpresflags |= DFL(DC_SETVIEW);
1105 viewflags |= VWCHANGE;
1106 }