ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_x11.c
Revision: 3.37
Committed: Thu Jan 1 11:21:55 2004 UTC (20 years, 3 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 3.36: +121 -70 lines
Log Message:
Ansification and prototypes.

File Contents

# User Rev Content
1 gregl 3.1 #ifndef lint
2 schorsch 3.37 static const char RCSid[] = "$Id: rhd_x11.c,v 3.36 2003/09/19 18:33:05 greg Exp $";
3 gregl 3.1 #endif
4     /*
5     * X11 driver for holodeck display.
6     * Based on rview driver.
7     */
8    
9 schorsch 3.37 #include <stdlib.h>
10     #include <stdio.h>
11 gregl 3.1 #include <X11/Xlib.h>
12     #include <X11/cursorfont.h>
13     #include <X11/Xutil.h>
14 greg 3.32 #include <time.h>
15 schorsch 3.37
16     #include "platform.h"
17     #include "rtmath.h"
18     #include "rterror.h"
19     #include "plocate.h"
20     #include "rhdisp.h"
21 gwlarson 3.29 #include "rhd_qtree.h"
22 gregl 3.1 #include "x11icon.h"
23    
24 gregl 3.20 #ifndef RAYQLEN
25     #define RAYQLEN 50000 /* max. rays to queue before flush */
26     #endif
27    
28 gregl 3.11 #ifndef FEQ
29     #define FEQ(a,b) ((a)-(b) <= FTINY && (a)-(b) >= -FTINY)
30     #endif
31    
32 gregl 3.1 #define GAMMA 2.2 /* default gamma correction */
33    
34 gwlarson 3.30 #define FRAMESTATE(s) (((s)&(ShiftMask|ControlMask))==(ShiftMask|ControlMask))
35    
36 gregl 3.13 #define MOVPCT 7 /* percent distance to move /frame */
37 gregl 3.2 #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
38 gregl 3.13 #define MOVDEG (-5) /* degrees to orbit CW/down /frame */
39     #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
40 gregl 3.2
41 gregl 3.1 #define MINWIDTH 480 /* minimum graphics window width */
42     #define MINHEIGHT 400 /* minimum graphics window height */
43    
44     #define VIEWDIST 356 /* assumed viewing distance (mm) */
45    
46     #define BORWIDTH 5 /* border width */
47    
48     #define ourscreen DefaultScreen(ourdisplay)
49     #define ourroot RootWindow(ourdisplay,ourscreen)
50     #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
51 gregl 3.2 ButtonPressMask|ButtonReleaseMask)
52 gregl 3.1
53     #define levptr(etype) ((etype *)&currentevent)
54    
55     struct driver odev; /* global device driver structure */
56    
57 gwlarson 3.30 char odev_args[64]; /* command arguments */
58    
59 gregl 3.1 static XEvent currentevent; /* current event */
60    
61     static int ncolors = 0; /* color table size */
62     static int mapped = 0; /* window is mapped? */
63     static unsigned long *pixval = NULL; /* allocated pixels */
64     static unsigned long ourblack=0, ourwhite=1;
65    
66     static Display *ourdisplay = NULL; /* our display */
67     static XVisualInfo ourvinfo; /* our visual information */
68     static Window gwind = 0; /* our graphics window */
69     static GC ourgc = 0; /* our graphics context for drawing */
70     static Colormap ourmap = 0; /* our color map */
71    
72     static double pwidth, pheight; /* pixel dimensions (mm) */
73    
74     static int inpresflags; /* input result flags */
75    
76 gregl 3.2 static int headlocked = 0; /* lock vertical motion */
77 gregl 3.1
78 schorsch 3.37
79     static int mytmflags(void);
80     static void xnewcolr(int ndx, int r, int g, int b);
81     static int getpixels(void);
82     static void freepixels(void);
83     static unsigned long true_pixel(register BYTE rgb[3]);
84     static void getevent(void);
85     static int ilclip(int dp[2][2], FVECT wp[2]);
86     static void draw3dline(FVECT wp[2]);
87     static void draw_grids(void);
88     static int moveview(int dx, int dy, int mov, int orb);
89     static void getframe(XButtonPressedEvent *ebut);
90     static void waitabit(void);
91     static void getmove(XButtonPressedEvent *ebut);
92     static void getkey(register XKeyPressedEvent *ekey);
93     static void fixwindow(register XExposeEvent *eexp);
94     static void resizewindow(register XConfigureEvent *ersz);
95 gregl 3.1
96    
97     static int
98 schorsch 3.37 mytmflags(void) /* figure out tone mapping flags */
99 gregl 3.1 {
100     extern char *progname;
101     register char *cp, *tail;
102     /* find basic name */
103     for (cp = tail = progname; *cp; cp++)
104     if (*cp == '/')
105     tail = cp+1;
106     for (cp = tail; *cp && *cp != '.'; cp++)
107     ;
108     if (cp-tail == 3 && !strncmp(tail, "x11", 3))
109 gregl 3.20 return(TM_F_CAMERA|TM_F_NOSTDERR);
110 gregl 3.1 if (cp-tail == 4 && !strncmp(tail, "x11h", 4))
111 gregl 3.20 return(TM_F_HUMAN|TM_F_NOSTDERR);
112 gregl 3.1 error(USER, "illegal driver name");
113 schorsch 3.37 return 0; /* pro forma return */
114 gregl 3.1 }
115    
116    
117 schorsch 3.37 extern void
118     dev_open( /* initialize X11 driver */
119     char *id
120     )
121 gregl 3.1 {
122 gregl 3.24 static RGBPRIMS myprims = STDPRIMS;
123     char *ev;
124 gregl 3.1 double gamval = GAMMA;
125 gregl 3.24 RGBPRIMP dpri = stdprims;
126 gregl 3.1 int nplanes;
127     XSetWindowAttributes ourwinattr;
128     XWMHints ourxwmhints;
129     XSizeHints oursizhints;
130 gregl 3.2 /* set quadtree globals */
131 gregl 3.4 qtMinNodesiz = 2;
132 gregl 3.1 /* 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     nplanes = DisplayPlanes(ourdisplay, ourscreen);
138     if (XMatchVisualInfo(ourdisplay,ourscreen,
139     nplanes>12?nplanes:24,TrueColor,&ourvinfo) ||
140     XMatchVisualInfo(ourdisplay,ourscreen,
141     nplanes>12?nplanes:24,DirectColor,&ourvinfo)) {
142     ourblack = 0;
143     ourwhite = ourvinfo.red_mask |
144     ourvinfo.green_mask |
145     ourvinfo.blue_mask ;
146     } else {
147     if (nplanes < 4)
148     error(INTERNAL, "not enough colors\n");
149     if (!XMatchVisualInfo(ourdisplay,ourscreen,
150     nplanes,PseudoColor,&ourvinfo) &&
151     !XMatchVisualInfo(ourdisplay,ourscreen,
152     nplanes,GrayScale,&ourvinfo))
153     error(INTERNAL, "unsupported visual type\n");
154     ourblack = BlackPixel(ourdisplay,ourscreen);
155     ourwhite = WhitePixel(ourdisplay,ourscreen);
156     }
157     /* set gamma and tone mapping */
158 gregl 3.24 if ((ev = XGetDefault(ourdisplay, "radiance", "gamma")) != NULL
159     || (ev = getenv("DISPLAY_GAMMA")) != NULL)
160     gamval = atof(ev);
161     if ((ev = getenv("DISPLAY_PRIMARIES")) != NULL &&
162     sscanf(ev, "%f %f %f %f %f %f %f %f",
163     &myprims[RED][CIEX],&myprims[RED][CIEY],
164     &myprims[GRN][CIEX],&myprims[GRN][CIEY],
165     &myprims[BLU][CIEX],&myprims[BLU][CIEY],
166     &myprims[WHT][CIEX],&myprims[WHT][CIEY]) >= 6)
167     dpri = myprims;
168     if (tmInit(mytmflags(), dpri, gamval) == NULL)
169 gregl 3.1 error(SYSTEM, "not enough memory in dev_open");
170     /* open window */
171     ourwinattr.background_pixel = ourblack;
172     ourwinattr.border_pixel = ourblack;
173     ourwinattr.event_mask = ourmask;
174     /* this is stupid */
175     ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
176     ourvinfo.visual, AllocNone);
177     gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
178     DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
179     DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
180     BORWIDTH, ourvinfo.depth, InputOutput, ourvinfo.visual,
181     CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
182     if (gwind == 0)
183     error(SYSTEM, "cannot create window\n");
184     XStoreName(ourdisplay, gwind, id);
185     /* get graphics context */
186     ourgc = XCreateGC(ourdisplay, gwind, 0, NULL);
187     /* set window manager hints */
188     ourxwmhints.flags = InputHint|IconPixmapHint;
189     ourxwmhints.input = True;
190     ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
191     gwind, x11icon_bits, x11icon_width, x11icon_height);
192     XSetWMHints(ourdisplay, gwind, &ourxwmhints);
193     oursizhints.min_width = MINWIDTH;
194     oursizhints.min_height = MINHEIGHT;
195     oursizhints.flags = PMinSize;
196     XSetNormalHints(ourdisplay, gwind, &oursizhints);
197 gregl 3.18 /* figure out sensible view */
198     pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
199     DisplayWidth(ourdisplay, ourscreen);
200     pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
201     DisplayHeight(ourdisplay, ourscreen);
202 schorsch 3.34 odev.v = stdview;
203 gregl 3.18 odev.v.type = VT_PER;
204 gregl 3.1 /* map the window and get its size */
205     XMapWindow(ourdisplay, gwind);
206 gregl 3.18 dev_input(); /* sets size and view angles */
207 gregl 3.2 /* allocate our leaf pile */
208     if (!qtAllocLeaves(DisplayWidth(ourdisplay,ourscreen) *
209 gregl 3.21 DisplayHeight(ourdisplay,ourscreen) * 3 /
210     (qtMinNodesiz*qtMinNodesiz*2)))
211 gregl 3.2 error(SYSTEM, "insufficient memory for leaf storage");
212 gregl 3.1 odev.name = id;
213     odev.ifd = ConnectionNumber(ourdisplay);
214     }
215    
216    
217 schorsch 3.37 extern void
218     dev_close(void) /* close our display */
219 gregl 3.1 {
220     freepixels();
221     XFreeGC(ourdisplay, ourgc);
222     XDestroyWindow(ourdisplay, gwind);
223     gwind = 0;
224     ourgc = 0;
225     XCloseDisplay(ourdisplay);
226     ourdisplay = NULL;
227     qtFreeLeaves();
228     tmDone(NULL);
229     odev.v.type = 0;
230     odev.hres = odev.vres = 0;
231     odev.ifd = -1;
232     }
233    
234    
235 schorsch 3.37 extern void
236     dev_clear(void) /* clear our quadtree */
237 gregl 3.23 {
238     qtCompost(100);
239     if (ncolors > 0)
240     new_ctab(ncolors);
241     rayqleft = 0; /* hold off update */
242     }
243    
244    
245 schorsch 3.37 extern int
246     dev_view( /* assign new driver view */
247     VIEW *nv
248     )
249 gregl 3.1 {
250 gregl 3.13 if (nv->type == VT_PAR || /* check view legality */
251 gregl 3.17 nv->horiz > 160. || nv->vert > 160.) {
252 gregl 3.13 error(COMMAND, "illegal view type/angle");
253     nv->type = VT_PER;
254     nv->horiz = odev.v.horiz;
255     nv->vert = odev.v.vert;
256     return(0);
257     }
258     if (nv->vfore > FTINY) {
259     error(COMMAND, "cannot handle fore clipping");
260     nv->vfore = 0.;
261     return(0);
262     }
263 gregl 3.11 if (nv != &odev.v) {
264     if (!FEQ(nv->horiz,odev.v.horiz) || /* resize window? */
265     !FEQ(nv->vert,odev.v.vert)) {
266 gregl 3.13 int dw = DisplayWidth(ourdisplay,ourscreen);
267     int dh = DisplayHeight(ourdisplay,ourscreen);
268    
269     dw -= 25; /* for window frame */
270 gregl 3.16 dh -= 50;
271 gregl 3.12 odev.hres = 2.*VIEWDIST/pwidth *
272     tan(PI/180./2.*nv->horiz);
273     odev.vres = 2.*VIEWDIST/pheight *
274     tan(PI/180./2.*nv->vert);
275 gregl 3.13 if (odev.hres > dw) {
276     odev.vres = dw * odev.vres / odev.hres;
277     odev.hres = dw;
278     }
279     if (odev.vres > dh) {
280     odev.hres = dh * odev.hres / odev.vres;
281     odev.vres = dh;
282     }
283 gregl 3.11 XResizeWindow(ourdisplay, gwind, odev.hres, odev.vres);
284 gregl 3.18 dev_input(); /* wait for resize event */
285 gregl 3.11 }
286 schorsch 3.34 odev.v = *nv;
287 gregl 3.11 }
288 gregl 3.1 qtReplant();
289 gregl 3.13 return(1);
290 gwlarson 3.26 }
291    
292    
293 schorsch 3.37 extern void
294     dev_section( /* add octree for geometry rendering */
295     char *ofn
296     )
297 gwlarson 3.31 {
298     /* unimplemented */
299     }
300    
301    
302 schorsch 3.37 extern void
303     dev_auxcom( /* process an auxiliary command */
304     char *cmd,
305     char *args
306     )
307 gwlarson 3.26 {
308     sprintf(errmsg, "%s: unknown command", cmd);
309     error(COMMAND, errmsg);
310 gregl 3.1 }
311    
312    
313 schorsch 3.37 extern VIEW *
314     dev_auxview( /* return nth auxiliary view */
315     int n,
316     int hvres[2]
317     )
318 gwlarson 3.25 {
319     if (n)
320     return(NULL);
321     hvres[0] = odev.hres; hvres[1] = odev.vres;
322     return(&odev.v);
323     }
324    
325    
326 schorsch 3.37 extern int
327     dev_input(void) /* get X11 input */
328 gregl 3.1 {
329     inpresflags = 0;
330 gregl 3.5
331 gregl 3.1 do
332     getevent();
333    
334 gwlarson 3.27 while (XPending(ourdisplay) > 0);
335 gregl 3.1
336 gwlarson 3.27 odev.inpready = 0;
337    
338 gregl 3.1 return(inpresflags);
339     }
340    
341    
342 schorsch 3.37 extern void
343     dev_paintr( /* fill a rectangle */
344     BYTE rgb[3],
345     int xmin,
346     int ymin,
347     int xmax,
348     int ymax
349     )
350 gregl 3.1 {
351     unsigned long pixel;
352    
353     if (!mapped)
354     return;
355     if (ncolors > 0)
356     pixel = pixval[get_pixel(rgb, xnewcolr)];
357     else
358     pixel = true_pixel(rgb);
359     XSetForeground(ourdisplay, ourgc, pixel);
360     XFillRectangle(ourdisplay, gwind,
361     ourgc, xmin, odev.vres-ymax, xmax-xmin, ymax-ymin);
362     }
363    
364    
365 schorsch 3.37 extern int
366     dev_flush(void) /* flush output */
367 gregl 3.1 {
368     qtUpdate();
369 gregl 3.20 rayqleft = RAYQLEN;
370 gwlarson 3.27 return(odev.inpready = XPending(ourdisplay));
371 gregl 3.1 }
372    
373    
374 schorsch 3.37 static void
375     xnewcolr( /* enter a color into hardware table */
376     int ndx,
377     int r,
378     int g,
379     int b
380     )
381 gregl 3.1 {
382     XColor xcolor;
383    
384     xcolor.pixel = pixval[ndx];
385     xcolor.red = r << 8;
386     xcolor.green = g << 8;
387     xcolor.blue = b << 8;
388     xcolor.flags = DoRed|DoGreen|DoBlue;
389    
390     XStoreColor(ourdisplay, ourmap, &xcolor);
391     }
392    
393    
394     static int
395 schorsch 3.37 getpixels(void) /* get the color map */
396 gregl 3.1 {
397     XColor thiscolor;
398     register int i, j;
399    
400     if (ncolors > 0)
401     return(ncolors);
402     if (ourvinfo.visual == DefaultVisual(ourdisplay,ourscreen)) {
403     ourmap = DefaultColormap(ourdisplay,ourscreen);
404     goto loop;
405     }
406     newmap:
407     ourmap = XCreateColormap(ourdisplay,gwind,ourvinfo.visual,AllocNone);
408     loop:
409     for (ncolors = ourvinfo.colormap_size;
410     ncolors > ourvinfo.colormap_size/3;
411     ncolors = ncolors*.937) {
412     pixval = (unsigned long *)malloc(ncolors*sizeof(unsigned long));
413     if (pixval == NULL)
414     return(ncolors = 0);
415     if (XAllocColorCells(ourdisplay,ourmap,0,NULL,0,pixval,ncolors))
416     break;
417 greg 3.32 free((void *)pixval);
418 gregl 3.1 pixval = NULL;
419     }
420     if (pixval == NULL) {
421     if (ourmap == DefaultColormap(ourdisplay,ourscreen))
422     goto newmap; /* try it with our map */
423     else
424     return(ncolors = 0); /* failed */
425     }
426     if (ourmap != DefaultColormap(ourdisplay,ourscreen))
427     for (i = 0; i < ncolors; i++) { /* reset black and white */
428     if (pixval[i] != ourblack && pixval[i] != ourwhite)
429     continue;
430     thiscolor.pixel = pixval[i];
431     thiscolor.flags = DoRed|DoGreen|DoBlue;
432     XQueryColor(ourdisplay,
433     DefaultColormap(ourdisplay,ourscreen),
434     &thiscolor);
435     XStoreColor(ourdisplay, ourmap, &thiscolor);
436     for (j = i; j+1 < ncolors; j++)
437     pixval[j] = pixval[j+1];
438     ncolors--;
439     i--;
440     }
441     XSetWindowColormap(ourdisplay, gwind, ourmap);
442     return(ncolors);
443     }
444    
445    
446 schorsch 3.37 static void
447     freepixels(void) /* free our pixels */
448 gregl 3.1 {
449     if (ncolors == 0)
450     return;
451     XFreeColors(ourdisplay,ourmap,pixval,ncolors,0L);
452 greg 3.32 free((void *)pixval);
453 gregl 3.1 pixval = NULL;
454     ncolors = 0;
455     if (ourmap != DefaultColormap(ourdisplay,ourscreen))
456     XFreeColormap(ourdisplay, ourmap);
457     ourmap = 0;
458     }
459    
460    
461     static unsigned long
462 schorsch 3.37 true_pixel( /* return true pixel value for color */
463     register BYTE rgb[3]
464     )
465 gregl 3.1 {
466     register unsigned long rval;
467    
468     rval = ourvinfo.red_mask*rgb[RED]/255 & ourvinfo.red_mask;
469     rval |= ourvinfo.green_mask*rgb[GRN]/255 & ourvinfo.green_mask;
470     rval |= ourvinfo.blue_mask*rgb[BLU]/255 & ourvinfo.blue_mask;
471     return(rval);
472     }
473    
474    
475 schorsch 3.37 static void
476     getevent(void) /* get next event */
477 gregl 3.1 {
478     XNextEvent(ourdisplay, levptr(XEvent));
479     switch (levptr(XEvent)->type) {
480     case ConfigureNotify:
481     resizewindow(levptr(XConfigureEvent));
482     break;
483     case UnmapNotify:
484     mapped = 0;
485     freepixels();
486     break;
487     case MapNotify:
488     if (ourvinfo.class == PseudoColor ||
489     ourvinfo.class == GrayScale) {
490     if (getpixels() == 0)
491     error(SYSTEM, "cannot allocate colors\n");
492     new_ctab(ncolors);
493     }
494     mapped = 1;
495     break;
496     case Expose:
497     fixwindow(levptr(XExposeEvent));
498     break;
499     case KeyPress:
500     getkey(levptr(XKeyPressedEvent));
501     break;
502     case ButtonPress:
503 gwlarson 3.30 if (FRAMESTATE(levptr(XButtonPressedEvent)->state))
504     getframe(levptr(XButtonPressedEvent));
505     else
506     getmove(levptr(XButtonPressedEvent));
507 gregl 3.1 break;
508     }
509     }
510    
511    
512 schorsch 3.37 static int
513     ilclip( /* clip world coordinates to device */
514     int dp[2][2],
515     FVECT wp[2]
516     )
517 gregl 3.9 {
518 gwlarson 3.28 static FVECT vmin = {0.,0.,0.}, vmax = {1.-FTINY,1.-FTINY,FHUGE};
519     FVECT wpc[2], ip[2];
520     double d, d0, d1;
521     /* check for points behind view */
522     d = DOT(odev.v.vp, odev.v.vdir);
523     d0 = DOT(wp[0], odev.v.vdir) - d;
524     d1 = DOT(wp[1], odev.v.vdir) - d;
525     /* work on copy of world points */
526     if (d0 <= d1) {
527     VCOPY(wpc[0], wp[0]); VCOPY(wpc[1], wp[1]);
528     } else {
529     d = d0; d0 = d1; d1 = d;
530     VCOPY(wpc[1], wp[0]); VCOPY(wpc[0], wp[1]);
531     }
532     if (d0 <= FTINY) {
533     if (d1 <= FTINY) return(0);
534     VSUB(wpc[0], wpc[0], wpc[1]);
535     d = .99*d1/(d1-d0);
536     VSUM(wpc[0], wpc[1], wpc[0], d);
537     }
538     /* get view coordinates and clip to window */
539     viewloc(ip[0], &odev.v, wpc[0]);
540     viewloc(ip[1], &odev.v, wpc[1]);
541 gregl 3.9 if (!clip(ip[0], ip[1], vmin, vmax))
542     return(0);
543     dp[0][0] = ip[0][0]*odev.hres;
544     dp[0][1] = ip[0][1]*odev.vres;
545     dp[1][0] = ip[1][0]*odev.hres;
546     dp[1][1] = ip[1][1]*odev.vres;
547     return(1);
548     }
549    
550    
551 schorsch 3.37 static void
552     draw3dline( /* draw 3d line in world coordinates */
553     FVECT wp[2]
554     )
555 gregl 3.9 {
556     int dp[2][2];
557    
558     if (!ilclip(dp, wp))
559     return;
560     XDrawLine(ourdisplay, gwind, ourgc,
561     dp[0][0], odev.vres-1 - dp[0][1],
562     dp[1][0], odev.vres-1 - dp[1][1]);
563     }
564    
565    
566 schorsch 3.37 static void
567     draw_grids(void) /* draw holodeck section grids */
568 gregl 3.9 {
569     static BYTE gridrgb[3] = {0x0, 0xff, 0xff};
570     unsigned long pixel;
571    
572     if (ncolors > 0)
573     pixel = pixval[get_pixel(gridrgb, xnewcolr)];
574     else
575     pixel = true_pixel(gridrgb);
576     XSetForeground(ourdisplay, ourgc, pixel);
577     /* draw each grid line */
578     gridlines(draw3dline);
579     }
580    
581    
582 schorsch 3.37 static int
583     moveview( /* move our view */
584     int dx,
585     int dy,
586     int mov,
587     int orb
588     )
589 gregl 3.2 {
590     VIEW nv;
591 gregl 3.17 FVECT odir, v1;
592 gregl 3.2 double d;
593 gregl 3.13 register int li;
594 gregl 3.2 /* start with old view */
595 schorsch 3.34 nv = odev.v;
596 gregl 3.2 /* change view direction */
597 gregl 3.13 if (mov | orb) {
598 gregl 3.4 if ((li = qtFindLeaf(dx, dy)) < 0)
599 gregl 3.2 return(0); /* not on window */
600 gregl 3.17 VSUM(odir, qtL.wp[li], nv.vp, -1.);
601 gregl 3.2 } else {
602     if (viewray(nv.vp, nv.vdir, &odev.v,
603     (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY)
604     return(0); /* outside view */
605     }
606 gregl 3.13 if (orb && mov) { /* orbit left/right */
607 gregl 3.17 spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
608     VSUM(nv.vp, qtL.wp[li], odir, -1.);
609     spinvector(nv.vdir, nv.vdir, nv.vup, d);
610 gregl 3.13 } else if (orb) { /* orbit up/down */
611 gregl 3.17 fcross(v1, odir, nv.vup);
612 gregl 3.13 if (normalize(v1) == 0.)
613     return(0);
614 gregl 3.17 spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
615     VSUM(nv.vp, qtL.wp[li], odir, -1.);
616     spinvector(nv.vdir, nv.vdir, v1, d);
617 gregl 3.13 } else if (mov) { /* move forward/backward */
618     d = MOVPCT/100. * mov;
619 gregl 3.17 VSUM(nv.vp, nv.vp, odir, d);
620 gregl 3.2 }
621 gregl 3.13 if (!mov ^ !orb && headlocked) { /* restore head height */
622     VSUM(v1, odev.v.vp, nv.vp, -1.);
623     d = DOT(v1, odev.v.vup);
624     VSUM(nv.vp, nv.vp, odev.v.vup, d);
625     }
626 gregl 3.2 if (setview(&nv) != NULL)
627     return(0); /* illegal view */
628     dev_view(&nv);
629 gregl 3.14 inpresflags |= DFL(DC_SETVIEW);
630 gregl 3.2 return(1);
631     }
632    
633    
634 schorsch 3.37 static void
635     getframe( /* get focus frame */
636     XButtonPressedEvent *ebut
637     )
638 gwlarson 3.30 {
639     int startx = ebut->x, starty = ebut->y;
640     int endx, endy;
641    
642     XMaskEvent(ourdisplay, ButtonReleaseMask, levptr(XEvent));
643     endx = levptr(XButtonReleasedEvent)->x;
644     endy = levptr(XButtonReleasedEvent)->y;
645 schorsch 3.35 if ((endx == startx) | (endy == starty)) {
646 gwlarson 3.30 XBell(ourdisplay, 0);
647     return;
648     }
649     if (endx < startx) {register int c = endx; endx = startx; startx = c;}
650     if (endy < starty) {register int c = endy; endy = starty; starty = c;}
651     sprintf(odev_args, "%.3f %.3f %.3f %.3f",
652     (startx+.5)/odev.hres, 1.-(endy+.5)/odev.vres,
653     (endx+.5)/odev.hres, 1.-(starty+.5)/odev.vres);
654     inpresflags |= DFL(DC_FOCUS);
655     }
656    
657    
658 schorsch 3.37 static void
659     waitabit(void) /* pause a moment */
660 greg 3.32 {
661     struct timespec ts;
662     ts.tv_sec = 0;
663 greg 3.36 ts.tv_nsec = 100000000;
664 greg 3.32 nanosleep(&ts, NULL);
665     }
666    
667    
668 schorsch 3.37 static void
669     getmove( /* get view change */
670     XButtonPressedEvent *ebut
671     )
672 gregl 3.2 {
673 gregl 3.13 int movdir = MOVDIR(ebut->button);
674     int movorb = MOVORB(ebut->state);
675 gregl 3.2 int oldnodesiz = qtMinNodesiz;
676     Window rootw, childw;
677     int rootx, rooty, wx, wy;
678     unsigned int statemask;
679    
680     qtMinNodesiz = 16; /* for quicker update */
681 gregl 3.9 XNoOp(ourdisplay);
682 gregl 3.2
683 gregl 3.9 while (!XCheckMaskEvent(ourdisplay,
684     ButtonReleaseMask, levptr(XEvent))) {
685 greg 3.32 waitabit();
686 gregl 3.2 if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
687     &rootx, &rooty, &wx, &wy, &statemask))
688     break; /* on another screen */
689    
690 gregl 3.13 if (!moveview(wx, odev.vres-1-wy, movdir, movorb)) {
691 gregl 3.2 sleep(1);
692 gregl 3.9 continue;
693     }
694     XClearWindow(ourdisplay, gwind);
695     qtUpdate();
696     draw_grids();
697     }
698 gregl 3.14 if (!(inpresflags & DFL(DC_SETVIEW))) { /* do final motion */
699 gregl 3.13 movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
700 gregl 3.2 wx = levptr(XButtonReleasedEvent)->x;
701     wy = levptr(XButtonReleasedEvent)->y;
702 gregl 3.13 moveview(wx, odev.vres-1-wy, movdir, movorb);
703 gregl 3.2 }
704 gregl 3.9 dev_flush();
705 gregl 3.2
706     qtMinNodesiz = oldnodesiz; /* restore quadtree resolution */
707     }
708    
709    
710 schorsch 3.37 static void
711     getkey( /* get input key */
712     register XKeyPressedEvent *ekey
713     )
714 gregl 3.1 {
715 gwlarson 3.30 Window rootw, childw;
716     int rootx, rooty, wx, wy;
717     unsigned int statemask;
718 gregl 3.1 int n;
719     char buf[8];
720    
721     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
722     if (n != 1)
723     return;
724     switch (buf[0]) {
725     case 'h': /* turn on height motion lock */
726 gregl 3.2 headlocked = 1;
727 gregl 3.1 return;
728     case 'H': /* turn off height motion lock */
729 gregl 3.2 headlocked = 0;
730 gregl 3.13 return;
731     case 'l': /* retrieve last view */
732 gregl 3.14 inpresflags |= DFL(DC_LASTVIEW);
733 gwlarson 3.30 return;
734     case 'f': /* frame view position */
735     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
736     &rootx, &rooty, &wx, &wy, &statemask))
737     return; /* on another screen */
738     sprintf(odev_args, "%.4f %.4f", (wx+.5)/odev.hres,
739     1.-(wy+.5)/odev.vres);
740     inpresflags |= DFL(DC_FOCUS);
741     return;
742     case 'F': /* unfocus */
743     odev_args[0] = '\0';
744     inpresflags |= DFL(DC_FOCUS);
745 gregl 3.1 return;
746 gregl 3.2 case 'p': /* pause computation */
747 gregl 3.14 inpresflags |= DFL(DC_PAUSE);
748 gregl 3.2 return;
749 gregl 3.7 case 'v': /* spit out view */
750 gregl 3.14 inpresflags |= DFL(DC_GETVIEW);
751 gregl 3.7 return;
752 gregl 3.2 case '\n':
753 gregl 3.5 case '\r': /* resume computation */
754 gregl 3.14 inpresflags |= DFL(DC_RESUME);
755 gregl 3.2 return;
756 gregl 3.7 case CTRL('R'): /* redraw screen */
757     if (ncolors > 0)
758     new_ctab(ncolors);
759     qtRedraw(0, 0, odev.hres, odev.vres);
760     return;
761     case CTRL('L'): /* refresh from server */
762 gregl 3.14 if (inpresflags & DFL(DC_REDRAW))
763 gregl 3.8 return;
764 gregl 3.7 XClearWindow(ourdisplay, gwind);
765 gregl 3.9 draw_grids();
766 gregl 3.8 XFlush(ourdisplay);
767 gregl 3.6 qtCompost(100); /* unload the old tree */
768 gregl 3.3 if (ncolors > 0)
769     new_ctab(ncolors);
770 gregl 3.14 inpresflags |= DFL(DC_REDRAW); /* resend values from server */
771 gregl 3.22 rayqleft = 0; /* hold off update */
772 gregl 3.3 return;
773 gregl 3.15 case 'K': /* kill rtrace process(es) */
774     inpresflags |= DFL(DC_KILL);
775     break;
776     case 'R': /* restart rtrace */
777     inpresflags |= DFL(DC_RESTART);
778     break;
779     case 'C': /* clobber holodeck */
780     inpresflags |= DFL(DC_CLOBBER);
781     break;
782 gregl 3.1 case 'q': /* quit the program */
783 gregl 3.14 inpresflags |= DFL(DC_QUIT);
784 gregl 3.1 return;
785     default:
786     XBell(ourdisplay, 0);
787     return;
788     }
789     }
790    
791    
792 schorsch 3.37 static void
793     fixwindow( /* repair damage to window */
794     register XExposeEvent *eexp
795     )
796 gregl 3.1 {
797     if (odev.hres == 0 || odev.vres == 0) { /* first exposure */
798     odev.hres = eexp->width;
799     odev.vres = eexp->height;
800     }
801     qtRedraw(eexp->x, odev.vres - eexp->y - eexp->height,
802     eexp->x + eexp->width, odev.vres - eexp->y);
803     }
804    
805    
806 schorsch 3.37 static void
807     resizewindow( /* resize window */
808     register XConfigureEvent *ersz
809     )
810 gregl 3.1 {
811     if (ersz->width == odev.hres && ersz->height == odev.vres)
812     return;
813    
814     odev.hres = ersz->width;
815     odev.vres = ersz->height;
816    
817 gregl 3.12 odev.v.horiz = 2.*180./PI * atan(0.5/VIEWDIST*pwidth*odev.hres);
818     odev.v.vert = 2.*180./PI * atan(0.5/VIEWDIST*pheight*odev.vres);
819    
820 gregl 3.14 inpresflags |= DFL(DC_SETVIEW);
821 gregl 3.1 }