ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_x11.c
Revision: 3.11
Committed: Mon Dec 8 19:03:18 1997 UTC (26 years, 3 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.10: +17 -8 lines
Log Message:
added ability to adjust window size on view change

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 * X11 driver for holodeck display.
9 * Based on rview driver.
10 */
11
12 #include "standard.h"
13 #include "rhd_qtree.h"
14
15 #include <X11/Xlib.h>
16 #include <X11/cursorfont.h>
17 #include <X11/Xutil.h>
18
19 #include "x11icon.h"
20
21 #ifndef FEQ
22 #define FEQ(a,b) ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
23 #endif
24
25 #define CTRL(c) ((c)-'@')
26
27 #define GAMMA 2.2 /* default gamma correction */
28
29 #define MOVPCT 10 /* percent distance to move */
30 #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
31
32 #define MINWIDTH 480 /* minimum graphics window width */
33 #define MINHEIGHT 400 /* minimum graphics window height */
34
35 #define VIEWDIST 356 /* assumed viewing distance (mm) */
36
37 #define BORWIDTH 5 /* border width */
38
39 #define ourscreen DefaultScreen(ourdisplay)
40 #define ourroot RootWindow(ourdisplay,ourscreen)
41 #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
42 ButtonPressMask|ButtonReleaseMask)
43
44 #define levptr(etype) ((etype *)&currentevent)
45
46 struct driver odev; /* global device driver structure */
47
48 static XEvent currentevent; /* current event */
49
50 static int ncolors = 0; /* color table size */
51 static int mapped = 0; /* window is mapped? */
52 static unsigned long *pixval = NULL; /* allocated pixels */
53 static unsigned long ourblack=0, ourwhite=1;
54
55 static Display *ourdisplay = NULL; /* our display */
56 static XVisualInfo ourvinfo; /* our visual information */
57 static Window gwind = 0; /* our graphics window */
58 static GC ourgc = 0; /* our graphics context for drawing */
59 static Colormap ourmap = 0; /* our color map */
60
61 static double pwidth, pheight; /* pixel dimensions (mm) */
62
63 static int inpresflags; /* input result flags */
64
65 static int headlocked = 0; /* lock vertical motion */
66
67 static int getpixels(), xnewcolr(), freepixels(), resizewindow(),
68 getevent(), getkey(), moveview(), getmove(), fixwindow();
69 static unsigned long true_pixel();
70
71
72 static int
73 mytmflags() /* figure out tone mapping flags */
74 {
75 extern char *progname;
76 register char *cp, *tail;
77 /* find basic name */
78 for (cp = tail = progname; *cp; cp++)
79 if (*cp == '/')
80 tail = cp+1;
81 for (cp = tail; *cp && *cp != '.'; cp++)
82 ;
83 if (cp-tail == 3 && !strncmp(tail, "x11", 3))
84 return(TM_F_CAMERA);
85 if (cp-tail == 4 && !strncmp(tail, "x11h", 4))
86 return(TM_F_HUMAN);
87 error(USER, "illegal driver name");
88 }
89
90
91 dev_open(id) /* initialize X11 driver */
92 char *id;
93 {
94 extern char *getenv();
95 char *gv;
96 double gamval = GAMMA;
97 int nplanes;
98 XSetWindowAttributes ourwinattr;
99 XWMHints ourxwmhints;
100 XSizeHints oursizhints;
101 /* set quadtree globals */
102 qtMinNodesiz = 2;
103 /* open display server */
104 ourdisplay = XOpenDisplay(NULL);
105 if (ourdisplay == NULL)
106 error(USER, "cannot open X-windows; DISPLAY variable set?\n");
107 /* find a usable visual */
108 nplanes = DisplayPlanes(ourdisplay, ourscreen);
109 if (XMatchVisualInfo(ourdisplay,ourscreen,
110 nplanes>12?nplanes:24,TrueColor,&ourvinfo) ||
111 XMatchVisualInfo(ourdisplay,ourscreen,
112 nplanes>12?nplanes:24,DirectColor,&ourvinfo)) {
113 ourblack = 0;
114 ourwhite = ourvinfo.red_mask |
115 ourvinfo.green_mask |
116 ourvinfo.blue_mask ;
117 } else {
118 if (nplanes < 4)
119 error(INTERNAL, "not enough colors\n");
120 if (!XMatchVisualInfo(ourdisplay,ourscreen,
121 nplanes,PseudoColor,&ourvinfo) &&
122 !XMatchVisualInfo(ourdisplay,ourscreen,
123 nplanes,GrayScale,&ourvinfo))
124 error(INTERNAL, "unsupported visual type\n");
125 ourblack = BlackPixel(ourdisplay,ourscreen);
126 ourwhite = WhitePixel(ourdisplay,ourscreen);
127 }
128 /* set gamma and tone mapping */
129 if ((gv = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
130 || (gv = getenv("DISPLAY_GAMMA")) != NULL)
131 gamval = atof(gv);
132 if (tmInit(mytmflags(), stdprims, gamval) == NULL)
133 error(SYSTEM, "not enough memory in dev_open");
134 /* open window */
135 ourwinattr.background_pixel = ourblack;
136 ourwinattr.border_pixel = ourblack;
137 ourwinattr.event_mask = ourmask;
138 /* this is stupid */
139 ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
140 ourvinfo.visual, AllocNone);
141 gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
142 DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
143 DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
144 BORWIDTH, ourvinfo.depth, InputOutput, ourvinfo.visual,
145 CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
146 if (gwind == 0)
147 error(SYSTEM, "cannot create window\n");
148 XStoreName(ourdisplay, gwind, id);
149 /* get graphics context */
150 ourgc = XCreateGC(ourdisplay, gwind, 0, NULL);
151 /* set window manager hints */
152 ourxwmhints.flags = InputHint|IconPixmapHint;
153 ourxwmhints.input = True;
154 ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
155 gwind, x11icon_bits, x11icon_width, x11icon_height);
156 XSetWMHints(ourdisplay, gwind, &ourxwmhints);
157 oursizhints.min_width = MINWIDTH;
158 oursizhints.min_height = MINHEIGHT;
159 oursizhints.flags = PMinSize;
160 XSetNormalHints(ourdisplay, gwind, &oursizhints);
161 /* map the window and get its size */
162 XMapWindow(ourdisplay, gwind);
163 dev_input();
164 /* allocate our leaf pile */
165 if (!qtAllocLeaves(DisplayWidth(ourdisplay,ourscreen) *
166 DisplayHeight(ourdisplay,ourscreen) /
167 (qtMinNodesiz*qtMinNodesiz)))
168 error(SYSTEM, "insufficient memory for leaf storage");
169
170 /* figure out sensible view */
171 pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
172 DisplayWidth(ourdisplay, ourscreen);
173 pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
174 DisplayHeight(ourdisplay, ourscreen);
175 copystruct(&odev.v, &stdview);
176 odev.name = id;
177 odev.v.type = VT_PER;
178 odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
179 odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
180 odev.ifd = ConnectionNumber(ourdisplay);
181 }
182
183
184 dev_close() /* close our display */
185 {
186 freepixels();
187 XFreeGC(ourdisplay, ourgc);
188 XDestroyWindow(ourdisplay, gwind);
189 gwind = 0;
190 ourgc = 0;
191 XCloseDisplay(ourdisplay);
192 ourdisplay = NULL;
193 qtFreeLeaves();
194 tmDone(NULL);
195 odev.v.type = 0;
196 odev.hres = odev.vres = 0;
197 odev.ifd = -1;
198 }
199
200
201 dev_view(nv) /* assign new driver view */
202 VIEW *nv;
203 {
204 if (nv != &odev.v) {
205 if (!FEQ(nv->horiz,odev.v.horiz) || /* resize window? */
206 !FEQ(nv->vert,odev.v.vert)) {
207 odev.hres = 2.*VIEWDIST*tan(PI/180./2.*nv->horiz) /
208 pwidth;
209 odev.vres = 2.*VIEWDIST*tan(PI/180./2.*nv->vert) /
210 pheight;
211 XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
212 }
213 copystruct(&odev.v, nv);
214 }
215 qtReplant();
216 }
217
218
219 int
220 dev_input() /* get X11 input */
221 {
222 inpresflags = 0;
223
224 do
225 getevent();
226
227 while (XQLength(ourdisplay) > 0);
228
229 return(inpresflags);
230 }
231
232
233 dev_paintr(rgb, xmin, ymin, xmax, ymax) /* fill a rectangle */
234 BYTE rgb[3];
235 int xmin, ymin, xmax, ymax;
236 {
237 unsigned long pixel;
238
239 if (!mapped)
240 return;
241 if (ncolors > 0)
242 pixel = pixval[get_pixel(rgb, xnewcolr)];
243 else
244 pixel = true_pixel(rgb);
245 XSetForeground(ourdisplay, ourgc, pixel);
246 XFillRectangle(ourdisplay, gwind,
247 ourgc, xmin, odev.vres-ymax, xmax-xmin, ymax-ymin);
248 }
249
250
251 int
252 dev_flush() /* flush output */
253 {
254 qtUpdate();
255 return(XPending(ourdisplay));
256 }
257
258
259 static
260 xnewcolr(ndx, r, g, b) /* enter a color into hardware table */
261 int ndx;
262 int r, g, b;
263 {
264 XColor xcolor;
265
266 xcolor.pixel = pixval[ndx];
267 xcolor.red = r << 8;
268 xcolor.green = g << 8;
269 xcolor.blue = b << 8;
270 xcolor.flags = DoRed|DoGreen|DoBlue;
271
272 XStoreColor(ourdisplay, ourmap, &xcolor);
273 }
274
275
276 static int
277 getpixels() /* get the color map */
278 {
279 XColor thiscolor;
280 register int i, j;
281
282 if (ncolors > 0)
283 return(ncolors);
284 if (ourvinfo.visual == DefaultVisual(ourdisplay,ourscreen)) {
285 ourmap = DefaultColormap(ourdisplay,ourscreen);
286 goto loop;
287 }
288 newmap:
289 ourmap = XCreateColormap(ourdisplay,gwind,ourvinfo.visual,AllocNone);
290 loop:
291 for (ncolors = ourvinfo.colormap_size;
292 ncolors > ourvinfo.colormap_size/3;
293 ncolors = ncolors*.937) {
294 pixval = (unsigned long *)malloc(ncolors*sizeof(unsigned long));
295 if (pixval == NULL)
296 return(ncolors = 0);
297 if (XAllocColorCells(ourdisplay,ourmap,0,NULL,0,pixval,ncolors))
298 break;
299 free((char *)pixval);
300 pixval = NULL;
301 }
302 if (pixval == NULL) {
303 if (ourmap == DefaultColormap(ourdisplay,ourscreen))
304 goto newmap; /* try it with our map */
305 else
306 return(ncolors = 0); /* failed */
307 }
308 if (ourmap != DefaultColormap(ourdisplay,ourscreen))
309 for (i = 0; i < ncolors; i++) { /* reset black and white */
310 if (pixval[i] != ourblack && pixval[i] != ourwhite)
311 continue;
312 thiscolor.pixel = pixval[i];
313 thiscolor.flags = DoRed|DoGreen|DoBlue;
314 XQueryColor(ourdisplay,
315 DefaultColormap(ourdisplay,ourscreen),
316 &thiscolor);
317 XStoreColor(ourdisplay, ourmap, &thiscolor);
318 for (j = i; j+1 < ncolors; j++)
319 pixval[j] = pixval[j+1];
320 ncolors--;
321 i--;
322 }
323 XSetWindowColormap(ourdisplay, gwind, ourmap);
324 return(ncolors);
325 }
326
327
328 static
329 freepixels() /* free our pixels */
330 {
331 if (ncolors == 0)
332 return;
333 XFreeColors(ourdisplay,ourmap,pixval,ncolors,0L);
334 free((char *)pixval);
335 pixval = NULL;
336 ncolors = 0;
337 if (ourmap != DefaultColormap(ourdisplay,ourscreen))
338 XFreeColormap(ourdisplay, ourmap);
339 ourmap = 0;
340 }
341
342
343 static unsigned long
344 true_pixel(rgb) /* return true pixel value for color */
345 register BYTE rgb[3];
346 {
347 register unsigned long rval;
348
349 rval = ourvinfo.red_mask*rgb[RED]/255 & ourvinfo.red_mask;
350 rval |= ourvinfo.green_mask*rgb[GRN]/255 & ourvinfo.green_mask;
351 rval |= ourvinfo.blue_mask*rgb[BLU]/255 & ourvinfo.blue_mask;
352 return(rval);
353 }
354
355
356 static
357 getevent() /* get next event */
358 {
359 XNextEvent(ourdisplay, levptr(XEvent));
360 switch (levptr(XEvent)->type) {
361 case ConfigureNotify:
362 resizewindow(levptr(XConfigureEvent));
363 break;
364 case UnmapNotify:
365 mapped = 0;
366 freepixels();
367 break;
368 case MapNotify:
369 if (ourvinfo.class == PseudoColor ||
370 ourvinfo.class == GrayScale) {
371 if (getpixels() == 0)
372 error(SYSTEM, "cannot allocate colors\n");
373 new_ctab(ncolors);
374 }
375 mapped = 1;
376 break;
377 case Expose:
378 fixwindow(levptr(XExposeEvent));
379 break;
380 case KeyPress:
381 getkey(levptr(XKeyPressedEvent));
382 break;
383 case ButtonPress:
384 getmove(levptr(XButtonPressedEvent));
385 break;
386 }
387 }
388
389
390 static
391 ilclip(dp, wp) /* clip world coordinates to device */
392 int dp[2][2];
393 FVECT wp[2];
394 {
395 static FVECT vmin = {0.,0.,0.}, vmax = {1.,1.,FHUGE};
396 FVECT ip[2];
397 /* not exactly right, but who cares? */
398 viewloc(ip[0], &odev.v, wp[0]);
399 viewloc(ip[1], &odev.v, wp[1]);
400 if (!clip(ip[0], ip[1], vmin, vmax))
401 return(0);
402 dp[0][0] = ip[0][0]*odev.hres;
403 dp[0][1] = ip[0][1]*odev.vres;
404 dp[1][0] = ip[1][0]*odev.hres;
405 dp[1][1] = ip[1][1]*odev.vres;
406 return(1);
407 }
408
409
410 static
411 draw3dline(wp) /* draw 3d line in world coordinates */
412 FVECT wp[2];
413 {
414 int dp[2][2];
415
416 if (!ilclip(dp, wp))
417 return;
418 XDrawLine(ourdisplay, gwind, ourgc,
419 dp[0][0], odev.vres-1 - dp[0][1],
420 dp[1][0], odev.vres-1 - dp[1][1]);
421 }
422
423
424 static
425 draw_grids() /* draw holodeck section grids */
426 {
427 static BYTE gridrgb[3] = {0x0, 0xff, 0xff};
428 unsigned long pixel;
429
430 if (!mapped || odev.v.type != VT_PER)
431 return;
432 if (ncolors > 0)
433 pixel = pixval[get_pixel(gridrgb, xnewcolr)];
434 else
435 pixel = true_pixel(gridrgb);
436 XSetForeground(ourdisplay, ourgc, pixel);
437 /* draw each grid line */
438 gridlines(draw3dline);
439 }
440
441
442 static
443 moveview(dx, dy, move) /* move our view */
444 int dx, dy, move;
445 {
446 VIEW nv;
447 double d;
448 register int i, li;
449 /* start with old view */
450 copystruct(&nv, &odev.v);
451 /* change view direction */
452 if (move) {
453 if ((li = qtFindLeaf(dx, dy)) < 0)
454 return(0); /* not on window */
455 for (i = 0; i < 3; i++)
456 nv.vdir[i] = qtL.wp[li][i] - nv.vp[i];
457 } else {
458 if (viewray(nv.vp, nv.vdir, &odev.v,
459 (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
460 return(0); /* outside view */
461 }
462 /* move viewpoint */
463 if (move > 0)
464 for (i = 0; i < 3; i++)
465 nv.vp[i] += MOVPCT/100. * nv.vdir[i];
466 else if (move < 0)
467 for (i = 0; i < 3; i++)
468 nv.vp[i] -= MOVPCT/100. * nv.vdir[i];
469 if (move && headlocked) {
470 d = 0; /* bring head back to same height */
471 for (i = 0; i < 3; i++)
472 d += odev.v.vup[i] * (odev.v.vp[i] - nv.vp[i]);
473 for (i = 0; i < 3; i++)
474 nv.vp[i] += d * odev.v.vup[i];
475 }
476 if (setview(&nv) != NULL)
477 return(0); /* illegal view */
478 dev_view(&nv);
479 inpresflags |= DEV_NEWVIEW;
480 return(1);
481 }
482
483
484 static
485 getmove(ebut) /* get view change */
486 XButtonPressedEvent *ebut;
487 {
488 int whichbutton = ebut->button;
489 int oldnodesiz = qtMinNodesiz;
490 Window rootw, childw;
491 int rootx, rooty, wx, wy;
492 unsigned int statemask;
493
494 qtMinNodesiz = 16; /* for quicker update */
495 XNoOp(ourdisplay);
496
497 while (!XCheckMaskEvent(ourdisplay,
498 ButtonReleaseMask, levptr(XEvent))) {
499
500 if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
501 &rootx, &rooty, &wx, &wy, &statemask))
502 break; /* on another screen */
503
504 if (!moveview(wx, odev.vres-1-wy, MOVDIR(whichbutton))) {
505 sleep(1);
506 continue;
507 }
508 XClearWindow(ourdisplay, gwind);
509 qtUpdate();
510 draw_grids();
511 }
512 if (!(inpresflags & DEV_NEWVIEW)) { /* do final motion */
513 whichbutton = levptr(XButtonReleasedEvent)->button;
514 wx = levptr(XButtonReleasedEvent)->x;
515 wy = levptr(XButtonReleasedEvent)->y;
516 moveview(wx, odev.vres-1-wy, MOVDIR(whichbutton));
517 }
518 dev_flush();
519
520 qtMinNodesiz = oldnodesiz; /* restore quadtree resolution */
521 }
522
523
524 static
525 getkey(ekey) /* get input key */
526 register XKeyPressedEvent *ekey;
527 {
528 int n;
529 char buf[8];
530
531 n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
532 if (n != 1)
533 return;
534 switch (buf[0]) {
535 case 'h': /* turn on height motion lock */
536 headlocked = 1;
537 return;
538 case 'H': /* turn off height motion lock */
539 headlocked = 0;
540 return;
541 case CTRL('S'):
542 case 'p': /* pause computation */
543 inpresflags |= DEV_WAIT;
544 return;
545 case 'v': /* spit out view */
546 inpresflags |= DEV_PUTVIEW;
547 return;
548 case CTRL('Q'):
549 case '\n':
550 case '\r': /* resume computation */
551 inpresflags |= DEV_RESUME;
552 return;
553 case CTRL('R'): /* redraw screen */
554 if (ncolors > 0)
555 new_ctab(ncolors);
556 qtRedraw(0, 0, odev.hres, odev.vres);
557 return;
558 case CTRL('L'): /* refresh from server */
559 if (inpresflags & DEV_REDRAW)
560 return;
561 XClearWindow(ourdisplay, gwind);
562 draw_grids();
563 XFlush(ourdisplay);
564 qtCompost(100); /* unload the old tree */
565 if (ncolors > 0)
566 new_ctab(ncolors);
567 inpresflags |= DEV_REDRAW; /* resend values from server */
568 return;
569 case CTRL('D'):
570 case 'Q':
571 case 'q': /* quit the program */
572 inpresflags |= DEV_SHUTDOWN;
573 return;
574 default:
575 XBell(ourdisplay, 0);
576 return;
577 }
578 }
579
580
581 static
582 fixwindow(eexp) /* repair damage to window */
583 register XExposeEvent *eexp;
584 {
585 if (odev.hres == 0 || odev.vres == 0) { /* first exposure */
586 odev.hres = eexp->width;
587 odev.vres = eexp->height;
588 inpresflags |= DEV_NEWSIZE;
589 }
590 qtRedraw(eexp->x, odev.vres - eexp->y - eexp->height,
591 eexp->x + eexp->width, odev.vres - eexp->y);
592 }
593
594
595 static
596 resizewindow(ersz) /* resize window */
597 register XConfigureEvent *ersz;
598 {
599 if (ersz->width == odev.hres && ersz->height == odev.vres)
600 return;
601
602 if (odev.hres != 0 && odev.vres != 0) {
603 odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
604 odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
605 inpresflags |= DEV_NEWVIEW;
606 }
607 odev.hres = ersz->width;
608 odev.vres = ersz->height;
609
610 inpresflags |= DEV_NEWSIZE;
611 }