ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdisp.c
Revision: 3.51
Committed: Sun Mar 28 20:33:13 2004 UTC (20 years ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad3R6, rad3R6P1, rad3R8
Changes since 3.50: +2 -2 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhdisp.c,v 3.50 2004/01/01 11:21:55 schorsch 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_HEM:
386 vwfocus.horiz = 2.*180./PI*asin(
387 hsiz * sin(PI/180./2.*odev.v.horiz) );
388 vwfocus.vert = 2.*180./PI*asin(
389 vsiz * sin(PI/180./2.*odev.v.vert) );
390 break;
391 case VT_CYL:
392 vwfocus.horiz = hsiz * odev.v.horiz;
393 vwfocus.vert = 2.*180./PI*atan(
394 vsiz * tan(PI/180./2.*odev.v.vert) );
395 break;
396 default:
397 error(INTERNAL, "bad view type in set_focus");
398 }
399 vwfocus.hoff = (odev.v.hoff + hcent - 0.5)/hsiz;
400 vwfocus.voff = (odev.v.voff + vcent - 0.5)/vsiz;
401 setview(&vwfocus);
402 beam_view(&vwfocus, (int)(3*odev.hres*hsiz)+100,
403 (int)(3*odev.vres*vsiz)+100);
404 beam_sync(0); /* update server */
405 }
406
407
408 static int
409 usr_input(void) /* get user input and process it */
410 {
411 VIEW vparams;
412 char cmd[256];
413 register char *args;
414 register int i;
415
416 if (fgets(cmd, sizeof(cmd), sstdin) == NULL) {
417 fclose(sstdin);
418 sstdin = NULL;
419 return(-1);
420 }
421 if (*cmd == '\n')
422 return(DC_RESUME);
423 for (args = cmd; *args && !isspace(*args); args++)
424 ;
425 while (isspace(*args))
426 *args++ = '\0';
427 if (*args && args[i=strlen(args)-1] == '\n')
428 args[i] = '\0';
429 for (i = 0; i < DC_NCMDS; i++)
430 if (!strcmp(cmd, cmdlist[i]))
431 break;
432 if (i >= DC_NCMDS) {
433 dev_auxcom(cmd, args);
434 return(-1);
435 }
436 switch (i) {
437 case DC_SETVIEW: /* set the view */
438 vparams = odev.v;
439 if (!sscanview(&vparams, args))
440 error(COMMAND, "missing view options");
441 else
442 new_view(&vparams);
443 break;
444 case DC_GETVIEW: /* print the current view */
445 printview();
446 break;
447 case DC_LASTVIEW: /* restore previous view */
448 new_view(NULL);
449 break;
450 case DC_FOCUS: /* set focus frame */
451 set_focus(args);
452 break;
453 case DC_PAUSE: /* pause the current calculation */
454 case DC_RESUME: /* resume the calculation */
455 /* handled in main() */
456 break;
457 case DC_REDRAW: /* redraw from server */
458 imm_mode = beam_sync(1) > 0;
459 dev_clear();
460 break;
461 case DC_KILL: /* kill rtrace process(es) */
462 serv_request(DR_KILL, 0, NULL);
463 break;
464 case DC_CLOBBER: /* clobber holodeck */
465 serv_request(DR_CLOBBER, 0, NULL);
466 break;
467 case DC_RESTART: /* restart rtrace */
468 serv_request(DR_RESTART, 0, NULL);
469 break;
470 case DC_QUIT: /* quit request */
471 serv_request(DR_SHUTDOWN, 0, NULL);
472 break;
473 default:
474 error(CONSISTENCY, "bad command id in usr_input");
475 }
476 return(i);
477 }
478
479
480 static void
481 printview(void) /* print our current view to server stdout */
482 {
483 fputs(VIEWSTR, sstdout);
484 fprintview(&odev.v, sstdout);
485 fputc('\n', sstdout);
486 fflush(sstdout);
487 }
488
489
490 extern int
491 serv_result(void) /* get next server result and process it */
492 {
493 static char *buf = NULL;
494 static int bufsiz = 0;
495 MSGHEAD msg;
496 /* read message header */
497 if (fread((char *)&msg, sizeof(MSGHEAD), 1, stdin) != 1)
498 goto readerr;
499 if (msg.nbytes > 0) { /* get the message body */
500 if (msg.nbytes > bufsiz) {
501 if (buf == NULL)
502 buf = (char *)malloc(bufsiz=msg.nbytes);
503 else
504 buf = (char *)realloc((void *)buf,
505 bufsiz=msg.nbytes);
506 if (buf == NULL)
507 error(SYSTEM, "out of memory in serv_result");
508 }
509 if (fread(buf, 1, msg.nbytes, stdin) != msg.nbytes)
510 goto readerr;
511 }
512 switch (msg.type) { /* process results */
513 case DS_BUNDLE:
514 if (msg.nbytes < sizeof(PACKHEAD) ||
515 msg.nbytes != packsiz(((PACKHEAD *)buf)->nr))
516 error(INTERNAL, "bad display packet from server");
517 disp_bundle((PACKHEAD *)buf);
518 break;
519 case DS_ADDHOLO:
520 if (msg.nbytes < sizeof(HDGRID)+2)
521 error(INTERNAL, "bad holodeck record from server");
522 add_holo((HDGRID *)buf, buf+sizeof(HDGRID),
523 buf+sizeof(HDGRID)+strlen(buf+sizeof(HDGRID))+1);
524 break;
525 case DS_OUTSECT:
526 do_outside = 1;
527 goto noargs;
528 case DS_EYESEP:
529 if (msg.nbytes <= 1 || (eyesepdist = atof(buf)) <= FTINY)
530 error(INTERNAL, "bad eye separation from server");
531 break;
532 case DS_STARTIMM:
533 case DS_ENDIMM:
534 if (!(imm_mode = msg.type==DS_STARTIMM))
535 dev_flush();
536 #ifdef DEBUG
537 {
538 time_t tnow = time(NULL);
539 if (msg.type==DS_STARTIMM) tadd += tnow - tmodesw;
540 else timm += tnow - tmodesw;
541 tmodesw = tnow;
542 }
543 #endif
544 goto noargs;
545 case DS_ACKNOW:
546 case DS_SHUTDOWN:
547 goto noargs;
548 default:
549 error(INTERNAL, "unrecognized result from server process");
550 }
551 return(msg.type); /* return message type */
552 noargs:
553 if (msg.nbytes) {
554 sprintf(errmsg, "unexpected body with server message %d",
555 msg.type);
556 error(INTERNAL, errmsg);
557 }
558 return(msg.type);
559 readerr:
560 if (feof(stdin))
561 error(SYSTEM, "server process died");
562 error(SYSTEM, "error reading from server process");
563 return -1;
564 }
565
566
567 extern void
568 serv_request( /* send a request to the server process */
569 int type,
570 int nbytes,
571 char *p
572 )
573 {
574 MSGHEAD msg;
575 int m;
576 /* consistency checks */
577 DCHECK(nbytes < 0 || nbytes > 0 & p == NULL,
578 CONSISTENCY, "bad buffer handed to serv_request");
579 /* get server's attention for big request */
580 if (nbytes >= BIGREQSIZ-sizeof(MSGHEAD)) {
581 serv_request(DR_ATTEN, 0, NULL);
582 while ((m = serv_result()) != DS_ACKNOW)
583 if (m == DS_SHUTDOWN) /* the bugger quit on us */
584 quit(0);
585 }
586 msg.type = type; /* write and flush the message */
587 msg.nbytes = nbytes;
588 fwrite((char *)&msg, sizeof(MSGHEAD), 1, stdout);
589 if (nbytes > 0)
590 fwrite(p, 1, nbytes, stdout);
591 if (fflush(stdout) < 0)
592 error(SYSTEM, "write error in serv_request");
593 }
594
595
596 void
597 eputs( /* put error message to stderr */
598 register char *s
599 )
600 {
601 static int midline = 0;
602
603 if (!*s)
604 return;
605 if (!midline++) { /* prepend line with program name */
606 fputs(progname, stderr);
607 fputs(": ", stderr);
608 }
609 fputs(s, stderr);
610 if (s[strlen(s)-1] == '\n') {
611 fflush(stderr);
612 midline = 0;
613 }
614 }
615
616
617 void
618 quit( /* clean up and exit */
619 int code
620 )
621 {
622 if (code)
623 exit(code);
624 if (odev.v.type)
625 dev_close();
626 exit(0);
627 }