ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/glrad.c
Revision: 3.14
Committed: Mon May 19 16:32:19 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.13: +1 -6 lines
Log Message:
Eliminated unnecessary and problematic external function declarations

File Contents

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