ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/glrad.c
Revision: 3.4
Committed: Wed Jun 10 17:52:18 1998 UTC (25 years, 9 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.3: +77 -7 lines
Log Message:
added stereo viewing with -S option
added -s option for silent running
added check of render options for -bv-

File Contents

# User Rev Content
1 gwlarson 3.1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ SGI";
5     #endif
6    
7     /*
8     * Program to display Radiance scene using OpenGL.
9     */
10    
11     #include "radogl.h"
12     #include "view.h"
13     #include "paths.h"
14     #include <sys/types.h>
15     #include <GL/glx.h>
16 gwlarson 3.4 #ifndef NOSTEREO
17     #include <X11/extensions/SGIStereo.h>
18     #endif
19 gwlarson 3.1 #include <ctype.h>
20     #include "glradicon.h"
21    
22     #ifndef MAXVIEW
23     #define MAXVIEW 63 /* maximum number of standard views */
24     #endif
25     #ifndef MAXSCENE
26     #define MAXSCENE 127 /* maximum number of scene files */
27     #endif
28    
29     #define ZOOMPCT 9 /* percent to zoom at a time */
30    
31     #define MOVPCT 7 /* percent distance to move /frame */
32     #define MOVDIR(b) ((b)==Button1 ? 1 : (b)==Button2 ? 0 : -1)
33     #define MOVDEG (-5) /* degrees to orbit CW/down /frame */
34     #define MOVORB(s) ((s)&ShiftMask ? 1 : (s)&ControlMask ? -1 : 0)
35    
36     #define MINWIDTH 480 /* minimum graphics window width */
37     #define MINHEIGHT 400 /* minimum graphics window height */
38    
39     #define BORWIDTH 5 /* border width */
40    
41     #define ourscreen DefaultScreen(ourdisplay)
42     #define ourroot RootWindow(ourdisplay,ourscreen)
43     #define ourmask (StructureNotifyMask|ExposureMask|KeyPressMask|\
44     ButtonPressMask|ButtonReleaseMask)
45    
46     #define levptr(etype) ((etype *)&currentevent)
47    
48     XEvent currentevent; /* current event */
49    
50     int mapped = 0; /* window is mapped? */
51     unsigned long ourblack=0, ourwhite=~0;
52    
53     Display *ourdisplay = NULL; /* our display */
54     XVisualInfo *ourvinf; /* our visual information */
55     Window gwind = 0; /* our graphics window */
56     int hres, vres; /* rendering window dimensions */
57     int maxhres, maxvres; /* maximum given dimensions */
58     GLXContext gctx; /* our GLX context */
59    
60     double pwidth, pheight; /* pixel dimensions (mm) */
61    
62     int headlocked = 0; /* lock vertical motion */
63    
64     struct {
65     char *nam; /* view name (NULL if none) */
66     VIEW *v; /* parameters (NULL term.) */
67     } vwl[MAXVIEW+1]; /* our list of views */
68    
69     int currentview = 0; /* current view number */
70     VIEW thisview = STDVIEW; /* displayed view */
71 gwlarson 3.4 double eyedist = 1; /* interocular distance */
72 gwlarson 3.1 VIEW lastview; /* last recorded view */
73    
74     char *progname; /* global argv[0] */
75     char *radfile; /* rad input file */
76     char *scene[MAXSCENE+1]; /* material and scene file list */
77     int nscenef = 0; /* number of scene files */
78     char *octree; /* octree name (NULL if unnec.) */
79    
80     int rtpd[3]; /* rtrace process descriptors */
81    
82 gwlarson 3.4 int silent = 0; /* run rad silently? */
83 gwlarson 3.1 int backvis = 1; /* back faces visible? */
84 gwlarson 3.4 int stereo = 0; /* do stereo? */
85 gwlarson 3.1
86 gwlarson 3.4 #ifdef NOSTEREO
87     #define setstereobuf(bid) 0
88     #else
89     #define setstereobuf(bid) (glXWaitGL(), \
90     XSGISetStereoBuffer(ourdisplay, gwind, bid), \
91     glXWaitX())
92     #endif
93    
94 gwlarson 3.1 int displist; /* our scene display list */
95    
96 gwlarson 3.2 int in_dev_view = 0; /* currently in dev_view() */
97    
98 gwlarson 3.4 #ifdef BSD
99     #define strchr index
100     #endif
101    
102     extern char *strchr(), *fgets(), *fgetline(), *atos(), *scan4var();
103 gwlarson 3.1 extern int nowarn; /* turn warnings off? */
104     extern time_t time();
105    
106    
107     main(argc, argv)
108     int argc;
109     char *argv[];
110     {
111     char *viewsel = NULL;
112     long vwintvl = 0;
113     int i;
114    
115     progname = argv[0];
116     for (i = 1; i < argc && argv[i][0] == '-'; i++)
117     switch (argv[i][1]) {
118     case 'v':
119     viewsel = argv[++i];
120     break;
121     case 'w':
122     nowarn = !nowarn;
123     break;
124 gwlarson 3.4 case 's':
125     silent = !silent;
126     break;
127     case 'S':
128     stereo = !stereo;
129     break;
130 gwlarson 3.1 case 'c':
131     vwintvl = atoi(argv[++i]);
132     break;
133     case 'b':
134     backvis = !backvis;
135     break;
136     default:
137     goto userr;
138     }
139     if (i >= argc)
140     goto userr;
141 gwlarson 3.4 #ifdef NOSTEREO
142     if (stereo)
143     error(INTERNAL, "stereo not supported in this version");
144     #endif
145 gwlarson 3.1 /* run rad and get views */
146     runrad(argc-i, argv+i);
147     /* check view */
148 gwlarson 3.3 if (viewsel != NULL)
149     if (viewsel[0] == '-') {
150     char *ve = viewsel;
151     if (!sscanview(&thisview, viewsel) ||
152     (ve = setview(&thisview)) != NULL) {
153     fprintf(stderr, "%s: bad view: %s\n",
154     progname, ve);
155     quit(1);
156     }
157     currentview = -1;
158     } else if ((currentview = findvw(viewsel)) < 0) {
159     fprintf(stderr, "%s: no such view: %s\n",
160     progname, viewsel);
161     quit(1);
162     }
163 gwlarson 3.1 /* open GL */
164     dev_open(radfile = argv[i]);
165     /* load octree or scene files */
166     if (octree != NULL) {
167     displist = rgl_octlist(octree, NULL, NULL);
168     startrtrace(octree);
169     } else
170     displist = rgl_filelist(nscenef, scene);
171     /* set initial view */
172 gwlarson 3.3 dev_view(currentview < 0 ? &thisview : vwl[currentview].v);
173 gwlarson 3.1 /* input/render loop */
174     while (dev_input(vwintvl))
175     ;
176     /* all done */
177     quit(0);
178     userr:
179 gwlarson 3.3 fprintf(stderr, "Usage: %s [-w][-b][-v view] rfile [VAR=value]..\n",
180 gwlarson 3.1 argv[0]);
181     quit(1);
182     }
183    
184    
185     quit(code) /* exit gracefully */
186     int code;
187     {
188     if (ourdisplay != NULL)
189     dev_close();
190     if (rtpd[2] > 0) {
191     if (close_process(rtpd) > 0)
192     wputs("bad exit status from rtrace\n");
193     rtpd[2] = 0;
194     }
195     exit(code);
196     }
197    
198    
199     startrtrace(octname) /* start rtrace on octname */
200     char *octname;
201     {
202     static char *av[12] = {"rtrace", "-h", "-fff", "-ld+",
203     "-opL", "-x", "1"};
204     int ac = 7;
205    
206     if (nowarn) av[ac++] = "-w-";
207     av[ac++] = octname;
208     av[ac] = NULL;
209     if (open_process(rtpd, av) <= 0)
210     error(SYSTEM, "cannot start rtrace process");
211     }
212    
213    
214     runrad(ac, av) /* run rad and load variables */
215     int ac;
216     char **av;
217     {
218     static char optfile[] = TEMPLATE;
219     int nvn = 0, nvv = 0;
220     FILE *fp;
221     int cval;
222     register char *cp;
223     char radcomm[256], buf[128], nam[32];
224     /* set rad commmand */
225     strcpy(radcomm, "rad -w -v 0 "); /* look out below! */
226     cp = radcomm + 19;
227 gwlarson 3.4 if (silent) {
228     strcpy(cp, "-s ");
229     cp += 3;
230     }
231 gwlarson 3.1 while (ac--) {
232     strcpy(cp, *av++);
233     while (*cp) cp++;
234     *cp++ = ' ';
235     }
236     strcpy(cp, "OPTFILE="); /* create temporary options file */
237     strcpy(cp+8, mktemp(optfile));
238     if (system(radcomm)) /* update octree */
239     error(USER, "error executing rad command");
240     /* replace "-v 0" with "-n -e -s -V" */
241     strcpy(radcomm+7, "-n -e -s -V");
242     radcomm[18] = ' ';
243     if ((fp = popen(radcomm, "r")) == NULL)
244     error(SYSTEM, "cannot start rad command");
245     buf[0] = '\0'; /* read variables alphabetically */
246     /* get exposure */
247     if ((cp = scan4var(buf, sizeof(buf), "EXPOSURE", fp)) != NULL) {
248     expval = atof(cp);
249     if (*cp == '-' | *cp == '+')
250     expval = pow(2., expval);
251 gwlarson 3.3 expval *= 0.5; /* compensate for local shading */
252 gwlarson 3.1 }
253 gwlarson 3.4 /* look for eye separation */
254     if ((cp = scan4var(buf, sizeof(buf), "EYESEP", fp)) != NULL)
255     eyedist = atof(cp);
256 gwlarson 3.1 /* look for materials */
257     while ((cp = scan4var(buf, sizeof(buf), "materials", fp)) != NULL) {
258     nscenef += wordstring(scene+nscenef, cp);
259     buf[0] = '\0';
260     }
261     /* look for octree */
262     if ((cp = scan4var(buf, sizeof(buf), "OCTREE", fp)) != NULL)
263     octree = savqstr(cp);
264     /* look for scene files */
265     while ((cp = scan4var(buf, sizeof(buf), "scene", fp)) != NULL) {
266     nscenef += wordstring(scene+nscenef, cp);
267     buf[0] = '\0';
268     }
269     /* load view names */
270     while ((cp = scan4var(buf, sizeof(buf), "view", fp)) != NULL) {
271     if (nvn >= MAXVIEW)
272     error(INTERNAL, "too many views in rad file");
273     vwl[nvn++].nam = *cp == '-' ? (char *)NULL :
274     savqstr(atos(nam, sizeof(nam), cp));
275     buf[0] = '\0';
276     }
277     /* load actual views */
278     do
279     if (isview(buf)) {
280     vwl[nvv].v = (VIEW *)bmalloc(sizeof(VIEW));
281     copystruct(vwl[nvv].v, &stdview);
282     sscanview(vwl[nvv].v, buf);
283     if ((cp = setview(vwl[nvv++].v)) != NULL) {
284     fprintf(stderr, "%s: bad view %d - %s\n",
285     progname, nvv, cp);
286     quit(1);
287     }
288     }
289     while (fgets(buf, sizeof(buf), fp) != NULL);
290     if (nvv != nvn)
291     error(INTERNAL, "view miscount in runrad");
292     pclose(fp);
293     /* open options file */
294     if ((fp = fopen(optfile, "r")) == NULL)
295     error(SYSTEM, "cannot open options file");
296 gwlarson 3.4 /* get relevant options */
297 gwlarson 3.1 while (fgets(buf, sizeof(buf), fp) != NULL)
298 gwlarson 3.4 if (!strncmp(buf, "-av ", 4))
299 gwlarson 3.1 setcolor(ambval, atof(buf+4),
300     atof(sskip2(buf+4,1)),
301     atof(sskip2(buf+4,2)));
302 gwlarson 3.4 else if (backvis && !strncmp(buf, "-bv", 3) &&
303     (!buf[3] || strchr(" 0-FfNn", buf[3]) != NULL))
304     backvis = 0;
305 gwlarson 3.1 fclose(fp);
306     unlink(optfile); /* delete options file */
307     }
308    
309    
310     int
311     findvw(nm) /* find named view */
312     register char *nm;
313     {
314     register int n;
315    
316     if (*nm >= '1' & *nm <= '9' &&
317     (n = atoi(nm)-1) <= MAXVIEW && vwl[n].v != NULL)
318     return(n);
319     for (n = 0; vwl[n].v != NULL; n++)
320     if (vwl[n].nam != NULL && !strcmp(nm, vwl[n].nam))
321     return(n);
322     return(-1);
323     }
324    
325    
326     int
327     varmatch(s, vn) /* match line to variable */
328     register char *s, *vn;
329     {
330     register int c;
331    
332     for ( ; *vn && *s == *vn; s++, vn++)
333     ;
334     while (isspace(*s))
335     s++;
336     if (*s == '=')
337     return(*vn);
338     while (!(c = toupper(*s++) - toupper(*vn)) && *vn++)
339     ;
340     return(c);
341     }
342    
343    
344     char *
345     scan4var(buf, buflen, vname, fp) /* scan for variable from fp */
346     char *buf;
347     int buflen;
348     char *vname;
349     FILE *fp;
350     {
351     int cval;
352     register char *cp;
353     /* search out matching line */
354     while ((cval = varmatch(buf, vname))) {
355     if (cval > 0) /* gone too far? */
356     return(NULL);
357     buf[0] = '\0'; /* else get next line */
358     if (fgetline(buf, buflen, fp) == NULL)
359     return(NULL);
360     }
361     /* skip variable name and '=' */
362     for (cp = buf; *cp++ != '='; )
363     ;
364     while (isspace(*cp)) cp++;
365     return(cp);
366     }
367    
368    
369     dev_open(id) /* initialize GLX driver */
370     char *id;
371     {
372     static int atlBest[] = {GLX_RGBA, GLX_RED_SIZE,4,
373     GLX_GREEN_SIZE,4, GLX_BLUE_SIZE,4,
374     GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,15, None};
375     XSetWindowAttributes ourwinattr;
376     XWMHints ourxwmhints;
377     XSizeHints oursizhints;
378     /* open display server */
379     ourdisplay = XOpenDisplay(NULL);
380     if (ourdisplay == NULL)
381     error(USER, "cannot open X-windows; DISPLAY variable set?\n");
382     /* find a usable visual */
383     ourvinf = glXChooseVisual(ourdisplay, ourscreen, atlBest);
384     if (ourvinf == NULL)
385     error(USER, "no suitable visuals available");
386     /* get a context */
387     gctx = glXCreateContext(ourdisplay, ourvinf, NULL, GL_TRUE);
388     /* open window */
389     ourwinattr.background_pixel = ourblack;
390     ourwinattr.border_pixel = ourblack;
391     ourwinattr.event_mask = ourmask;
392     /* this is stupid */
393     ourwinattr.colormap = XCreateColormap(ourdisplay, ourroot,
394     ourvinf->visual, AllocNone);
395     gwind = XCreateWindow(ourdisplay, ourroot, 0, 0,
396     DisplayWidth(ourdisplay,ourscreen)-2*BORWIDTH,
397     DisplayHeight(ourdisplay,ourscreen)-2*BORWIDTH,
398     BORWIDTH, ourvinf->depth, InputOutput, ourvinf->visual,
399     CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &ourwinattr);
400     if (gwind == 0)
401     error(SYSTEM, "cannot create window\n");
402     XStoreName(ourdisplay, gwind, id);
403 gwlarson 3.4 #ifndef NOSTEREO
404     if (stereo) /* check if stereo working */
405     switch (XSGIQueryStereoMode(ourdisplay, gwind)) {
406     case STEREO_TOP:
407     case STEREO_BOTTOM:
408     break;
409     case STEREO_OFF:
410     error(USER,
411     "wrong video mode: run \"/usr/gfx/setmon -n STR_TOP\" first");
412     case X_STEREO_UNSUPPORTED:
413     error(USER, "stereo not supported on this screen");
414     default:
415     error(INTERNAL, "unknown stereo mode");
416     }
417     #endif
418 gwlarson 3.1 /* set window manager hints */
419     ourxwmhints.flags = InputHint|IconPixmapHint;
420     ourxwmhints.input = True;
421     ourxwmhints.icon_pixmap = XCreateBitmapFromData(ourdisplay,
422     gwind, glradicon_bits, glradicon_width, glradicon_height);
423     XSetWMHints(ourdisplay, gwind, &ourxwmhints);
424     oursizhints.min_width = MINWIDTH;
425 gwlarson 3.4 oursizhints.min_height = stereo ? MINHEIGHT/2 : MINHEIGHT;
426 gwlarson 3.1 oursizhints.flags = PMinSize;
427     XSetNormalHints(ourdisplay, gwind, &oursizhints);
428     /* set GLX context */
429     glXMakeCurrent(ourdisplay, gwind, gctx);
430     glEnable(GL_DEPTH_TEST);
431     glDepthFunc(GL_LESS);
432     glShadeModel(GL_SMOOTH);
433     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
434     glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
435     glEnable(GL_LIGHTING);
436     if (backvis)
437     glDisable(GL_CULL_FACE);
438     else {
439     glFrontFace(GL_CCW);
440     glCullFace(GL_BACK);
441     glEnable(GL_CULL_FACE);
442     }
443     glDrawBuffer(GL_BACK);
444     /* figure out sensible view */
445     pwidth = (double)DisplayWidthMM(ourdisplay, ourscreen) /
446     DisplayWidth(ourdisplay, ourscreen);
447     pheight = (double)DisplayHeightMM(ourdisplay, ourscreen) /
448     DisplayHeight(ourdisplay, ourscreen);
449 gwlarson 3.4 if (stereo) { /* set stereo mode */
450     setstereobuf(STEREO_BUFFER_LEFT);
451     pheight *= 2.;
452     }
453 gwlarson 3.1 /* map the window */
454     XMapWindow(ourdisplay, gwind);
455 gwlarson 3.3 do
456     dev_input(0); /* get resize event */
457     while (hres == 0 & vres == 0);
458 gwlarson 3.1 rgl_checkerr("initializing GLX");
459     }
460    
461    
462     dev_close() /* close our display and free resources */
463     {
464     glXMakeCurrent(ourdisplay, None, NULL);
465     glXDestroyContext(ourdisplay, gctx);
466     XDestroyWindow(ourdisplay, gwind);
467     gwind = 0;
468     XCloseDisplay(ourdisplay);
469     ourdisplay = NULL;
470     }
471    
472    
473     int
474     dev_view(nv) /* assign new driver view */
475     register VIEW *nv;
476     {
477     int newhres = hres, newvres = vres;
478     double wa, va;
479     /* check view legality */
480     if (nv->type != VT_PER) {
481     error(COMMAND, "illegal view type");
482     nv->type = VT_PER;
483     }
484     if (nv->horiz > 160. | nv->vert > 160.) {
485     error(COMMAND, "illegal view angle");
486     if (nv->horiz > 160.)
487     nv->horiz = 160.;
488     if (nv->vert > 160.)
489     nv->vert = 160.;
490     }
491     if (hres != 0 & vres != 0) {
492     wa = (vres*pheight)/(hres*pwidth);
493 gwlarson 3.2 va = viewaspect(nv);
494 gwlarson 3.1 if (va > wa+.05) {
495     newvres = (pwidth/pheight)*va*newhres + .5;
496     if (newvres > maxvres) {
497     newvres = maxvres;
498     newhres = (pheight/pwidth)/va*newvres + .5;
499     }
500     } else if (va < wa-.05) {
501     newhres = (pheight/pwidth)/va*newvres + .5;
502     if (newhres > maxhres) {
503     newhres = maxhres;
504     newvres = (pwidth/pheight)*va*newhres + .5;
505     }
506     }
507     if (newhres != hres | newvres != vres) {
508 gwlarson 3.2 in_dev_view++;
509 gwlarson 3.1 XResizeWindow(ourdisplay, gwind, newhres, newvres);
510     do
511     dev_input(0); /* get resize event */
512     while (newhres != hres | newvres != vres);
513 gwlarson 3.2 in_dev_view--;
514 gwlarson 3.1 }
515     }
516     copystruct(&thisview, nv);
517     setglpersp(&thisview);
518     render();
519     return(1);
520     }
521    
522    
523     int
524     dev_input(nsecs) /* get next input event */
525     int nsecs;
526     {
527     #if 0
528     static time_t lasttime = 0;
529     time_t thistime;
530    
531     if (nsecs > 0) {
532     thistime = time(0);
533     nsecs -= (long)(thistime - lasttime);
534     lasttime = thistime;
535     }
536     if (nsecs > 0)
537     alarm(nsecs);
538     #endif
539     XNextEvent(ourdisplay, levptr(XEvent));
540     switch (levptr(XEvent)->type) {
541     case ConfigureNotify:
542     resizewindow(levptr(XConfigureEvent));
543     break;
544     case UnmapNotify:
545     mapped = 0;
546     break;
547     case MapNotify:
548     mapped = 1;
549     break;
550     case Expose:
551     fixwindow(levptr(XExposeEvent));
552     break;
553     case KeyPress:
554     return(getkey(levptr(XKeyPressedEvent)));
555     case ButtonPress:
556     getmove(levptr(XButtonPressedEvent));
557     break;
558     }
559     return(1);
560     }
561    
562    
563     render() /* render our display list and swap buffers */
564     {
565 gwlarson 3.4 double d;
566    
567 gwlarson 3.1 if (!mapped)
568     return;
569     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
570     glCallList(displist);
571 gwlarson 3.4 if (stereo) { /* do right eye for stereo */
572     setstereobuf(STEREO_BUFFER_RIGHT);
573     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
574     glMatrixMode(GL_MODELVIEW);
575     glPushMatrix();
576     d = -eyedist / sqrt(thisview.hn2);
577     glTranslated(d*thisview.hvec[0], d*thisview.hvec[1],
578     d*thisview.hvec[2]);
579     glCallList(displist);
580     glMatrixMode(GL_MODELVIEW);
581     glPopMatrix();
582     setstereobuf(STEREO_BUFFER_LEFT);
583     }
584 gwlarson 3.1 glXSwapBuffers(ourdisplay, gwind); /* calls glFlush() */
585     rgl_checkerr("rendering display list");
586     }
587    
588    
589     moveview(dx, dy, mov, orb) /* move our view */
590     int dx, dy, mov, orb;
591     {
592     VIEW nv;
593     FVECT odir, v1, wp;
594     double d;
595     register int li;
596     /* start with old view */
597     copystruct(&nv, &thisview);
598     /* change view direction */
599     if ((d = viewray(v1, odir, &thisview,
600     (dx+.5)/hres, (dy+.5)/vres)) < -FTINY)
601     return(0); /* outside view */
602     if (mov | orb) {
603     if (!getintersect(wp, v1, odir, d))
604     return(0);
605     VSUM(odir, wp, nv.vp, -1.);
606     } else
607     VCOPY(nv.vdir, odir);
608     if (orb && mov) { /* orbit left/right */
609     spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov);
610     VSUM(nv.vp, wp, odir, -1.);
611     spinvector(nv.vdir, nv.vdir, nv.vup, d);
612     } else if (orb) { /* orbit up/down */
613     fcross(v1, odir, nv.vup);
614     if (normalize(v1) == 0.)
615     return(0);
616     spinvector(odir, odir, v1, d=MOVDEG*PI/180.*orb);
617     VSUM(nv.vp, wp, odir, -1.);
618     spinvector(nv.vdir, nv.vdir, v1, d);
619     } else if (mov) { /* move forward/backward */
620     d = MOVPCT/100. * mov;
621     VSUM(nv.vp, nv.vp, odir, d);
622     }
623     if (!mov ^ !orb && headlocked) { /* restore head height */
624     VSUM(v1, thisview.vp, nv.vp, -1.);
625     d = DOT(v1, thisview.vup);
626     VSUM(nv.vp, nv.vp, thisview.vup, d);
627     }
628     if (setview(&nv) != NULL)
629     return(0); /* illegal view */
630     dev_view(&nv);
631     return(1);
632     }
633    
634    
635     getmove(ebut) /* get view change */
636     XButtonPressedEvent *ebut;
637     {
638     int movdir = MOVDIR(ebut->button);
639     int movorb = MOVORB(ebut->state);
640     int moved = 0;
641     Window rootw, childw;
642     int rootx, rooty, wx, wy;
643     unsigned int statemask;
644    
645 gwlarson 3.3 copylastv( movorb ? (movdir ? "left/right" : "up/down") :
646     (movdir ? "fore/back" : "rotate") );
647 gwlarson 3.1 XNoOp(ourdisplay);
648    
649     while (!XCheckMaskEvent(ourdisplay,
650     ButtonReleaseMask, levptr(XEvent))) {
651    
652     if (!XQueryPointer(ourdisplay, gwind, &rootw, &childw,
653     &rootx, &rooty, &wx, &wy, &statemask))
654     break; /* on another screen */
655    
656     if (!moveview(wx, vres-1-wy, movdir, movorb)) {
657     sleep(1);
658     continue;
659     } else
660     moved++;
661     }
662     if (!moved) { /* do final motion */
663     movdir = MOVDIR(levptr(XButtonReleasedEvent)->button);
664     wx = levptr(XButtonReleasedEvent)->x;
665     wy = levptr(XButtonReleasedEvent)->y;
666     moveview(wx, vres-1-wy, movdir, movorb);
667     }
668     }
669    
670    
671     getintersect(wp, org, dir, md) /* intersect ray with scene geometry */
672     FVECT wp; /* returned world intersection point */
673     FVECT org, dir;
674     double md;
675     {
676     float fbuf[6];
677     /* check to see if rtrace is running */
678     if (rtpd[2] <= 0)
679     return(0);
680     /* assign origin */
681     fbuf[0] = org[0]; fbuf[1] = org[1]; fbuf[2] = org[2];
682     /* compute clipping distance */
683     if (md <= FTINY) md = FHUGE;
684     fbuf[3] = dir[0]*md; fbuf[4] = dir[1]*md; fbuf[5] = dir[2]*md;
685     /* trace that ray */
686     if (process(rtpd, fbuf, fbuf, 4*sizeof(float), 6*sizeof(float)) !=
687     4*sizeof(float))
688     error(INTERNAL, "error getting data back from rtrace process");
689     if (fbuf[3] >= .99*FHUGE)
690     return(0); /* missed local objects */
691     wp[0] = fbuf[0]; wp[1] = fbuf[1]; wp[2] = fbuf[2];
692     return(1); /* else return world intersection */
693     }
694    
695    
696     setglpersp(vp) /* set perspective view in GL */
697     register VIEW *vp;
698     {
699     double d, xmin, xmax, ymin, ymax, zmin, zmax;
700    
701 gwlarson 3.2 zmin = 0.1;
702     zmax = 1000.;
703 gwlarson 3.1 if (thisview.vfore > FTINY)
704     zmin = thisview.vfore;
705     if (thisview.vaft > FTINY)
706     zmax = thisview.vaft;
707     xmax = zmin * tan(PI/180./2. * thisview.horiz);
708     xmin = -xmax;
709     d = thisview.hoff * (xmax - xmin);
710     xmin += d; xmax += d;
711     ymax = zmin * tan(PI/180./2. * thisview.vert);
712     ymin = -ymax;
713     d = thisview.voff * (ymax - ymin);
714     ymin += d; ymax += d;
715     /* set view matrix */
716     glMatrixMode(GL_PROJECTION);
717     glLoadIdentity();
718     glFrustum(xmin, xmax, ymin, ymax, zmin, zmax);
719     gluLookAt(thisview.vp[0], thisview.vp[1], thisview.vp[2],
720     thisview.vp[0] + thisview.vdir[0],
721     thisview.vp[1] + thisview.vdir[1],
722     thisview.vp[2] + thisview.vdir[2],
723     thisview.vup[0], thisview.vup[1], thisview.vup[2]);
724     rgl_checkerr("setting perspective view");
725     }
726    
727    
728     int
729     getkey(ekey) /* get input key */
730     register XKeyPressedEvent *ekey;
731     {
732     int n;
733     char buf[8];
734    
735     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
736     if (n != 1)
737     return(1);
738     switch (buf[0]) {
739     case 'h': /* turn on height motion lock */
740     headlocked = 1;
741     break;
742     case 'H': /* turn off height motion lock */
743     headlocked = 0;
744     break;
745     case 'l': /* retrieve last (premouse) view */
746 gwlarson 3.2 if (lastview.type) {
747 gwlarson 3.1 VIEW vtmp;
748     copystruct(&vtmp, &thisview);
749     dev_view(&lastview);
750     copystruct(&lastview, &vtmp);
751     } else
752     XBell(ourdisplay, 0);
753     break;
754     case 'n': /* move to next standard view */
755     gotoview(currentview+1);
756     break;
757     case 'p': /* move to last standard view */
758     gotoview(currentview-1);
759     break;
760     case '+': /* zoom in */
761     zoomview(100+ZOOMPCT, ekey->x, vres-1-ekey->y);
762     break;
763     case '-': /* zoom out */
764     zoomview(100-ZOOMPCT, ekey->x, vres-1-ekey->y);
765     break;
766     case 'v': /* spit current view to stdout */
767     fputs(VIEWSTR, stdout);
768     fprintview(&thisview, stdout);
769     fputc('\n', stdout);
770     break;
771     case 'V': /* append view to rad file */
772     appendview(NULL, &thisview);
773     break;
774     case 'q': /* quit the program */
775     return(0);
776     default:
777     XBell(ourdisplay, 0);
778     break;
779     }
780     return(1);
781     }
782    
783    
784     zoomview(pct, dx, dy) /* zoom in or out around (dx,dy) */
785     int pct;
786     int dx, dy;
787     {
788     double h, v;
789     FVECT direc;
790    
791     if (pct == 100 | pct <= 0)
792     return;
793     copylastv("zooming");
794     h = (dx+.5)/hres - 0.5;
795     v = (dy+.5)/vres - 0.5;
796     h *= (1. - 100./pct);
797     v *= (1. - 100./pct);
798     thisview.vdir[0] += h*thisview.hvec[0] + v*thisview.vvec[0];
799     thisview.vdir[1] += h*thisview.hvec[1] + v*thisview.vvec[1];
800     thisview.vdir[2] += h*thisview.hvec[2] + v*thisview.vvec[2];
801     thisview.horiz = 2.*180./PI * atan( 100./pct *
802     tan(PI/180./2.*thisview.horiz) );
803     thisview.vert = 2.*180./PI * atan( 100./pct *
804     tan(PI/180./2.*thisview.vert) );
805     setview(&thisview);
806     dev_view(&thisview);
807     }
808    
809    
810     gotoview(vwnum) /* go to specified view number */
811     int vwnum;
812     {
813     if (vwnum < 0)
814     for (vwnum = currentview; vwl[vwnum+1].v != NULL; vwnum++)
815     ;
816     else if (vwnum >= MAXVIEW || vwl[vwnum].v == NULL)
817     vwnum = 0;
818     if (vwnum == currentview)
819     return;
820 gwlarson 3.4 copylastv("standard view");
821 gwlarson 3.1 dev_view(vwl[currentview=vwnum].v);
822     }
823    
824    
825     appendview(nm, vp) /* append standard view */
826     char *nm;
827     VIEW *vp;
828     {
829     FILE *fp;
830     /* check if already in there */
831     if (!bcmp(&thisview, vwl[currentview].v, sizeof(VIEW))) {
832     error(COMMAND, "view already in standard list");
833     return;
834     }
835     /* append to file */
836     if ((fp = fopen(radfile, "a")) == NULL) {
837     error(COMMAND, "cannot append rad input file");
838     return;
839     }
840     fputs("view=", fp);
841     if (nm != NULL) {
842     fputc(' ', fp); fputs(nm, fp);
843     }
844     fprintview(vp, fp); fputc('\n', fp);
845     fclose(fp);
846     /* append to our list */
847     while (vwl[currentview].v != NULL)
848     currentview++;
849     if (currentview >= MAXVIEW)
850     error(INTERNAL, "too many views in appendview");
851     vwl[currentview].v = (VIEW *)bmalloc(sizeof(VIEW));
852     copystruct(vwl[currentview].v, &thisview);
853     if (nm != NULL)
854     vwl[currentview].nam = savqstr(nm);
855     }
856    
857    
858     copylastv(cause) /* copy last view position */
859     char *cause;
860     {
861 gwlarson 3.2 static char *lastvc;
862    
863 gwlarson 3.1 if (cause == lastvc)
864     return; /* only record one view per cause */
865     lastvc = cause;
866     copystruct(&lastview, &thisview);
867     }
868    
869    
870     fixwindow(eexp) /* repair damage to window */
871     register XExposeEvent *eexp;
872     {
873     if (hres == 0 | vres == 0) { /* first exposure */
874     resizewindow((XConfigureEvent *)eexp);
875     return;
876     }
877     if (eexp->count) /* wait for final exposure */
878     return;
879     /* rerender everything */
880     render();
881     }
882    
883    
884     resizewindow(ersz) /* resize window */
885     register XConfigureEvent *ersz;
886     {
887     static char resizing[] = "resizing window";
888     double wa, va;
889    
890     glViewport(0, 0, hres=ersz->width, vres=ersz->height);
891     if (hres > maxhres) maxhres = hres;
892     if (vres > maxvres) maxvres = vres;
893 gwlarson 3.2 if (in_dev_view)
894     return;
895 gwlarson 3.1 wa = (vres*pheight)/(hres*pwidth);
896     va = viewaspect(&thisview);
897     if (va > wa+.05) {
898     copylastv(resizing);
899     thisview.vert = 2.*180./PI *
900     atan( tan(PI/180./2. * thisview.horiz) * wa );
901     } else if (va < wa-.05) {
902     copylastv(resizing);
903     thisview.horiz = 2.*180./PI *
904     atan( tan(PI/180./2. * thisview.vert) / wa );
905     } else
906     return;
907     setview(&thisview);
908     dev_view(&thisview);
909     }