ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ogl.c
Revision: 3.28
Committed: Sun Jul 24 19:53:08 2005 UTC (18 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1
Changes since 3.27: +3 -3 lines
Log Message:
Compile fixes and version update for 3.7 release

File Contents

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