ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_glx.c
Revision: 3.3
Committed: Wed Dec 24 15:55:43 1997 UTC (26 years, 4 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.2: +26 -3 lines
Log Message:
added fast redraw for mouse-controlled movement

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