ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_glx.c
Revision: 3.2
Committed: Wed Dec 24 14:06:40 1997 UTC (26 years, 4 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.1: +227 -98 lines
Log Message:
first fully working version

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