ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ogl.c
Revision: 3.2
Committed: Sun Dec 20 20:36:48 1998 UTC (25 years, 3 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.1: +82 -33 lines
Log Message:
added port drawing into alpha buffer mask
changed tone remapping call

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