ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_glx.c
Revision: 3.31
Committed: Fri Sep 19 18:33:04 2003 UTC (20 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6P1, rad3R6
Changes since 3.30: +3 -1 lines
Log Message:
Improved rholo -o ogl interaction under Mac OS X

File Contents

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