ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_glx.c
Revision: 3.28
Committed: Thu Jun 10 15:22:21 1999 UTC (24 years, 10 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.27: +57 -39 lines
Log Message:
Implemented sample quadtree in place of triangle quadtree
Made geometric predicates more robust
Added #define LORES which utilizes a single precision floating point
  sample array, the default is a double sample array
Added topology DEBUG commands (for DEBUG > 1)
Made code optimizations

File Contents

# User Rev Content
1 gwlarson 3.28 /* Copyright (c) 1999 Silicon Graphics, Inc. */
2 gregl 3.1
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ SGI";
5     #endif
6    
7     /*
8     * OpenGL GLX driver for holodeck display.
9 gwlarson 3.19 * Based on old GLX driver using cones.
10     *
11     * Define symbol STEREO for stereo viewing.
12     * Define symbol DOBJ for display object viewing.
13 gregl 3.1 */
14    
15 gwlarson 3.19 #ifdef NOSTEREO
16     #ifdef STEREO
17     #undef STEREO
18     #else
19     #undef NOSTEREO
20     #endif
21     #endif
22    
23 gregl 3.1 #include "standard.h"
24    
25 gwlarson 3.19 #include <GL/glx.h>
26     #include <GL/glu.h>
27     #ifdef STEREO
28     #include <X11/extensions/SGIStereo.h>
29     #endif
30 gwlarson 3.24
31     #include "rhd_sample.h"
32 gwlarson 3.19 #ifdef DOBJ
33     #include "rhdobj.h"
34     #endif
35 gregl 3.1
36 gwlarson 3.19 #include "x11icon.h"
37 gregl 3.1
38 gregl 3.10 #ifndef RAYQLEN
39 gwlarson 3.24 #define RAYQLEN 1024 /* max. rays to queue before flush */
40 gregl 3.10 #endif
41    
42 gregl 3.1 #ifndef FEQ
43     #define FEQ(a,b) ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
44     #endif
45    
46 gregl 3.2 #define GAMMA 1.4 /* default gamma correction */
47 gregl 3.1
48 gwlarson 3.24 #define FRAMESTATE(s) (((s)&(ShiftMask|ControlMask))==(ShiftMask|ControlMask))
49    
50 gregl 3.1 #define MOVPCT 7 /* percent distance to move /frame */
51     #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
52     #define MOVDEG (-5) /* degrees to orbit CW/down /frame */
53     #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
54    
55 gwlarson 3.19 #ifndef TARGETFPS
56 gwlarson 3.28 #define TARGETFPS 2.0 /* target frames/sec during motion */
57 gwlarson 3.19 #endif
58    
59 gregl 3.1 #define MINWIDTH 480 /* minimum graphics window width */
60     #define MINHEIGHT 400 /* minimum graphics window height */
61    
62     #define VIEWDIST 356 /* assumed viewing distance (mm) */
63    
64     #define BORWIDTH 5 /* border width */
65    
66 gwlarson 3.19 #define setstereobuf(bid) (glXWaitGL(), \
67     XSGISetStereoBuffer(ourdisplay, gwind, bid), \
68     glXWaitX())
69    
70 gregl 3.1 #define ourscreen DefaultScreen(ourdisplay)
71     #define ourroot RootWindow(ourdisplay,ourscreen)
72     #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
73     ButtonPressMask|ButtonReleaseMask)
74    
75     #define levptr(etype) ((etype *)&currentevent)
76    
77     struct driver odev; /* global device driver structure */
78    
79 gwlarson 3.24 char odev_args[64]; /* command arguments */
80    
81 gwlarson 3.23 #ifdef STEREO
82 gwlarson 3.19 static VIEW vwright; /* right eye view */
83 gwlarson 3.23 #endif
84 gwlarson 3.19
85     static int rayqleft = 0; /* rays left to queue before flush */
86    
87 gregl 3.1 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 gwlarson 3.19 static double mindpth, maxdpth; /* min. and max. depth */
100 gregl 3.1
101 gwlarson 3.19 double dev_zmin, dev_zmax; /* fore and aft clipping plane dist. */
102 gregl 3.4
103 gregl 3.1 static int inpresflags; /* input result flags */
104    
105     static int headlocked = 0; /* lock vertical motion */
106    
107 gwlarson 3.19 static int resizewindow(), getevent(), getkey(), moveview(), wipeclean(),
108 gwlarson 3.24 setglpersp(), getframe(), getmove(), fixwindow(), mytmflags();
109 gregl 3.1
110 gwlarson 3.19 #ifdef STEREO
111     static int pushright(), popright();
112     #endif
113 gwlarson 3.28 static double getdistance();
114     #define mapdepth(d) ((d)> 0.9995 ? FHUGE: dev_zmin/ \
115     (1.-(d)*(1.-dev_zmin/dev_zmax)))
116 gregl 3.1
117 gwlarson 3.19 extern time_t time();
118    
119    
120     dev_open(id) /* initialize GLX driver */
121 gregl 3.1 char *id;
122     {
123     extern char *getenv();
124 gregl 3.15 static RGBPRIMS myprims = STDPRIMS;
125 gregl 3.1 static int atlBest[] = {GLX_RGBA, GLX_RED_SIZE,8,
126     GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8,
127 gregl 3.4 GLX_DEPTH_SIZE,15, None};
128 gregl 3.15 char *ev;
129 gregl 3.1 double gamval = GAMMA;
130 gregl 3.15 RGBPRIMP dpri = stdprims;
131 gregl 3.1 XSetWindowAttributes ourwinattr;
132     XWMHints ourxwmhints;
133     XSizeHints oursizhints;
134 gwlarson 3.19 /* check for unsupported stereo */
135     #ifdef NOSTEREO
136 gwlarson 3.22 error(INTERNAL, "stereo display driver unavailable");
137 gwlarson 3.19 #endif
138 gregl 3.1 /* open display server */
139     ourdisplay = XOpenDisplay(NULL);
140     if (ourdisplay == NULL)
141     error(USER, "cannot open X-windows; DISPLAY variable set?\n");
142 gwlarson 3.19 #ifdef STEREO
143     switch (XSGIQueryStereoMode(ourdisplay, ourroot)) {
144     case STEREO_TOP:
145     case STEREO_BOTTOM:
146     break;
147     case STEREO_OFF:
148     error(USER,
149     "wrong video mode: run \"/usr/gfx/setmon -n STR_TOP\" first");
150     case X_STEREO_UNSUPPORTED:
151     error(USER, "stereo mode not supported on this screen");
152     default:
153     error(INTERNAL, "unknown stereo mode");
154     }
155     #endif
156 gregl 3.1 /* find a usable visual */
157     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest);
158     if (ourvinf == NULL)
159     error(USER, "no suitable visuals available");
160     /* get a context */
161     gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE);
162     /* set gamma and tone mapping */
163 gregl 3.15 if ((ev = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
164     || (ev = getenv("DISPLAY_GAMMA")) != NULL)
165     gamval = atof(ev);
166     if ((ev = getenv("DISPLAY_PRIMARIES")) != NULL &&
167     sscanf(ev, "%f %f %f %f %f %f %f %f",
168     &myprims[RED][CIEX],&myprims[RED][CIEY],
169     &myprims[GRN][CIEX],&myprims[GRN][CIEY],
170     &myprims[BLU][CIEX],&myprims[BLU][CIEY],
171     &myprims[WHT][CIEX],&myprims[WHT][CIEY]) >= 6)
172     dpri = myprims;
173     if (tmInit(mytmflags(), dpri, gamval) == NULL)
174 gregl 3.1 error(SYSTEM, "not enough memory in dev_open");
175     /* open window */
176     ourwinattr.background_pixel = ourblack;
177     ourwinattr.border_pixel = ourblack;
178     ourwinattr.event_mask = ourmask;
179     /* this is stupid */
180     ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
181     ourvinf->visual, AllocNone);
182     gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
183     DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
184 gwlarson 3.19 #ifdef STEREO
185     (DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH)/2,
186     #else
187 gregl 3.1 DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
188 gwlarson 3.19 #endif
189 gregl 3.1 BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual,
190     CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
191     if (gwind == 0)
192     error(SYSTEM, "cannot create window\n");
193     XStoreName(ourdisplay, gwind, id);
194     /* set window manager hints */
195     ourxwmhints.flags = InputHint|IconPixmapHint;
196     ourxwmhints.input = True;
197     ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
198     gwind, x11icon_bits, x11icon_width, x11icon_height);
199     XSetWMHints(ourdisplay, gwind, &ourxwmhints);
200     oursizhints.min_width = MINWIDTH;
201 gwlarson 3.19 #ifdef STEREO
202     oursizhints.min_height = MINHEIGHT/2;
203     oursizhints.max_width = DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH;
204     oursizhints.max_height = (DisplayHeight(ourdisplay,ourscreen) -
205     2*BORWIDTH)/2;
206     oursizhints.flags = PMinSize|PMaxSize;
207     #else
208 gregl 3.1 oursizhints.min_height = MINHEIGHT;
209     oursizhints.flags = PMinSize;
210 gwlarson 3.19 #endif
211 gregl 3.1 XSetNormalHints(ourdisplay, gwind, &oursizhints);
212 gregl 3.2 /* set GLX context */
213     glXMakeCurrent(ourdisplay, gwind, gctx);
214     glEnable(GL_DEPTH_TEST);
215     glDepthFunc(GL_LEQUAL);
216 gwlarson 3.19 glShadeModel(GL_SMOOTH);
217 gregl 3.2 glDisable(GL_DITHER);
218 gregl 3.4 glDisable(GL_CULL_FACE);
219 gregl 3.1 /* figure out sensible view */
220     pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
221     DisplayWidth(ourdisplay, ourscreen);
222     pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
223     DisplayHeight(ourdisplay, ourscreen);
224 gwlarson 3.19 #ifdef STEREO
225     pheight *= 2.;
226     setstereobuf(STEREO_BUFFER_LEFT);
227     #endif
228 gwlarson 3.23 checkglerr("setting rendering parameters");
229 gregl 3.1 copystruct(&odev.v, &stdview);
230     odev.v.type = VT_PER;
231 gregl 3.2 /* map the window */
232     XMapWindow(ourdisplay, gwind);
233     dev_input(); /* sets size and view angles */
234 gwlarson 3.19 /* allocate our samples */
235     if (!smInit(DisplayWidth(ourdisplay,ourscreen) *
236     DisplayHeight(ourdisplay,ourscreen) / 10))
237 gregl 3.2 error(SYSTEM, "insufficient memory for value storage");
238 gwlarson 3.19 mindpth = FHUGE; maxdpth = FTINY;
239 gregl 3.1 odev.name = id;
240     odev.ifd = ConnectionNumber(ourdisplay);
241     }
242    
243    
244     dev_close() /* close our display and free resources */
245     {
246 gwlarson 3.19 smInit(0);
247     #ifdef DOBJ
248     dobj_cleanup();
249     #endif
250 gregl 3.1 glXMakeCurrent(ourdisplay, None, NULL);
251     glXDestroyContext(ourdisplay, gctx);
252     XDestroyWindow(ourdisplay, gwind);
253     gwind = 0;
254     XCloseDisplay(ourdisplay);
255     ourdisplay = NULL;
256     tmDone(NULL);
257     odev.v.type = 0;
258     odev.hres = odev.vres = 0;
259     odev.ifd = -1;
260     }
261    
262    
263 gwlarson 3.19 dev_clear() /* clear our representation */
264 gregl 3.14 {
265 gwlarson 3.19 smInit(rsL.max_samp);
266 gwlarson 3.28 wipeclean(1);
267 gregl 3.14 rayqleft = 0; /* hold off update */
268     }
269    
270    
271 gregl 3.1 int
272     dev_view(nv) /* assign new driver view */
273     register VIEW *nv;
274     {
275 gwlarson 3.19 double d;
276    
277     if (nv->type != VT_PER || /* check view legality */
278 gregl 3.4 nv->horiz > 160. || nv->vert > 160.) {
279 gregl 3.1 error(COMMAND, "illegal view type/angle");
280 gregl 3.4 nv->type = odev.v.type;
281 gregl 3.1 nv->horiz = odev.v.horiz;
282     nv->vert = odev.v.vert;
283     return(0);
284     }
285 gwlarson 3.22 if (nv != &odev.v) {
286     /* resize window? */
287     if (!FEQ(nv->horiz,odev.v.horiz) ||
288     !FEQ(nv->vert,odev.v.vert)) {
289     int dw = DisplayWidth(ourdisplay,ourscreen);
290     int dh = DisplayHeight(ourdisplay,ourscreen);
291 gregl 3.1
292 gwlarson 3.22 dw -= 25; /* for window frame */
293     dh -= 50;
294 gwlarson 3.19 #ifdef STEREO
295 gwlarson 3.22 dh /= 2;
296 gwlarson 3.19 #endif
297 gwlarson 3.22 odev.hres = 2.*VIEWDIST/pwidth *
298     tan(PI/180./2.*nv->horiz);
299     odev.vres = 2.*VIEWDIST/pheight *
300     tan(PI/180./2.*nv->vert);
301     if (odev.hres > dw) {
302     odev.vres = dw * odev.vres / odev.hres;
303     odev.hres = dw;
304     }
305     if (odev.vres > dh) {
306     odev.hres = dh * odev.hres / odev.vres;
307     odev.vres = dh;
308     }
309     XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
310     dev_input(); /* get resize event */
311 gregl 3.1 }
312 gwlarson 3.22 copystruct(&odev.v, nv); /* setview() already called */
313 gwlarson 3.27 }
314 gwlarson 3.19 #ifdef STEREO
315 gwlarson 3.27 copystruct(&vwright, nv);
316     d = eyesepdist / sqrt(nv->hn2);
317     VSUM(vwright.vp, nv->vp, nv->hvec, d);
318     /* setview(&vwright); -- Unnecessary */
319 gwlarson 3.19 #endif
320 gwlarson 3.28 wipeclean(0);
321 gregl 3.1 return(1);
322 gwlarson 3.18 }
323    
324    
325 gwlarson 3.26 dev_section(gfn, pfn) /* add octree for geometry rendering */
326     char *gfn, *pfn;
327 gwlarson 3.25 {
328     /* unimplemented */
329     }
330    
331    
332 gwlarson 3.18 dev_auxcom(cmd, args) /* process an auxiliary command */
333     char *cmd, *args;
334     {
335 gwlarson 3.19 #ifdef DOBJ
336     if (dobj_command(cmd, args) >= 0)
337     return;
338     #endif
339 gwlarson 3.18 sprintf(errmsg, "%s: unknown command", cmd);
340     error(COMMAND, errmsg);
341 gregl 3.1 }
342    
343    
344 gwlarson 3.17 VIEW *
345     dev_auxview(n, hvres) /* return nth auxiliary view */
346     int n;
347     int hvres[2];
348     {
349     hvres[0] = odev.hres; hvres[1] = odev.vres;
350 gwlarson 3.19 if (n == 0)
351     return(&odev.v);
352     #ifdef STEREO
353     if (n == 1)
354     return(&vwright);
355     #endif
356     return(NULL);
357 gwlarson 3.17 }
358    
359    
360 gregl 3.1 int
361     dev_input() /* get X11 input */
362     {
363     inpresflags = 0;
364    
365     do
366     getevent();
367    
368 gwlarson 3.19 while (XPending(ourdisplay) > 0);
369 gregl 3.1
370 gwlarson 3.19 odev.inpready = 0;
371    
372 gregl 3.1 return(inpresflags);
373     }
374    
375    
376 gwlarson 3.19 dev_value(c, d, p) /* add a pixel value to our mesh */
377     COLR c;
378     FVECT d, p;
379     {
380     double depth;
381     #ifdef DOBJ
382     if (dobj_lightsamp != NULL) { /* in light source sampling */
383     (*dobj_lightsamp)(c, d, p);
384     return;
385     }
386     #endif
387 gwlarson 3.22 if (p != NULL) { /* add depth to our range */
388 gwlarson 3.19 depth = (p[0] - odev.v.vp[0])*d[0] +
389     (p[1] - odev.v.vp[1])*d[1] +
390     (p[2] - odev.v.vp[2])*d[2];
391     if (depth > FTINY) {
392     if (depth < mindpth)
393     mindpth = depth;
394     if (depth > maxdpth)
395     maxdpth = depth;
396     }
397     }
398 gwlarson 3.22 smNewSamp(c, d, p); /* add to display representation */
399 gwlarson 3.19 if (!--rayqleft)
400     dev_flush(); /* flush output */
401     }
402    
403    
404 gregl 3.4 int
405     dev_flush() /* flush output */
406 gregl 3.1 {
407 gwlarson 3.22 if (mapped) {
408 gwlarson 3.19 #ifdef STEREO
409 gwlarson 3.22 pushright(); /* update right eye */
410 gwlarson 3.28 smUpdate(&vwright, MAXQUALITY);
411 gwlarson 3.19 #ifdef DOBJ
412 gwlarson 3.22 dobj_render(); /* usually in foreground */
413 gwlarson 3.19 #endif
414 gwlarson 3.22 popright(); /* update left eye */
415 gwlarson 3.19 #endif
416 gwlarson 3.28 smUpdate(&odev.v, MAXQUALITY);
417 gwlarson 3.22 checkglerr("rendering mesh");
418 gwlarson 3.19 #ifdef DOBJ
419 gwlarson 3.22 dobj_render();
420 gwlarson 3.19 #endif
421 gwlarson 3.22 glFlush(); /* flush OGL */
422     }
423 gregl 3.10 rayqleft = RAYQLEN;
424 gwlarson 3.19 /* flush X11 and return # pending */
425     return(odev.inpready = XPending(ourdisplay));
426 gregl 3.1 }
427    
428    
429 gwlarson 3.19 checkglerr(where) /* check for GL or GLU error */
430     char *where;
431 gregl 3.1 {
432 gwlarson 3.19 register GLenum errcode;
433    
434     while ((errcode = glGetError()) != GL_NO_ERROR) {
435     sprintf(errmsg, "OpenGL error %s: %s",
436     where, gluErrorString(errcode));
437     error(WARNING, errmsg);
438 gregl 3.1 }
439     }
440    
441    
442 gwlarson 3.19 #ifdef STEREO
443     static
444     pushright() /* push on right view */
445     {
446     double d;
447    
448     setstereobuf(STEREO_BUFFER_RIGHT);
449     glMatrixMode(GL_MODELVIEW);
450     glPushMatrix();
451     d = -eyesepdist / sqrt(odev.v.hn2);
452     glTranslated(d*odev.v.hvec[0], d*odev.v.hvec[1], d*odev.v.hvec[2]);
453 gwlarson 3.23 checkglerr("setting right view");
454 gwlarson 3.19 }
455    
456    
457     static
458     popright() /* pop off right view */
459     {
460     glMatrixMode(GL_MODELVIEW);
461     glPopMatrix();
462     setstereobuf(STEREO_BUFFER_LEFT);
463     }
464     #endif
465    
466    
467 gregl 3.1 static int
468     mytmflags() /* figure out tone mapping flags */
469     {
470     extern char *progname;
471     register char *cp, *tail;
472     /* find basic name */
473     for (cp = tail = progname; *cp; cp++)
474     if (*cp == '/')
475     tail = cp+1;
476     for (cp = tail; *cp && *cp != '.'; cp++)
477     ;
478 gwlarson 3.19 if (cp > tail && cp[-1] == 'h')
479     return(TM_F_HUMAN|TM_F_NOSTDERR);
480     else
481 gregl 3.10 return(TM_F_CAMERA|TM_F_NOSTDERR);
482 gregl 3.1 }
483    
484    
485     static
486     getevent() /* get next event */
487     {
488     XNextEvent(ourdisplay, levptr(XEvent));
489     switch (levptr(XEvent)->type) {
490     case ConfigureNotify:
491     resizewindow(levptr(XConfigureEvent));
492     break;
493     case UnmapNotify:
494     mapped = 0;
495     break;
496     case MapNotify:
497     mapped = 1;
498     break;
499     case Expose:
500     fixwindow(levptr(XExposeEvent));
501     break;
502     case KeyPress:
503     getkey(levptr(XKeyPressedEvent));
504     break;
505     case ButtonPress:
506 gwlarson 3.24 if (FRAMESTATE(levptr(XButtonPressedEvent)->state))
507     getframe(levptr(XButtonPressedEvent));
508     else
509     getmove(levptr(XButtonPressedEvent));
510 gregl 3.1 break;
511     }
512     }
513    
514    
515     static
516     draw3dline(wp) /* draw 3d line in world coordinates */
517     register FVECT wp[2];
518     {
519     glVertex3d(wp[0][0], wp[0][1], wp[0][2]);
520     glVertex3d(wp[1][0], wp[1][1], wp[1][2]);
521     }
522    
523    
524     static
525 gwlarson 3.22 draw_grids(fore) /* draw holodeck section grids */
526     int fore;
527 gregl 3.1 {
528 gwlarson 3.22 if (fore)
529     glColor4ub(0, 255, 255, 0);
530     else
531     glColor4ub(0, 0, 0, 0);
532 gregl 3.4 glBegin(GL_LINES); /* draw each grid line */
533 gregl 3.1 gridlines(draw3dline);
534     glEnd();
535 gwlarson 3.23 checkglerr("drawing grid lines");
536 gregl 3.1 }
537    
538 gwlarson 3.28 static double
539     getdistance(dx, dy, direc) /* distance from fore plane along view ray */
540     int dx, dy;
541     FVECT direc;
542     {
543     GLfloat gldepth;
544     double dist;
545 gregl 3.1
546 gwlarson 3.28 if (dx<0 | dx>=odev.hres | dy<0 | dy>=odev.vres)
547     return(FHUGE);
548     glReadPixels(dx,dy, 1,1, GL_DEPTH_COMPONENT,GL_FLOAT, &gldepth);
549     dist = mapdepth(gldepth);
550     if (dist >= .99*FHUGE)
551     return(FHUGE);
552     return((dist-odev.v.vfore)/DOT(direc,odev.v.vdir));
553     }
554    
555    
556 gregl 3.1 static
557     moveview(dx, dy, mov, orb) /* move our view */
558     int dx, dy, mov, orb;
559     {
560     VIEW nv;
561 gwlarson 3.19 FVECT odir, v1, wip;
562 gwlarson 3.28 double d,d1;
563 gregl 3.1 register int li;
564     /* start with old view */
565     copystruct(&nv, &odev.v);
566 gwlarson 3.22 /* orient our motion */
567 gwlarson 3.19 if (viewray(v1, odir, &odev.v,
568     (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
569     return(0); /* outside view */
570 gwlarson 3.22 if (mov | orb) { /* moving relative to geometry */
571 gwlarson 3.28 d = getdistance(dx, dy, odir);/*distance from front plane */
572 gwlarson 3.19 #ifdef DOBJ
573 gwlarson 3.28 d1 = dobj_trace(NULL, v1, odir); /* check objects */
574 gwlarson 3.22 /* check holodeck */
575 gwlarson 3.28 if (d1 < d)
576     d = d1;
577 gwlarson 3.19 #endif
578 gwlarson 3.28 if (d >= .99*FHUGE)
579     d = 0.5*(dev_zmax+dev_zmin); /* just guess */
580     VSUM(wip, v1, odir, d);
581     VSUB(odir, wip, odev.v.vp);
582     #if 0
583 gwlarson 3.24 fprintf(stderr, "moveview: hit %s at (%f,%f,%f) (t=%f)\n",
584     li < 0 ? "object" : "mesh",
585     wip[0], wip[1], wip[2],
586     (wip[0]-odev.v.vp[0])*odir[0] +
587     (wip[1]-odev.v.vp[1])*odir[1] +
588     (wip[2]-odev.v.vp[2])*odir[2]);
589     #endif
590 gwlarson 3.22 } else /* panning with constant viewpoint */
591 gwlarson 3.19 VCOPY(nv.vdir, odir);
592 gregl 3.1 if (orb && mov) { /* orbit left/right */
593     spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
594 gwlarson 3.19 VSUM(nv.vp, wip, odir, -1.);
595 gregl 3.1 spinvector(nv.vdir, nv.vdir, nv.vup, d);
596     } else if (orb) { /* orbit up/down */
597     fcross(v1, odir, nv.vup);
598     if (normalize(v1) == 0.)
599     return(0);
600     spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
601 gwlarson 3.19 VSUM(nv.vp, wip, odir, -1.);
602 gregl 3.1 spinvector(nv.vdir, nv.vdir, v1, d);
603     } else if (mov) { /* move forward/backward */
604     d = MOVPCT/100. * mov;
605     VSUM(nv.vp, nv.vp, odir, d);
606     }
607     if (!mov ^ !orb && headlocked) { /* restore head height */
608     VSUM(v1, odev.v.vp, nv.vp, -1.);
609 gwlarson 3.22 d = DOT(v1, nv.vup);
610 gregl 3.1 VSUM(nv.vp, nv.vp, odev.v.vup, d);
611     }
612     if (setview(&nv) != NULL)
613     return(0); /* illegal view */
614     dev_view(&nv);
615     inpresflags |= DFL(DC_SETVIEW);
616     return(1);
617     }
618    
619    
620     static
621 gwlarson 3.24 getframe(ebut) /* get focus frame */
622     XButtonPressedEvent *ebut;
623     {
624     int startx = ebut->x, starty = ebut->y;
625     int endx, endy;
626    
627     XMaskEvent(ourdisplay, ButtonReleaseMask, levptr(XEvent));
628     endx = levptr(XButtonReleasedEvent)->x;
629     endy = levptr(XButtonReleasedEvent)->y;
630     if (endx == startx | endy == starty) {
631     XBell(ourdisplay, 0);
632     return;
633     }
634     if (endx < startx) {register int c = endx; endx = startx; startx = c;}
635     if (endy < starty) {register int c = endy; endy = starty; starty = c;}
636     sprintf(odev_args, "%.3f %.3f %.3f %.3f",
637     (startx+.5)/odev.hres, 1.-(endy+.5)/odev.vres,
638     (endx+.5)/odev.hres, 1.-(starty+.5)/odev.vres);
639     inpresflags |= DFL(DC_FOCUS);
640     }
641    
642    
643     static
644 gregl 3.1 getmove(ebut) /* get view change */
645     XButtonPressedEvent *ebut;
646     {
647     int movdir = MOVDIR(ebut->button);
648     int movorb = MOVORB(ebut->state);
649 gwlarson 3.28 int qlevel = MAXQUALITY-1;
650 gwlarson 3.19 time_t lasttime, thistime;
651     int nframes;
652 gregl 3.1 Window rootw, childw;
653     int rootx, rooty, wx, wy;
654     unsigned int statemask;
655    
656 gwlarson 3.23 XNoOp(ourdisplay); /* makes sure we're not idle */
657 gregl 3.1
658 gwlarson 3.28 nframes = 0;
659 gregl 3.1 while (!XCheckMaskEvent(ourdisplay,
660     ButtonReleaseMask, levptr(XEvent))) {
661 gwlarson 3.23 /* get cursor position */
662 gregl 3.1 if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
663     &rootx, &rooty, &wx, &wy, &statemask))
664     break; /* on another screen */
665    
666 gwlarson 3.22 draw_grids(0); /* clear old grid lines */
667 gwlarson 3.23 #ifdef STEREO
668     pushright(); draw_grids(0); popright();
669     #endif
670     /* compute view motion */
671 gregl 3.1 if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) {
672     sleep(1);
673 gwlarson 3.19 lasttime++;
674 gwlarson 3.23 continue; /* cursor in bad place */
675 gregl 3.1 }
676 gwlarson 3.23 draw_grids(1); /* redraw grid */
677 gwlarson 3.19 #ifdef STEREO
678     pushright();
679 gwlarson 3.22 draw_grids(1);
680 gwlarson 3.19 smUpdate(&vwright, qlevel);
681     #ifdef DOBJ
682     dobj_render();
683     #endif
684     popright();
685     #endif
686 gwlarson 3.23 /* redraw mesh */
687 gwlarson 3.19 smUpdate(&odev.v, qlevel);
688     #ifdef DOBJ
689 gwlarson 3.23 dobj_render(); /* redraw object */
690 gwlarson 3.19 #endif
691 gregl 3.4 glFlush();
692 gwlarson 3.28 /* figure out good quality level */
693     if (!nframes++) { /* ignore first frame */
694     lasttime = time(0);
695     continue;
696     }
697 gwlarson 3.19 thistime = time(0);
698 gwlarson 3.28 if (thistime - lasttime >= 6 ||
699 gwlarson 3.19 nframes > (int)(3*3*TARGETFPS)) {
700 gwlarson 3.28 qlevel = thistime<=lasttime ? 3*MAXQUALITY :
701 gwlarson 3.19 (int)((double)nframes/(thistime-lasttime)
702     / TARGETFPS * qlevel + 0.5);
703 gwlarson 3.28 nframes = 0;
704     if (qlevel >= MAXQUALITY) {
705     if (qlevel >= 3*MAXQUALITY) { /* brakes!! */
706 gwlarson 3.19 sleep(1);
707     lasttime++;
708     }
709 gwlarson 3.28 qlevel = MAXQUALITY-1;
710 gwlarson 3.19 } else if (qlevel < 1)
711     qlevel = 1;
712     }
713 gregl 3.1 }
714     if (!(inpresflags & DFL(DC_SETVIEW))) { /* do final motion */
715     movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
716     wx = levptr(XButtonReleasedEvent)->x;
717     wy = levptr(XButtonReleasedEvent)->y;
718     moveview(wx, odev.vres-1-wy, movdir, movorb);
719     }
720 gwlarson 3.19 }
721 gregl 3.4
722 gwlarson 3.19
723     static
724     setglpersp(vp) /* set perspective view in GL */
725     register VIEW *vp;
726     {
727     double d, xmin, xmax, ymin, ymax;
728    
729     if (mindpth >= maxdpth) {
730 gwlarson 3.25 dev_zmin = 1.;
731 gwlarson 3.19 dev_zmax = 100.;
732     } else {
733 gwlarson 3.28 dev_zmin = 0.1*mindpth;
734 gwlarson 3.26 dev_zmax = 5.0*maxdpth;
735 gwlarson 3.19 }
736     if (odev.v.vfore > FTINY)
737     dev_zmin = odev.v.vfore;
738     if (odev.v.vaft > FTINY)
739     dev_zmax = odev.v.vaft;
740 gwlarson 3.28 if (dev_zmin < dev_zmax/500.)
741     dev_zmin = dev_zmax/500.;
742 gwlarson 3.19 xmax = dev_zmin * tan(PI/180./2. * odev.v.horiz);
743     xmin = -xmax;
744     d = odev.v.hoff * (xmax - xmin);
745     xmin += d; xmax += d;
746     ymax = dev_zmin * tan(PI/180./2. * odev.v.vert);
747     ymin = -ymax;
748     d = odev.v.voff * (ymax - ymin);
749     ymin += d; ymax += d;
750     /* set view matrix */
751     glMatrixMode(GL_PROJECTION);
752     glLoadIdentity();
753     glFrustum(xmin, xmax, ymin, ymax, dev_zmin, dev_zmax);
754     gluLookAt(odev.v.vp[0], odev.v.vp[1], odev.v.vp[2],
755     odev.v.vp[0] + odev.v.vdir[0],
756     odev.v.vp[1] + odev.v.vdir[1],
757     odev.v.vp[2] + odev.v.vdir[2],
758     odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]);
759 gwlarson 3.23 checkglerr("setting perspective view");
760 gregl 3.1 }
761    
762    
763     static
764 gwlarson 3.28 wipeclean(tmflag) /* prepare for redraw */
765     int tmflag;
766 gwlarson 3.19 {
767 gwlarson 3.22 /* clear depth buffer */
768 gwlarson 3.19 #ifdef STEREO
769     setstereobuf(STEREO_BUFFER_RIGHT);
770     glClear(GL_DEPTH_BUFFER_BIT);
771     setstereobuf(STEREO_BUFFER_LEFT);
772     #endif
773     glClear(GL_DEPTH_BUFFER_BIT);
774 gwlarson 3.28 smClean(tmflag); /* reset drawing routines */
775 gwlarson 3.22 setglpersp(&odev.v); /* reset view & clipping planes */
776 gwlarson 3.19 }
777    
778    
779     static
780 gregl 3.1 getkey(ekey) /* get input key */
781     register XKeyPressedEvent *ekey;
782     {
783 gwlarson 3.24 Window rootw, childw;
784     int rootx, rooty, wx, wy;
785     unsigned int statemask;
786 gregl 3.1 int n;
787     char buf[8];
788    
789     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
790     if (n != 1)
791     return;
792     switch (buf[0]) {
793     case 'h': /* turn on height motion lock */
794     headlocked = 1;
795     return;
796     case 'H': /* turn off height motion lock */
797     headlocked = 0;
798     return;
799     case 'l': /* retrieve last view */
800     inpresflags |= DFL(DC_LASTVIEW);
801     return;
802     case 'p': /* pause computation */
803     inpresflags |= DFL(DC_PAUSE);
804     return;
805     case 'v': /* spit out view */
806     inpresflags |= DFL(DC_GETVIEW);
807 gwlarson 3.24 return;
808     case 'f': /* frame view position */
809     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
810     &rootx, &rooty, &wx, &wy, &statemask))
811     return; /* on another screen */
812     sprintf(odev_args, "%.4f %.4f", (wx+.5)/odev.hres,
813     1.-(wy+.5)/odev.vres);
814     inpresflags |= DFL(DC_FOCUS);
815     return;
816     case 'F': /* unfocus */
817     odev_args[0] = '\0';
818     inpresflags |= DFL(DC_FOCUS);
819 gregl 3.1 return;
820     case '\n':
821     case '\r': /* resume computation */
822     inpresflags |= DFL(DC_RESUME);
823     return;
824     case CTRL('R'): /* redraw screen */
825 gwlarson 3.28 wipeclean(1);
826 gregl 3.1 return;
827     case CTRL('L'): /* refresh from server */
828     if (inpresflags & DFL(DC_REDRAW))
829     return;
830 gwlarson 3.23 setglpersp(&odev.v); /* reset clipping planes */
831 gregl 3.1 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
832 gwlarson 3.23 glDisable(GL_DEPTH_TEST); /* so grids will clear */
833 gwlarson 3.22 draw_grids(1);
834 gwlarson 3.19 #ifdef STEREO
835     pushright();
836     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
837 gwlarson 3.22 draw_grids(1);
838 gwlarson 3.19 popright();
839     #endif
840     glEnable(GL_DEPTH_TEST);
841 gregl 3.1 glFlush();
842 gwlarson 3.19 smInit(rsL.max_samp); /* get rid of old values */
843 gregl 3.1 inpresflags |= DFL(DC_REDRAW); /* resend values from server */
844 gregl 3.13 rayqleft = 0; /* hold off update */
845 gregl 3.1 return;
846     case 'K': /* kill rtrace process(es) */
847     inpresflags |= DFL(DC_KILL);
848     break;
849     case 'R': /* restart rtrace */
850     inpresflags |= DFL(DC_RESTART);
851     break;
852     case 'C': /* clobber holodeck */
853     inpresflags |= DFL(DC_CLOBBER);
854     break;
855     case 'q': /* quit the program */
856     inpresflags |= DFL(DC_QUIT);
857     return;
858     default:
859     XBell(ourdisplay, 0);
860     return;
861     }
862     }
863    
864    
865     static
866     fixwindow(eexp) /* repair damage to window */
867     register XExposeEvent *eexp;
868     {
869 gwlarson 3.19 if (odev.hres == 0 | odev.vres == 0) { /* first exposure */
870 gregl 3.2 resizewindow((XConfigureEvent *)eexp);
871 gwlarson 3.19 return;
872     }
873     if (eexp->count) /* wait for final exposure */
874     return;
875 gwlarson 3.28 wipeclean(0); /* clear depth */
876 gregl 3.1 }
877    
878    
879     static
880     resizewindow(ersz) /* resize window */
881     register XConfigureEvent *ersz;
882     {
883 gregl 3.6 glViewport(0, 0, ersz->width, ersz->height);
884    
885 gregl 3.1 if (ersz->width == odev.hres && ersz->height == odev.vres)
886     return;
887    
888     odev.hres = ersz->width;
889     odev.vres = ersz->height;
890    
891     odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
892     odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
893    
894     inpresflags |= DFL(DC_SETVIEW);
895     }