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

# Content
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 x11 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 10 /* 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 3. /* cone height (fraction of depth) */
37 #endif
38 #ifndef CONEW
39 #define CONEW 0.05 /* cone width (fraction of screen) */
40 #endif
41 #ifndef DIRPEN
42 #define DIRPEN 0.001 /* direction penalty factor */
43 #endif
44 #ifndef VALUA
45 #define VALUA 16 /* target value area (pixels) */
46 #endif
47
48 #define GAMMA 1.4 /* default gamma correction */
49
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 static double maxdepth = 0.; /* maximum depth value so far */
83
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 static int quicken = 0; /* quicker, sloppier update rate? */
94
95 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 static int *valmap = NULL; /* sorted map of screen values */
110 static int vmaplen = 0; /* value map length */
111
112 #define redraw() (rV.drl = rV.bl)
113
114 static int resizewindow(), getevent(), getkey(), moveview(),
115 setGLview(), getmove(), fixwindow(), mytmflags(),
116 drawvalue(), valcmp(), clralphas(), setalphas(), mergalphas(),
117 IndexValue(), Compost(), FindValue(), TMapValues(),
118 AllocValues(), FreeValues();
119
120 extern int4 encodedir();
121 extern double fdir2diff(), dir2diff();
122
123
124 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 GLX_ALPHA_SIZE,8, GLX_DEPTH_SIZE,15,
131 None};
132 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 /* 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 /* 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 /* 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 DisplayHeight(ourdisplay,ourscreen) / VALUA))
198 error(SYSTEM, "insufficient memory for value storage");
199 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 dev_input(); /* get resize event */
254 }
255 copystruct(&odev.v, nv);
256 setGLview();
257 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
258 redraw();
259 }
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 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 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 zmax = 4.0*(1.+CONEH)*maxdepth;
343 } 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 #define SUCCSTEP 8 /* skip step when successful */
391 #define MAXSTEP 64
392
393 static
394 drawvalue(li) /* draw a pixel value as a cone */
395 register int li;
396 {
397 static int skipstep = 1;
398 static FVECT disp;
399 FVECT apex;
400 double d, dorg, dnew, h, v;
401 register int i;
402 /* check for quicker update */
403 if (quicken) {
404 if (li % skipstep)
405 return;
406 if (skipstep < MAXSTEP)
407 skipstep++;
408 }
409 /* 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 dorg = maxdepth;
422 } 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 for (i = 0; i < 3; i++)
441 disp[i] = apex[i] + coneh*(h*odev.v.hvec[i] + v*odev.v.vvec[i]);
442 /* draw cone (pyramid approx.) */
443 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 /* connect last face to first */
450 glVertex3d(conev[0][0] + disp[0], conev[0][1] + disp[1],
451 conev[0][2] + disp[2]);
452 glEnd(); /* done */
453 skipstep = SUCCSTEP;
454 }
455
456 #undef SUCCSTEP
457 #undef MAXSTEP
458
459
460 #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 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 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 clralphas(); /* restart value list */
643 rV.drl = rV.bl; /* need to redraw */
644 }
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 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 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 if (nclear >= nused) { /* clear them all? */
672 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 static BYTE gridrgba[4] = {0x0, 0xff, 0xff, 0x00};
728
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 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 FindValue(dx, dy) /* find a value on the display */
763 int dx, dy;
764 {
765 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 }
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 quicken = 1; /* accelerate update rate */
833 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 } else {
855 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
856 redraw();
857 }
858 quicken = 0;
859 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 glClear(GL_DEPTH_BUFFER_BIT);
896 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 if (odev.hres == 0 || odev.vres == 0) /* first exposure */
933 resizewindow((XConfigureEvent *)eexp);
934 if (eexp->width == odev.hres && eexp->height == odev.vres)
935 TMapValues(1);
936 if (!eexp->count) {
937 glClear(GL_DEPTH_BUFFER_BIT);
938 redraw();
939 }
940 }
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 }