ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdisp.c
Revision: 3.53
Committed: Tue Aug 16 18:09:53 2011 UTC (12 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad5R0, rad4R2, rad4R1, rad4R2P1
Changes since 3.52: +2 -2 lines
Log Message:
Minor fixes

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhdisp.c,v 3.52 2008/03/11 02:21:47 greg Exp $";
3 #endif
4 /*
5 * Holodeck display process.
6 */
7
8 #include <string.h>
9 #include <ctype.h>
10
11 #include "rterror.h"
12 #include "rholo.h"
13 #include "rhdisp.h"
14 #include "rhdriver.h"
15 #include "selcall.h"
16
17 #ifndef VIEWHISTLEN
18 #define VIEWHISTLEN 4 /* number of remembered views */
19 #endif
20
21 #ifndef FSIZDEF
22 #define FSIZDEF 0.125 /* default focus frame size */
23 #endif
24
25 #if defined(freebsd)
26 #define fbufcnt(f) ((f)->_r)
27 #elif defined(__GNUC__)
28 #define fbufcnt(f) ((f)->_IO_read_end - (f)->_IO_read_ptr)
29 #else
30 #define fbufcnt(f) ((f)->_cnt)
31 #endif
32
33 HOLO *hdlist[HDMAX+1]; /* global holodeck list */
34
35 char *hdgfn[HDMAX]; /* holodeck section geometry list */
36 char *hdpfn[HDMAX]; /* section portal list */
37
38 char cmdlist[DC_NCMDS][8] = DC_INIT;
39
40 int imm_mode = 0; /* bundles are being delivered immediately */
41
42 int do_outside = 0; /* render from outside sections */
43
44 double eyesepdist = 1; /* eye separation distance */
45
46 char *progname; /* global argv[0] */
47
48 FILE *sstdin, *sstdout; /* server's standard input and output */
49
50 #ifdef DEBUG
51 extern time_t time();
52 static time_t tmodesw;
53 static time_t timm, tadd;
54 static long nimmrays, naddrays;
55 #endif
56
57 #define RDY_SRV 01
58 #define RDY_DEV 02
59 #define RDY_SIN 04
60
61 static int disp_wait(void);
62 static void add_holo(HDGRID *hdg, char *gfn, char *pfn);
63 static void disp_bundle(PACKHEAD *p);
64 static void new_view(register VIEW *v);
65 static void set_focus(char *args);
66 static int usr_input(void);
67 static void printview(void);
68
69
70 int
71 main(
72 int argc,
73 char *argv[]
74 )
75 {
76 int rdy, inp, res = 0, pause = 0;
77
78 progname = argv[0];
79 if (argc < 3)
80 error(USER, "bad command line arguments");
81 /* open our device */
82 dev_open(argv[1]);
83 /* open server process i/o */
84 sstdout = fdopen(atoi(argv[2]), "w");
85 if (argc < 4 || (inp = atoi(argv[3])) < 0)
86 sstdin = NULL;
87 else
88 sstdin = fdopen(inp, "r");
89 /* set command error vector */
90 erract[COMMAND].pf = eputs;
91 #ifdef DEBUG
92 tmodesw = time(NULL);
93 #endif
94 /* enter main loop */
95 do {
96 rdy = disp_wait();
97 if (rdy & RDY_SRV) { /* process server result */
98 res = serv_result();
99 if (pause && res != DS_SHUTDOWN) {
100 serv_request(DR_ATTEN, 0, NULL);
101 while ((res = serv_result()) != DS_ACKNOW &&
102 res != DS_SHUTDOWN)
103 ;
104 }
105 }
106 if (rdy & RDY_DEV) { /* user input from driver */
107 inp = dev_input();
108 if (inp & DFL(DC_SETVIEW))
109 new_view(&odev.v);
110 else if (inp & DFL(DC_LASTVIEW))
111 new_view(NULL);
112 if (inp & DFL(DC_REDRAW))
113 imm_mode = beam_sync(1) > 0;
114 if (inp & DFL(DC_GETVIEW))
115 printview();
116 if (inp & DFL(DC_FOCUS))
117 set_focus(odev_args);
118 if (inp & DFL(DC_KILL)) {
119 serv_request(DR_KILL, 0, NULL);
120 pause = 0;
121 }
122 if (inp & DFL(DC_CLOBBER))
123 serv_request(DR_CLOBBER, 0, NULL);
124 if (inp & DFL(DC_RESTART)) {
125 serv_request(DR_RESTART, 0, NULL);
126 pause = 0;
127 }
128 if (inp & DFL(DC_RESUME)) {
129 serv_request(DR_NOOP, 0, NULL);
130 pause = 0;
131 }
132 if (inp & DFL(DC_PAUSE))
133 pause = 1;
134 if (inp & DFL(DC_QUIT))
135 serv_request(DR_SHUTDOWN, 0, NULL);
136 }
137 if (rdy & RDY_SIN && !imm_mode) /* user input from sstdin */
138 switch (usr_input()) {
139 case DC_PAUSE:
140 pause = 1;
141 break;
142 case DC_RESUME:
143 serv_request(DR_NOOP, 0, NULL);
144 /* fall through */
145 case DC_KILL:
146 case DC_RESTART:
147 pause = 0;
148 break;
149 }
150 } while (res != DS_SHUTDOWN);
151 #ifdef DEBUG
152 if (timm && nimmrays)
153 fprintf(stderr,
154 "%s: %.1f rays recalled/second (%ld rays total)\n",
155 progname, (double)nimmrays/timm, nimmrays);
156 if (tadd && naddrays)
157 fprintf(stderr,
158 "%s: %.1f rays calculated/second (%ld rays total)\n",
159 progname, (double)naddrays/tadd, naddrays);
160 #endif
161 /* all done */
162 quit(0);
163 return 0; /* pro forma return */
164 }
165
166
167 static int
168 disp_wait(void) /* wait for more input */
169 {
170 fd_set readset, errset;
171 int flgs;
172 int n;
173 /* see if we can avoid select call */
174 if (hdlist[0] == NULL)
175 return(RDY_SRV); /* initialize first */
176 flgs = 0; /* flag what's ready already */
177 if (imm_mode || fbufcnt(stdin) > 0)
178 flgs |= RDY_SRV;
179 if (sstdin != NULL && fbufcnt(sstdin) > 0)
180 flgs |= RDY_SIN;
181 if (odev.inpready)
182 flgs |= RDY_DEV;
183 if (flgs) /* got something? */
184 return(flgs);
185 if (dev_flush()) /* else flush output & check keyboard+mouse */
186 return(RDY_DEV);
187 /* if nothing, we need to call select */
188 FD_ZERO(&readset); FD_ZERO(&errset);
189 FD_SET(0, &readset);
190 FD_SET(0, &errset);
191 FD_SET(odev.ifd, &readset);
192 FD_SET(odev.ifd, &errset);
193 n = odev.ifd+1;
194 if (sstdin != NULL) {
195 FD_SET(fileno(sstdin), &readset);
196 FD_SET(fileno(sstdin), &errset);
197 if (fileno(sstdin) >= n)
198 n = fileno(sstdin) + 1;
199 }
200 n = select(n, &readset, NULL, &errset, NULL);
201 if (n < 0) {
202 if (errno == EINTR)
203 return(0);
204 error(SYSTEM, "select call failure in disp_wait");
205 }
206 if (FD_ISSET(0, &readset) || FD_ISSET(0, &errset))
207 flgs |= RDY_SRV;
208 if (FD_ISSET(odev.ifd, &readset) || FD_ISSET(odev.ifd, &errset))
209 flgs |= RDY_DEV;
210 if (sstdin != NULL && (FD_ISSET(fileno(sstdin), &readset) ||
211 FD_ISSET(fileno(sstdin), &errset)))
212 flgs |= RDY_SIN;
213 return(flgs);
214 }
215
216
217 static void
218 add_holo( /* register a new holodeck section */
219 HDGRID *hdg,
220 char *gfn,
221 char *pfn
222 )
223 {
224 VIEW nv;
225 double d;
226 register int hd;
227
228 for (hd = 0; hd < HDMAX && hdlist[hd] != NULL; hd++)
229 ;
230 if (hd >= HDMAX)
231 error(INTERNAL, "too many holodeck sections in add_holo");
232 hdlist[hd] = (HOLO *)malloc(sizeof(HOLO));
233 if (hdlist[hd] == NULL)
234 error(SYSTEM, "out of memory in add_holo");
235 memcpy((void *)hdlist[hd], (void *)hdg, sizeof(HDGRID));
236 hdcompgrid(hdlist[hd]);
237 hdgfn[hd] = savestr(gfn);
238 hdpfn[hd] = pfn && *pfn ? savestr(pfn) : (char *)NULL;
239 if (hd)
240 return;
241 /* set initial viewpoint */
242 nv = odev.v;
243 VSUM(nv.vp, hdlist[0]->orig, hdlist[0]->xv[0], 0.5);
244 VSUM(nv.vp, nv.vp, hdlist[0]->xv[1], 0.5);
245 VSUM(nv.vp, nv.vp, hdlist[0]->xv[2], 0.5);
246 fcross(nv.vdir, hdlist[0]->xv[1], hdlist[0]->xv[2]);
247 VCOPY(nv.vup, hdlist[0]->xv[2]);
248 if (do_outside) {
249 normalize(nv.vdir);
250 d = VLEN(hdlist[0]->xv[1]);
251 d += VLEN(hdlist[0]->xv[2]);
252 VSUM(nv.vp, nv.vp, nv.vdir, -d);
253 }
254 new_view(&nv);
255 }
256
257
258 static void
259 disp_bundle( /* display a ray bundle */
260 register PACKHEAD *p
261 )
262 {
263 GCOORD gc[2];
264 FVECT ro, rd, wp;
265 double d;
266 register int i;
267 /* get beam coordinates */
268 if ((p->hd < 0) | (p->hd >= HDMAX) || hdlist[p->hd] == NULL)
269 error(INTERNAL, "bad holodeck number in disp_bundle");
270 if (!hdbcoord(gc, hdlist[p->hd], p->bi))
271 error(INTERNAL, "bad beam index in disp_bundle");
272 /* display each ray */
273 for (i = p->nr; i--; ) {
274 hdray(ro, rd, hdlist[p->hd], gc, packra(p)[i].r);
275 d = hddepth(hdlist[p->hd], packra(p)[i].d);
276 if (d < .99*FHUGE) {
277 VSUM(wp, ro, rd, d); /* might be behind viewpoint */
278 dev_value(packra(p)[i].v, rd, wp);
279 } else
280 dev_value(packra(p)[i].v, rd, NULL);
281 }
282 #ifdef DEBUG
283 if (imm_mode) nimmrays += p->nr;
284 else naddrays += p->nr;
285 #endif
286 }
287
288
289 static void
290 new_view( /* change view parameters */
291 register VIEW *v
292 )
293 {
294 static VIEW viewhist[VIEWHISTLEN];
295 static unsigned nhist;
296 VIEW *dv;
297 int i, res[2];
298 int16 *slist;
299 char *err;
300 /* restore previous view? */
301 if (v == NULL) {
302 if (nhist > 1) /* get one before last setting */
303 nhist--;
304 else /* else go to end of list */
305 while (nhist < VIEWHISTLEN && viewhist[nhist].type)
306 nhist++;
307 v = viewhist + ((nhist-1)%VIEWHISTLEN);
308 } else
309 again:
310 if ((err = setview(v)) != NULL) {
311 error(COMMAND, err);
312 return;
313 }
314 if (!dev_view(v)) /* notify display driver */
315 goto again;
316 if (v->type == VT_PAR) {
317 error(COMMAND, "cannot handle parallel views");
318 return;
319 }
320 beam_init(odev.firstuse); /* compute new beam set */
321 for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++) {
322 if ((slist = beam_view(dv, res[0], res[1])) == NULL) {
323 if (!nhist) {
324 error(COMMAND, "invalid starting view");
325 return;
326 }
327 *v = *(viewhist + ((nhist-1)%VIEWHISTLEN));
328 goto again; /* XXX overloading dev_section()? */
329 }
330 DCHECK(*slist < 0, WARNING, "no visible sections in new_view");
331 for ( ; *slist >= 0; slist++)
332 dev_section(hdgfn[*slist], hdpfn[*slist]);
333 }
334 dev_section(NULL,NULL); /* end section list */
335 dev_flush(); /* update display */
336 /* update server */
337 imm_mode = beam_sync(odev.firstuse) > 0;
338 /* record new view */
339 if (v < viewhist || v >= viewhist+VIEWHISTLEN) {
340 *(viewhist + (nhist%VIEWHISTLEN)) = *v;
341 nhist++;
342 }
343 }
344
345
346 static void
347 set_focus( /* set focus frame */
348 char *args
349 )
350 {
351 double hcent, vcent, hsiz, vsiz;
352 VIEW *dv, vwfocus;
353 int i, res[2];
354
355 i = sscanf(args, "%lf %lf %lf %lf", &hcent, &vcent, &hsiz, &vsiz);
356 if (i < 2 || hcent < 0 || hcent > 1 || vcent < 0 || vcent > 1) {
357 beam_init(0); /* restore view */
358 for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
359 beam_view(dv, res[0], res[1]);
360 beam_sync(0); /* update server */
361 return;
362 }
363 if (i < 4 || hsiz <= hcent || hsiz > 1 || vsiz <= vcent || vsiz > 1)
364 hsiz = vsiz = FSIZDEF; /* gave center only */
365 else {
366 hsiz -= hcent; hcent += 0.5*hsiz; /* gave min and max */
367 vsiz -= vcent; vcent += 0.5*vsiz;
368 }
369 beam_init(0); /* add basic views */
370 for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
371 beam_view(dv, res[0]>>4, res[1]>>4);
372 vwfocus = odev.v; /* add focus view */
373 switch (odev.v.type) {
374 case VT_PER:
375 vwfocus.horiz = 2.*180./PI*atan(
376 hsiz * tan(PI/180./2.*odev.v.horiz) );
377 vwfocus.vert = 2.*180./PI*atan(
378 vsiz * tan(PI/180./2.*odev.v.vert) );
379 break;
380 case VT_PAR:
381 case VT_ANG:
382 vwfocus.horiz = hsiz * odev.v.horiz;
383 vwfocus.vert = vsiz * odev.v.vert;
384 break;
385 case VT_PLS:
386 vwfocus.horiz = hsiz * sin((PI/180./2.)*odev.v.horiz) /
387 (1.0 + cos((PI/180./2.)*odev.v.horiz));
388 vwfocus.horiz *= vwfocus.horiz;
389 vwfocus.horiz = (2.*180./PI)*acos((1. - vwfocus.horiz) /
390 (1. + vwfocus.horiz));
391 vwfocus.vert = vsiz * sin((PI/180./2.)*odev.v.vert) /
392 (1.0 + cos((PI/180./2.)*odev.v.vert));
393 vwfocus.vert *= vwfocus.vert;
394 vwfocus.vert = (2.*180./PI)*acos((1. - vwfocus.vert) /
395 (1. + vwfocus.vert));
396 break;
397 case VT_HEM:
398 vwfocus.horiz = 2.*180./PI*asin(
399 hsiz * sin(PI/180./2.*odev.v.horiz) );
400 vwfocus.vert = 2.*180./PI*asin(
401 vsiz * sin(PI/180./2.*odev.v.vert) );
402 break;
403 case VT_CYL:
404 vwfocus.horiz = hsiz * odev.v.horiz;
405 vwfocus.vert = 2.*180./PI*atan(
406 vsiz * tan(PI/180./2.*odev.v.vert) );
407 break;
408 default:
409 error(INTERNAL, "bad view type in set_focus");
410 }
411 vwfocus.hoff = (odev.v.hoff + hcent - 0.5)/hsiz;
412 vwfocus.voff = (odev.v.voff + vcent - 0.5)/vsiz;
413 setview(&vwfocus);
414 beam_view(&vwfocus, (int)(3*odev.hres*hsiz)+100,
415 (int)(3*odev.vres*vsiz)+100);
416 beam_sync(0); /* update server */
417 }
418
419
420 static int
421 usr_input(void) /* get user input and process it */
422 {
423 VIEW vparams;
424 char cmd[256];
425 register char *args;
426 register int i;
427
428 if (fgets(cmd, sizeof(cmd), sstdin) == NULL) {
429 fclose(sstdin);
430 sstdin = NULL;
431 return(-1);
432 }
433 if (*cmd == '\n')
434 return(DC_RESUME);
435 for (args = cmd; *args && !isspace(*args); args++)
436 ;
437 while (isspace(*args))
438 *args++ = '\0';
439 if (*args && args[i=strlen(args)-1] == '\n')
440 args[i] = '\0';
441 for (i = 0; i < DC_NCMDS; i++)
442 if (!strcmp(cmd, cmdlist[i]))
443 break;
444 if (i >= DC_NCMDS) {
445 dev_auxcom(cmd, args);
446 return(-1);
447 }
448 switch (i) {
449 case DC_SETVIEW: /* set the view */
450 vparams = odev.v;
451 if (!sscanview(&vparams, args))
452 error(COMMAND, "missing view options");
453 else
454 new_view(&vparams);
455 break;
456 case DC_GETVIEW: /* print the current view */
457 printview();
458 break;
459 case DC_LASTVIEW: /* restore previous view */
460 new_view(NULL);
461 break;
462 case DC_FOCUS: /* set focus frame */
463 set_focus(args);
464 break;
465 case DC_PAUSE: /* pause the current calculation */
466 case DC_RESUME: /* resume the calculation */
467 /* handled in main() */
468 break;
469 case DC_REDRAW: /* redraw from server */
470 imm_mode = beam_sync(1) > 0;
471 dev_clear();
472 break;
473 case DC_KILL: /* kill rtrace process(es) */
474 serv_request(DR_KILL, 0, NULL);
475 break;
476 case DC_CLOBBER: /* clobber holodeck */
477 serv_request(DR_CLOBBER, 0, NULL);
478 break;
479 case DC_RESTART: /* restart rtrace */
480 serv_request(DR_RESTART, 0, NULL);
481 break;
482 case DC_QUIT: /* quit request */
483 serv_request(DR_SHUTDOWN, 0, NULL);
484 break;
485 default:
486 error(CONSISTENCY, "bad command id in usr_input");
487 }
488 return(i);
489 }
490
491
492 static void
493 printview(void) /* print our current view to server stdout */
494 {
495 fputs(VIEWSTR, sstdout);
496 fprintview(&odev.v, sstdout);
497 fputc('\n', sstdout);
498 fflush(sstdout);
499 }
500
501
502 extern int
503 serv_result(void) /* get next server result and process it */
504 {
505 static char *buf = NULL;
506 static int bufsiz = 0;
507 MSGHEAD msg;
508 /* read message header */
509 if (fread((char *)&msg, sizeof(MSGHEAD), 1, stdin) != 1)
510 goto readerr;
511 if (msg.nbytes > 0) { /* get the message body */
512 if (msg.nbytes > bufsiz) {
513 if (buf == NULL)
514 buf = (char *)malloc(bufsiz=msg.nbytes);
515 else
516 buf = (char *)realloc((void *)buf,
517 bufsiz=msg.nbytes);
518 if (buf == NULL)
519 error(SYSTEM, "out of memory in serv_result");
520 }
521 if (fread(buf, 1, msg.nbytes, stdin) != msg.nbytes)
522 goto readerr;
523 }
524 switch (msg.type) { /* process results */
525 case DS_BUNDLE:
526 if (msg.nbytes < sizeof(PACKHEAD) ||
527 msg.nbytes != packsiz(((PACKHEAD *)buf)->nr))
528 error(INTERNAL, "bad display packet from server");
529 disp_bundle((PACKHEAD *)buf);
530 break;
531 case DS_ADDHOLO:
532 if (msg.nbytes < sizeof(HDGRID)+2)
533 error(INTERNAL, "bad holodeck record from server");
534 add_holo((HDGRID *)buf, buf+sizeof(HDGRID),
535 buf+sizeof(HDGRID)+strlen(buf+sizeof(HDGRID))+1);
536 break;
537 case DS_OUTSECT:
538 do_outside = 1;
539 goto noargs;
540 case DS_EYESEP:
541 if (msg.nbytes <= 1 || (eyesepdist = atof(buf)) <= FTINY)
542 error(INTERNAL, "bad eye separation from server");
543 break;
544 case DS_STARTIMM:
545 case DS_ENDIMM:
546 if (!(imm_mode = (msg.type==DS_STARTIMM)))
547 dev_flush();
548 #ifdef DEBUG
549 {
550 time_t tnow = time(NULL);
551 if (msg.type==DS_STARTIMM) tadd += tnow - tmodesw;
552 else timm += tnow - tmodesw;
553 tmodesw = tnow;
554 }
555 #endif
556 goto noargs;
557 case DS_ACKNOW:
558 case DS_SHUTDOWN:
559 goto noargs;
560 default:
561 error(INTERNAL, "unrecognized result from server process");
562 }
563 return(msg.type); /* return message type */
564 noargs:
565 if (msg.nbytes) {
566 sprintf(errmsg, "unexpected body with server message %d",
567 msg.type);
568 error(INTERNAL, errmsg);
569 }
570 return(msg.type);
571 readerr:
572 if (feof(stdin))
573 error(SYSTEM, "server process died");
574 error(SYSTEM, "error reading from server process");
575 return -1;
576 }
577
578
579 extern void
580 serv_request( /* send a request to the server process */
581 int type,
582 int nbytes,
583 char *p
584 )
585 {
586 MSGHEAD msg;
587 int m;
588 /* consistency checks */
589 DCHECK(nbytes < 0 || nbytes > 0 & p == NULL,
590 CONSISTENCY, "bad buffer handed to serv_request");
591 /* get server's attention for big request */
592 if (nbytes >= BIGREQSIZ-sizeof(MSGHEAD)) {
593 serv_request(DR_ATTEN, 0, NULL);
594 while ((m = serv_result()) != DS_ACKNOW)
595 if (m == DS_SHUTDOWN) /* the bugger quit on us */
596 quit(0);
597 }
598 msg.type = type; /* write and flush the message */
599 msg.nbytes = nbytes;
600 fwrite((char *)&msg, sizeof(MSGHEAD), 1, stdout);
601 if (nbytes > 0)
602 fwrite(p, 1, nbytes, stdout);
603 if (fflush(stdout) < 0)
604 error(SYSTEM, "write error in serv_request");
605 }
606
607
608 void
609 eputs( /* put error message to stderr */
610 register char *s
611 )
612 {
613 static int midline = 0;
614
615 if (!*s)
616 return;
617 if (!midline++) { /* prepend line with program name */
618 fputs(progname, stderr);
619 fputs(": ", stderr);
620 }
621 fputs(s, stderr);
622 if (s[strlen(s)-1] == '\n') {
623 fflush(stderr);
624 midline = 0;
625 }
626 }
627
628
629 void
630 quit( /* clean up and exit */
631 int code
632 )
633 {
634 if (code)
635 exit(code);
636 if (odev.v.type)
637 dev_close();
638 exit(0);
639 }