ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_glx.c
Revision: 3.1
Committed: Tue Dec 23 18:31:00 1997 UTC (26 years, 4 months ago) by gregl
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# User Rev Content
1 gregl 3.1 /* Copyright (c) 1997 Silicon Graphics, Inc. */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ SGI";
5     #endif
6    
7     /*
8     * OpenGL GLX driver for holodeck display.
9     * Based on rview driver.
10     */
11    
12     #include "standard.h"
13     #include "tonemap.h"
14     #include "rhdriver.h"
15    
16     #include <GL/glx.h>
17    
18     #include "x11icon.h"
19    
20     #ifndef FEQ
21     #define FEQ(a,b) ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
22     #endif
23    
24     #ifndef int4
25     #define int4 int
26     #endif
27    
28     #ifndef FREEPCT
29     #define FREEPCT 25 /* percentage of values to free */
30     #endif
31    
32     #ifndef NCONEV
33     #define NCONEV 7 /* number of cone base vertices */
34     #endif
35     #ifndef CONEH
36     #define CONEH 0.25 /* cone height (fraction of depth) */
37     #endif
38     #ifndef CONEW
39     #define CONEW 0.035 /* cone width (fraction of screen) */
40     #endif
41    
42     #define GAMMA 2.2 /* default gamma correction */
43    
44     #define MOVPCT 7 /* percent distance to move /frame */
45     #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
46     #define MOVDEG (-5) /* degrees to orbit CW/down /frame */
47     #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
48    
49     #define MINWIDTH 480 /* minimum graphics window width */
50     #define MINHEIGHT 400 /* minimum graphics window height */
51    
52     #define VIEWDIST 356 /* assumed viewing distance (mm) */
53    
54     #define BORWIDTH 5 /* border width */
55    
56     #define ourscreen DefaultScreen(ourdisplay)
57     #define ourroot RootWindow(ourdisplay,ourscreen)
58     #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
59     ButtonPressMask|ButtonReleaseMask)
60    
61     #define levptr(etype) ((etype *)&currentevent)
62    
63     struct driver odev; /* global device driver structure */
64    
65     static XEvent currentevent; /* current event */
66    
67     static int mapped = 0; /* window is mapped? */
68     static unsigned long *pixval = NULL; /* allocated pixels */
69     static unsigned long ourblack=0, ourwhite=~0;
70    
71     static Display *ourdisplay = NULL; /* our display */
72     static XVisualInfo *ourvinf; /* our visual information */
73     static Window gwind = 0; /* our graphics window */
74     static GLXContext gctx; /* our GLX context */
75    
76     static double mindepth = FHUGE; /* minimum depth value so far */
77     static double maxdepth = 0.; /* maximum depth value */
78    
79     static double pwidth, pheight; /* pixel dimensions (mm) */
80    
81     static FVECT conev[NCONEV]; /* drawing cone */
82     static double coneh; /* cone height */
83    
84     static int inpresflags; /* input result flags */
85    
86     static int headlocked = 0; /* lock vertical motion */
87    
88     static struct {
89     float (*wp)[3]; /* world intersection point array */
90     int4 *wd; /* world direction array */
91     TMbright *brt; /* encoded brightness array */
92     BYTE (*chr)[3]; /* encoded chrominance array */
93     BYTE (*rgb)[3]; /* tone-mapped color array */
94     BYTE *alpha; /* alpha values */
95     int nl; /* count of values */
96     int bl, tl; /* bottom and top (next) value index */
97     int tml; /* next value needing tone-mapping */
98     int drl; /* next value in need of drawing */
99     char *base; /* base of allocated memory */
100     } rV; /* our collection of values */
101    
102     #define redraw() (rV.drl = rV.bl)
103    
104     static int resizewindow(), getevent(), getkey(), moveview(),
105     setGLview(), getmove(), fixwindow(), mytmflags(),
106     newvalue(), drawvalue(), Compost(),
107     FindValue(), AllocValues(), TMapValues(), FreeValues();
108    
109    
110     dev_open(id) /* initialize X11 driver */
111     char *id;
112     {
113     extern char *getenv();
114     static int atlBest[] = {GLX_RGBA, GLX_RED_SIZE,8,
115     GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8,
116     GLX_ALPHA_SIZE,8, GLX_DEPTH_SIZE,23,
117     /*GLX_DOUBLEBUFFER,*/ None};
118     static int atlOK[] = {GLX_RGBA, GLX_RED_SIZE,4,
119     GLX_GREEN_SIZE,4, GLX_BLUE_SIZE,4,
120     GLX_ALPHA_SIZE,4, GLX_DEPTH_SIZE,15,
121     /*GLX_DOUBLEBUFFER,*/ None};
122     char *gv;
123     double gamval = GAMMA;
124     XSetWindowAttributes ourwinattr;
125     XWMHints ourxwmhints;
126     XSizeHints oursizhints;
127     /* open display server */
128     ourdisplay = XOpenDisplay(NULL);
129     if (ourdisplay == NULL)
130     error(USER, "cannot open X-windows; DISPLAY variable set?\n");
131     /* find a usable visual */
132     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest);
133     if (ourvinf == NULL)
134     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlOK);
135     if (ourvinf == NULL)
136     error(USER, "no suitable visuals available");
137     /* get a context */
138     gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE);
139     /* set gamma and tone mapping */
140     if ((gv = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
141     || (gv = getenv("DISPLAY_GAMMA")) != NULL)
142     gamval = atof(gv);
143     if (tmInit(mytmflags(), stdprims, gamval) == NULL)
144     error(SYSTEM, "not enough memory in dev_open");
145     /* open window */
146     ourwinattr.background_pixel = ourblack;
147     ourwinattr.border_pixel = ourblack;
148     ourwinattr.event_mask = ourmask;
149     /* this is stupid */
150     ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
151     ourvinf->visual, AllocNone);
152     gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
153     DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
154     DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
155     BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual,
156     CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
157     if (gwind == 0)
158     error(SYSTEM, "cannot create window\n");
159     XStoreName(ourdisplay, gwind, id);
160     /* set window manager hints */
161     ourxwmhints.flags = InputHint|IconPixmapHint;
162     ourxwmhints.input = True;
163     ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
164     gwind, x11icon_bits, x11icon_width, x11icon_height);
165     XSetWMHints(ourdisplay, gwind, &ourxwmhints);
166     oursizhints.min_width = MINWIDTH;
167     oursizhints.min_height = MINHEIGHT;
168     oursizhints.flags = PMinSize;
169     XSetNormalHints(ourdisplay, gwind, &oursizhints);
170     /* map the window and get its size */
171     XMapWindow(ourdisplay, gwind);
172     dev_input();
173     /* allocate our value list */
174     if (!AllocValues(DisplayWidth(ourdisplay,ourscreen) *
175     DisplayHeight(ourdisplay,ourscreen) / 4))
176     error(SYSTEM, "insufficient memory for value storage");
177     /* figure out sensible view */
178     pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
179     DisplayWidth(ourdisplay, ourscreen);
180     pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
181     DisplayHeight(ourdisplay, ourscreen);
182     copystruct(&odev.v, &stdview);
183     odev.v.type = VT_PER;
184     odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
185     odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
186     odev.name = id;
187     odev.ifd = ConnectionNumber(ourdisplay);
188     /* set GLX context and clear buffers */
189     glXMakeCurrent(ourdisplay, gwind, gctx);
190     glEnable(GL_DEPTH_TEST);
191     glDepthFunc(GL_LEQUAL);
192     glShadeModel(GL_FLAT);
193     glDisable(GL_DITHER);
194     glDrawBuffer(GL_FRONT_AND_BACK);
195     glReadBuffer(GL_BACK);
196     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
197     setGLview(); /* initialize view */
198     }
199    
200    
201     dev_close() /* close our display and free resources */
202     {
203     glXMakeCurrent(ourdisplay, None, NULL);
204     glXDestroyContext(ourdisplay, gctx);
205     XDestroyWindow(ourdisplay, gwind);
206     gwind = 0;
207     XCloseDisplay(ourdisplay);
208     ourdisplay = NULL;
209     tmDone(NULL);
210     FreeValues();
211     odev.v.type = 0;
212     odev.hres = odev.vres = 0;
213     odev.ifd = -1;
214     }
215    
216    
217     int
218     dev_view(nv) /* assign new driver view */
219     register VIEW *nv;
220     {
221     if (nv->type != VT_PER || /* check view legality */
222     nv->horiz > 120. || nv->vert > 120.) {
223     error(COMMAND, "illegal view type/angle");
224     nv->type = VT_PER;
225     nv->horiz = odev.v.horiz;
226     nv->vert = odev.v.vert;
227     return(0);
228     }
229     if (nv != &odev.v) {
230     if (!FEQ(nv->horiz,odev.v.horiz) || /* resize window? */
231     !FEQ(nv->vert,odev.v.vert)) {
232     int dw = DisplayWidth(ourdisplay,ourscreen);
233     int dh = DisplayHeight(ourdisplay,ourscreen);
234    
235     dw -= 25; /* for window frame */
236     dh -= 50;
237     odev.hres = 2.*VIEWDIST/pwidth *
238     tan(PI/180./2.*nv->horiz);
239     odev.vres = 2.*VIEWDIST/pheight *
240     tan(PI/180./2.*nv->vert);
241     if (odev.hres > dw) {
242     odev.vres = dw * odev.vres / odev.hres;
243     odev.hres = dw;
244     }
245     if (odev.vres > dh) {
246     odev.hres = dh * odev.hres / odev.vres;
247     odev.vres = dh;
248     }
249     XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
250     }
251     copystruct(&odev.v, nv);
252     setGLview();
253     }
254     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
255     redraw();
256     return(1);
257     }
258    
259    
260     int
261     dev_input() /* get X11 input */
262     {
263     inpresflags = 0;
264    
265     do
266     getevent();
267    
268     while (XQLength(ourdisplay) > 0);
269    
270     return(inpresflags);
271     }
272    
273    
274     dev_value(c, p, v) /* add a pixel value to our list */
275     COLR c;
276     FVECT p, v;
277     {
278     register int li;
279    
280     li = newvalue();
281     VCOPY(rV.wp[li], p);
282     rV.wd[li] = encodedir(v);
283     tmCvColrs(&rV.brt[li], rV.chr[li], c, 1);
284     }
285    
286    
287     int
288     dev_flush() /* flush output */
289     {
290     if (mapped) {
291     TMapValues(0);
292     while (rV.drl != rV.tl) {
293     drawvalue(rV.drl);
294     if (++rV.drl >= rV.nl)
295     rV.drl = 0;
296     }
297     glFlush();
298     }
299     return(XPending(ourdisplay));
300     }
301    
302    
303     static int
304     mytmflags() /* figure out tone mapping flags */
305     {
306     extern char *progname;
307     register char *cp, *tail;
308     /* find basic name */
309     for (cp = tail = progname; *cp; cp++)
310     if (*cp == '/')
311     tail = cp+1;
312     for (cp = tail; *cp && *cp != '.'; cp++)
313     ;
314     if (cp-tail == 3 && !strncmp(tail, "glx", 3))
315     return(TM_F_CAMERA);
316     if (cp-tail == 4 && !strncmp(tail, "glxh", 4))
317     return(TM_F_HUMAN);
318     error(USER, "illegal driver name");
319     }
320    
321    
322     static
323     setGLview() /* set our GL view */
324     {
325     double xmin, xmax, ymin, ymax, zmin, zmax;
326     double d, cx, sx, crad;
327     FVECT vx, vy;
328     register int i, j;
329     /* compute view frustum */
330     if (normalize(odev.v.vdir) == 0.0)
331     return;
332     if (mindepth < maxdepth) {
333     zmin = 0.25*mindepth;
334     zmax = 8.0*maxdepth;
335     } else {
336     zmin = 0.01;
337     zmax = 1000.;
338     }
339     if (odev.v.vfore > FTINY)
340     zmin = odev.v.vfore;
341     if (odev.v.vaft > FTINY)
342     zmax = odev.v.vaft;
343     xmax = zmin * tan(PI/180./2. * odev.v.horiz);
344     xmin = -xmax;
345     d = odev.v.hoff * (xmax - xmin);
346     xmin += d; xmax += d;
347     ymax = zmin * tan(PI/180./2. * odev.v.vert);
348     ymin = -ymax;
349     d = odev.v.voff * (ymax - ymin);
350     ymin += d; ymax += d;
351     /* set view matrix */
352     glMatrixMode(GL_PROJECTION);
353     glLoadIdentity();
354     glFrustum(xmin, xmax, ymin, ymax, zmin, zmax);
355     gluLookAt(odev.v.vp[0], odev.v.vp[1], odev.v.vp[2],
356     odev.v.vp[0] + odev.v.vdir[0],
357     odev.v.vp[1] + odev.v.vdir[1],
358     odev.v.vp[2] + odev.v.vdir[2],
359     odev.v.vup[0], odev.v.vup[1], odev.v.vup[2]);
360     /* set viewport */
361     glViewport(0, 0, odev.hres, odev.vres);
362     /* initialize cone for Vornoi polys */
363     coneh = CONEH*(zmax - zmin);
364     crad = 0.5 * CONEW * 0.5*(xmax-xmin + ymax-ymin) * (zmin+coneh)/zmin;
365     vy[0] = vy[1] = vy[2] = 0.;
366     for (i = 0; i < 3; i++)
367     if (odev.v.vdir[i] < 0.6 && odev.v.vdir[i] > -0.6)
368     break;
369     vy[i] = 1.;
370     fcross(vx, vy, odev.v.vdir);
371     normalize(vx);
372     fcross(vy, odev.v.vdir, vx);
373     for (j = 0, d = 0.; j < NCONEV; j++, d += 2.*PI/NCONEV) {
374     cx = crad*cos(d); sx = crad*sin(d);
375     for (i = 0; i < 3; i++)
376     conev[j][i] = coneh*odev.v.vdir[i] +
377     cx*vx[i] + sx*vy[i];
378     }
379     }
380    
381    
382     static int
383     newvalue() /* allocate a leaf from our pile */
384     {
385     int li;
386    
387     li = rV.tl++;
388     if (rV.tl >= rV.nl) /* get next leaf in ring */
389     rV.tl = 0;
390     if (rV.tl == rV.bl) /* need to shake some free */
391     Compost(FREEPCT);
392     return(li);
393     }
394    
395    
396     static
397     drawvalue(li) /* draw a pixel value as a cone */
398     register int li;
399     {
400     static FVECT apex, disp;
401     double d, h, v;
402     register int i;
403     /* compute cone's base displacement */
404     VCOPY(apex, rV.wp[li]);
405     disp[0] = apex[0] - odev.v.vp[0];
406     disp[1] = apex[1] - odev.v.vp[1];
407     disp[2] = apex[2] - odev.v.vp[2];
408     if ((d = DOT(disp,odev.v.vdir)) <= odev.v.vfore || d <= FTINY)
409     return;
410     if (d > 1e5) { /* background region */
411     if (odev.v.vaft > FTINY)
412     return;
413     h = maxdepth/d;
414     disp[0] *= h; disp[1] *= h; disp[2] *= h;
415     apex[0] = odev.v.vp[0] + disp[0];
416     apex[1] = odev.v.vp[1] + disp[1];
417     apex[2] = odev.v.vp[2] + disp[2];
418     d = maxdepth;
419     } else if (d > maxdepth)
420     maxdepth = d;
421     h = DOT(disp,odev.v.hvec)/(d*odev.v.hn2);
422     v = DOT(disp,odev.v.vvec)/(d*odev.v.vn2);
423     if (fabs(h - odev.v.hoff) < 0.5 && fabs(v - odev.v.voff) < 0.5 &&
424     d < mindepth)
425     {
426     fprintf(stderr, "min depth now %lf (%lf,%lf,%lf)\n", d, apex[0], apex[1], apex[2]);
427     mindepth = d;
428     }
429     for (i = 0; i < 3; i++)
430     disp[i] = apex[i] + coneh*(h*odev.v.hvec[i] + v*odev.v.vvec[i]);
431     /* draw pyramid (cone approx.) */
432     glColor4ub(rV.rgb[li][0], rV.rgb[li][1], rV.rgb[li][2], rV.alpha[li]);
433     glBegin(GL_TRIANGLE_FAN);
434     glVertex3f(apex[0], apex[1], apex[2]);
435     for (i = 0; i < NCONEV; i++)
436     glVertex3d(conev[i][0] + disp[0], conev[i][1] + disp[1],
437     conev[i][2] + disp[2]);
438     /* connect last side to first */
439     glVertex3d(conev[0][0] + disp[0], conev[0][1] + disp[1],
440     conev[0][2] + disp[2]);
441     glEnd(); /* done */
442     }
443    
444    
445     #define LEAFSIZ (3*sizeof(float)+sizeof(int4)+\
446     sizeof(TMbright)+7*sizeof(BYTE))
447    
448     static
449     AllocValues(n) /* allocate space for n values */
450     register int n;
451     {
452     unsigned nbytes;
453     register unsigned i;
454    
455     if (n <= 0)
456     return(0);
457     if (rV.nl >= n)
458     return(rV.nl);
459     else if (rV.nl > 0)
460     free(rV.base);
461     /* round space up to nearest power of 2 */
462     nbytes = n*LEAFSIZ + 8;
463     for (i = 1024; nbytes > i; i <<= 1)
464     ;
465     n = (i - 8) / LEAFSIZ; /* should we make sure n is even? */
466     rV.base = (char *)malloc(n*LEAFSIZ);
467     if (rV.base == NULL)
468     return(0);
469     /* assign larger alignment types earlier */
470     rV.wp = (float (*)[3])rV.base;
471     rV.wd = (int4 *)(rV.wp + n);
472     rV.brt = (TMbright *)(rV.wd + n);
473     rV.chr = (BYTE (*)[3])(rV.brt + n);
474     rV.rgb = (BYTE (*)[3])(rV.chr + n);
475     rV.alpha = (BYTE *)(rV.rgb + n);
476     rV.nl = n;
477     rV.drl = rV.tml = rV.bl = rV.tl = 0;
478     return(n);
479     }
480    
481     #undef LEAFSIZ
482    
483    
484     static
485     FreeValues() /* free our allocated values */
486     {
487     if (rV.nl <= 0)
488     return;
489     free(rV.base);
490     rV.base = NULL;
491     rV.nl = 0;
492     }
493    
494    
495     static
496     TMapValues(redo) /* map our values to RGB */
497     int redo;
498     {
499     int aorg, alen, borg, blen;
500     /* recompute mapping? */
501     if (redo)
502     rV.tml = rV.bl;
503     /* already done? */
504     if (rV.tml == rV.tl)
505     return(1);
506     /* compute segments */
507     aorg = rV.tml;
508     if (rV.tl >= aorg) {
509     alen = rV.tl - aorg;
510     blen = 0;
511     } else {
512     alen = rV.nl - aorg;
513     borg = 0;
514     blen = rV.tl;
515     }
516     /* (re)compute tone mapping? */
517     if (rV.tml == rV.bl) {
518     tmClearHisto();
519     tmAddHisto(rV.brt+aorg, alen, 1);
520     if (blen > 0)
521     tmAddHisto(rV.brt+borg, blen, 1);
522     if (tmComputeMapping(0., 0., 0.) != TM_E_OK)
523     return(0);
524     rV.drl = rV.bl;
525     }
526     if (tmMapPixels(rV.rgb+aorg, rV.brt+aorg,
527     rV.chr+aorg, alen) != TM_E_OK)
528     return(0);
529     if (blen > 0)
530     tmMapPixels(rV.rgb+borg, rV.brt+borg,
531     rV.chr+borg, blen);
532     /* compute unique alpha values */
533     rV.tml = rV.tl;
534     return(1);
535     }
536    
537    
538     static int
539     Compost(pct) /* free up some values */
540     int pct;
541     {
542     int nused, nclear, nmapped, ndrawn;
543     /* figure out how many values to clear */
544     nclear = rV.nl * pct / 100;
545     nused = rV.tl - rV.bl;
546     if (nused <= 0) nused += rV.nl;
547     nclear -= rV.nl - nused;
548     if (nclear <= 0)
549     return(0);
550     if (nclear >= nused) { /* clear them all */
551     rV.drl = rV.tml = rV.bl = rV.tl = 0;
552     return(nused);
553     }
554     /* else clear values from bottom */
555     ndrawn = rV.drl - rV.bl;
556     if (ndrawn < 0) ndrawn += rV.nl;
557     nmapped = rV.tml - rV.bl;
558     if (nmapped < 0) nmapped += rV.nl;
559     rV.bl += nclear;
560     if (rV.bl >= rV.nl) rV.bl -= rV.nl;
561     if (ndrawn < nclear) rV.drl = rV.bl;
562     if (nmapped < nclear) rV.tml = rV.bl;
563     return(nclear);
564     }
565    
566    
567     static
568     getevent() /* get next event */
569     {
570     XNextEvent(ourdisplay, levptr(XEvent));
571     switch (levptr(XEvent)->type) {
572     case ConfigureNotify:
573     resizewindow(levptr(XConfigureEvent));
574     break;
575     case UnmapNotify:
576     mapped = 0;
577     break;
578     case MapNotify:
579     mapped = 1;
580     break;
581     case Expose:
582     fixwindow(levptr(XExposeEvent));
583     break;
584     case KeyPress:
585     getkey(levptr(XKeyPressedEvent));
586     break;
587     case ButtonPress:
588     getmove(levptr(XButtonPressedEvent));
589     break;
590     }
591     }
592    
593    
594     static
595     draw3dline(wp) /* draw 3d line in world coordinates */
596     register FVECT wp[2];
597     {
598     glVertex3d(wp[0][0], wp[0][1], wp[0][2]);
599     glVertex3d(wp[1][0], wp[1][1], wp[1][2]);
600     }
601    
602    
603     static
604     draw_grids() /* draw holodeck section grids */
605     {
606     static GLubyte gridrgba[4] = {0x0, 0xff, 0xff, 0x00};
607    
608     if (!mapped)
609     return;
610     glColor4ub(gridrgba[0], gridrgba[1], gridrgba[2], gridrgba[3]);
611     /* draw each grid line */
612     glBegin(GL_LINES);
613     gridlines(draw3dline);
614     glEnd();
615     }
616    
617    
618     static int
619     FindValue(dx, dy) /* find a value on the display */
620     int dx, dy;
621     {
622     return(-1); /* not found */
623     }
624    
625    
626     static
627     moveview(dx, dy, mov, orb) /* move our view */
628     int dx, dy, mov, orb;
629     {
630     VIEW nv;
631     FVECT odir, v1;
632     double d;
633     register int li;
634     /* start with old view */
635     copystruct(&nv, &odev.v);
636     /* change view direction */
637     if (mov | orb) {
638     if ((li = FindValue(dx, dy)) < 0)
639     return(0); /* not on window */
640     VSUM(odir, rV.wp[li], nv.vp, -1.);
641     } else {
642     if (viewray(nv.vp, nv.vdir, &odev.v,
643     (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
644     return(0); /* outside view */
645     }
646     if (orb && mov) { /* orbit left/right */
647     spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
648     VSUM(nv.vp, rV.wp[li], odir, -1.);
649     spinvector(nv.vdir, nv.vdir, nv.vup, d);
650     } else if (orb) { /* orbit up/down */
651     fcross(v1, odir, nv.vup);
652     if (normalize(v1) == 0.)
653     return(0);
654     spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
655     VSUM(nv.vp, rV.wp[li], odir, -1.);
656     spinvector(nv.vdir, nv.vdir, v1, d);
657     } else if (mov) { /* move forward/backward */
658     d = MOVPCT/100. * mov;
659     VSUM(nv.vp, nv.vp, odir, d);
660     }
661     if (!mov ^ !orb && headlocked) { /* restore head height */
662     VSUM(v1, odev.v.vp, nv.vp, -1.);
663     d = DOT(v1, odev.v.vup);
664     VSUM(nv.vp, nv.vp, odev.v.vup, d);
665     }
666     if (setview(&nv) != NULL)
667     return(0); /* illegal view */
668     dev_view(&nv);
669     inpresflags |= DFL(DC_SETVIEW);
670     return(1);
671     }
672    
673    
674     static
675     getmove(ebut) /* get view change */
676     XButtonPressedEvent *ebut;
677     {
678     int movdir = MOVDIR(ebut->button);
679     int movorb = MOVORB(ebut->state);
680     Window rootw, childw;
681     int rootx, rooty, wx, wy;
682     unsigned int statemask;
683    
684     XNoOp(ourdisplay);
685    
686     while (!XCheckMaskEvent(ourdisplay,
687     ButtonReleaseMask, levptr(XEvent))) {
688    
689     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
690     &rootx, &rooty, &wx, &wy, &statemask))
691     break; /* on another screen */
692    
693     if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) {
694     sleep(1);
695     continue;
696     }
697     draw_grids();
698     dev_flush();
699     }
700     if (!(inpresflags & DFL(DC_SETVIEW))) { /* do final motion */
701     movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
702     wx = levptr(XButtonReleasedEvent)->x;
703     wy = levptr(XButtonReleasedEvent)->y;
704     moveview(wx, odev.vres-1-wy, movdir, movorb);
705     }
706     dev_flush();
707     }
708    
709    
710     static
711     getkey(ekey) /* get input key */
712     register XKeyPressedEvent *ekey;
713     {
714     int n;
715     char buf[8];
716    
717     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
718     if (n != 1)
719     return;
720     switch (buf[0]) {
721     case 'h': /* turn on height motion lock */
722     headlocked = 1;
723     return;
724     case 'H': /* turn off height motion lock */
725     headlocked = 0;
726     return;
727     case 'l': /* retrieve last view */
728     inpresflags |= DFL(DC_LASTVIEW);
729     return;
730     case 'p': /* pause computation */
731     inpresflags |= DFL(DC_PAUSE);
732     return;
733     case 'v': /* spit out view */
734     inpresflags |= DFL(DC_GETVIEW);
735     return;
736     case '\n':
737     case '\r': /* resume computation */
738     inpresflags |= DFL(DC_RESUME);
739     return;
740     case CTRL('R'): /* redraw screen */
741     TMapValues(1);
742     redraw();
743     return;
744     case CTRL('L'): /* refresh from server */
745     if (inpresflags & DFL(DC_REDRAW))
746     return;
747     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
748     glDrawBuffer(GL_FRONT);
749     glDisable(GL_DEPTH_TEST);
750     draw_grids();
751     glEnable(GL_DEPTH_TEST);
752     glDrawBuffer(GL_FRONT_AND_BACK);
753     glFlush();
754     Compost(100); /* get rid of old values */
755     inpresflags |= DFL(DC_REDRAW); /* resend values from server */
756     return;
757     case 'K': /* kill rtrace process(es) */
758     inpresflags |= DFL(DC_KILL);
759     break;
760     case 'R': /* restart rtrace */
761     inpresflags |= DFL(DC_RESTART);
762     break;
763     case 'C': /* clobber holodeck */
764     inpresflags |= DFL(DC_CLOBBER);
765     break;
766     case 'q': /* quit the program */
767     inpresflags |= DFL(DC_QUIT);
768     return;
769     default:
770     XBell(ourdisplay, 0);
771     return;
772     }
773     }
774    
775    
776     static
777     fixwindow(eexp) /* repair damage to window */
778     register XExposeEvent *eexp;
779     {
780     if (odev.hres == 0 || odev.vres == 0) { /* first exposure */
781     odev.hres = eexp->width;
782     odev.vres = eexp->height;
783     }
784     if (eexp->width == odev.hres && eexp->height == odev.vres)
785     TMapValues(1);
786     if (!eexp->count)
787     redraw();
788     }
789    
790    
791     static
792     resizewindow(ersz) /* resize window */
793     register XConfigureEvent *ersz;
794     {
795     if (ersz->width == odev.hres && ersz->height == odev.vres)
796     return;
797    
798     odev.hres = ersz->width;
799     odev.vres = ersz->height;
800    
801     odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
802     odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
803    
804     setGLview();
805    
806     inpresflags |= DFL(DC_SETVIEW);
807     }