ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rtcontrib.c
Revision: 1.6
Committed: Sat May 28 22:27:54 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.5: +5 -6 lines
Log Message:
Fixed application of ray weights and coefficients in ambient calculation

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rtcontrib.c,v 1.5 2005/05/26 21:35:35 greg Exp $";
3 #endif
4 /*
5 * Gather rtrace output to compute contributions from particular sources
6 */
7
8 #include "standard.h"
9 #include <ctype.h>
10 #include "platform.h"
11 #include "rtprocess.h"
12 #include "selcall.h"
13 #include "color.h"
14 #include "resolu.h"
15 #include "lookup.h"
16 #include "calcomp.h"
17
18 #define MAXMODLIST 1024 /* maximum modifiers we'll track */
19
20 int treebufsiz = BUFSIZ; /* current tree buffer size */
21
22 typedef double DCOLOR[3]; /* double-precision color */
23
24 /*
25 * The modcont structure is used to accumulate ray contributions
26 * for a particular modifier, which may be subdivided into bins
27 * if binv is non-NULL. If outspec contains a %s in it, this will
28 * be replaced with the modifier name. If outspec contains a %d in it,
29 * this will be used to create one output file per bin, otherwise all bins
30 * will be written to the same file, in order. If the global outfmt
31 * is 'c', then a 4-byte RGBE pixel will be output for each bin value
32 * and the file will conform to a RADIANCE image if xres & yres are set.
33 */
34 typedef struct {
35 const char *outspec; /* output file specification */
36 const char *modname; /* modifier name */
37 EPNODE *binv; /* bin value expression */
38 int nbins; /* number of accumulation bins */
39 DCOLOR cbin[1]; /* contribution bins (extends struct) */
40 } MODCONT; /* modifier contribution */
41
42 static void mcfree(void *p) { epfree((*(MODCONT *)p).binv); free(p); }
43
44 LUTAB modconttab = LU_SINIT(NULL,mcfree); /* modifier lookup table */
45
46 /* close output stream */
47 static void closefile(void *p) { fclose((FILE *)p); }
48
49 LUTAB ofiletab = LU_SINIT(free,closefile); /* output file table */
50
51 FILE *getofile(const char *ospec, const char *mname, int bn);
52
53 /*
54 * The rcont structure is used to manage i/o with a particular
55 * rtrace child process. Input is passed unchanged from stdin,
56 * and output is processed in input order and accumulated according
57 * to the corresponding modifier and bin number.
58 */
59 struct rtproc {
60 struct rtproc *next; /* next in list of processes */
61 SUBPROC pd; /* rtrace pipe descriptors */
62 unsigned long raynum; /* ray number for this tree */
63 int bsiz; /* ray tree buffer length */
64 char *buf; /* ray tree buffer */
65 int nbr; /* number of bytes from rtrace */
66 }; /* rtrace process buffer */
67
68 /* rtrace command and defaults */
69 char *rtargv[256] = { "rtrace", "-dj", ".5", "-dr", "3",
70 "-ab", "1", "-ad", "128", };
71 int rtargc = 9;
72 /* overriding rtrace options */
73 char *myrtopts[] = { "-o~~TmWdp", "-h-", "-x", "1", "-y", "0",
74 "-dt", "0", "-as", "0", "-aa", "0", NULL };
75
76 struct rtproc rt0; /* head of rtrace process list */
77
78 struct rtproc *rt_unproc = NULL; /* unprocessed ray trees */
79
80 char persistfn[] = "pfXXXXXX"; /* persist file name */
81
82 int gargc; /* global argc */
83 char **gargv; /* global argv */
84 #define progname gargv[0]
85
86 char *octree; /* global octree argument */
87
88 int inpfmt = 'a'; /* input format */
89 int outfmt = 'a'; /* output format */
90
91 int header = 1; /* output header? */
92 int xres = 0; /* horiz. output resolution */
93 int yres = 0; /* vert. output resolution */
94
95 long raysleft; /* number of rays left to trace */
96 long waitflush; /* how long until next flush */
97
98 unsigned long lastray = 0; /* last ray number sent */
99 unsigned long lastdone = 0; /* last ray processed */
100
101 int using_stdout = 0; /* are we using stdout? */
102
103 const char *modname[MAXMODLIST]; /* ordered modifier name list */
104 int nmods = 0; /* number of modifiers */
105
106 MODCONT *addmodifier(char *modn, char *outf, char *binv);
107
108 void init(int np);
109 int done_rprocs(struct rtproc *rtp);
110 void trace_contribs(FILE *fp);
111 struct rtproc *wait_rproc(void);
112 struct rtproc *get_rproc(void);
113 void queue_raytree(struct rtproc *rtp);
114 void process_queue(void);
115
116 void putcontrib(const DCOLOR cnt, FILE *fout);
117 void add_contrib(const char *modn);
118 void done_contrib(void);
119
120 /* set input/output format */
121 static void
122 setformat(const char *fmt)
123 {
124 switch (fmt[0]) {
125 case 'a':
126 case 'f':
127 case 'd':
128 inpfmt = fmt[0];
129 break;
130 default:
131 goto fmterr;
132 }
133 switch (fmt[1]) {
134 case '\0':
135 outfmt = inpfmt;
136 return;
137 case 'a':
138 case 'f':
139 case 'd':
140 case 'c':
141 outfmt = fmt[1];
142 break;
143 default:
144 goto fmterr;
145 }
146 if (!fmt[2])
147 return;
148 fmterr:
149 sprintf(errmsg, "Illegal i/o format: -f%s", fmt);
150 error(USER, errmsg);
151 }
152
153 /* gather rays from rtrace and output contributions */
154 int
155 main(int argc, char *argv[])
156 {
157 int nprocs = 1;
158 char *curout = NULL;
159 char *binval = NULL;
160 char fmt[8];
161 int i, j;
162 /* global program name */
163 gargv = argv;
164 /* set up calcomp mode */
165 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_RCONST|E_REDEFW;
166 esupport &= ~(E_OUTCHAN);
167 /* get our options */
168 for (i = 1; i < argc-1; i++) {
169 /* expand arguments */
170 while ((j = expandarg(&argc, &argv, i)) > 0)
171 ;
172 if (j < 0) {
173 fprintf(stderr, "%s: cannot expand '%s'",
174 argv[0], argv[i]);
175 exit(1);
176 }
177 if (argv[i][0] == '-')
178 switch (argv[i][1]) {
179 case 'n': /* number of processes */
180 if (argv[i][2] || i >= argc-1) break;
181 nprocs = atoi(argv[++i]);
182 if (nprocs <= 0)
183 error(USER, "illegal number of processes");
184 continue;
185 case 'h': /* output header? */
186 switch (argv[i][2]) {
187 case '\0':
188 header = !header;
189 continue;
190 case '+': case '1':
191 case 'T': case 't':
192 case 'Y': case 'y':
193 header = 1;
194 continue;
195 case '-': case '0':
196 case 'F': case 'f':
197 case 'N': case 'n':
198 header = 0;
199 continue;
200 }
201 break;
202 case 'f': /* file or i/o format */
203 if (!argv[i][2]) {
204 if (i >= argc-1) break;
205 fcompile(argv[++i]);
206 continue;
207 }
208 setformat(argv[i]+2);
209 continue;
210 case 'e': /* expression */
211 if (argv[i][2] || i >= argc-1) break;
212 scompile(argv[++i], NULL, 0);
213 continue;
214 case 'o': /* output file spec. */
215 if (argv[i][2] || i >= argc-1) break;
216 curout = argv[++i];
217 continue;
218 case 'x': /* horiz. output resolution */
219 if (argv[i][2] || i >= argc-1) break;
220 xres = atoi(argv[++i]);
221 continue;
222 case 'y': /* vert. output resolution */
223 if (argv[i][2] || i >= argc-1) break;
224 yres = atoi(argv[++i]);
225 continue;
226 case 'b': /* bin expression */
227 if (argv[i][2] || i >= argc-1) break;
228 binval = argv[++i];
229 continue;
230 case 'm': /* modifier name */
231 if (argv[i][2] || i >= argc-1) break;
232 rtargv[rtargc++] = "-ti";
233 rtargv[rtargc++] = argv[++i];
234 addmodifier(argv[i], curout, binval);
235 continue;
236 }
237 rtargv[rtargc++] = argv[i]; /* assume rtrace option */
238 }
239 /* set global argument list */
240 gargc = argc; gargv = argv;
241 /* add "mandatory" rtrace settings */
242 for (j = 0; myrtopts[j] != NULL; j++)
243 rtargv[rtargc++] = myrtopts[j];
244 /* just asking for defaults? */
245 if (!strcmp(argv[i], "-defaults")) {
246 char sxres[16], syres[16];
247 char *rtpath;
248 printf("-n %-2d\t\t\t\t# number of processes\n", nprocs);
249 fflush(stdout); /* report OUR options */
250 rtargv[rtargc++] = header ? "-h+" : "-h-";
251 sprintf(fmt, "-f%c%c", inpfmt, outfmt);
252 rtargv[rtargc++] = fmt;
253 rtargv[rtargc++] = "-x";
254 sprintf(sxres, "%d", xres);
255 rtargv[rtargc++] = sxres;
256 rtargv[rtargc++] = "-y";
257 sprintf(syres, "%d", yres);
258 rtargv[rtargc++] = syres;
259 rtargv[rtargc++] = "-oTW";
260 rtargv[rtargc++] = "-defaults";
261 rtargv[rtargc] = NULL;
262 rtpath = getpath(rtargv[0], getenv("PATH"), X_OK);
263 if (rtpath == NULL) {
264 eputs(rtargv[0]);
265 eputs(": command not found\n");
266 exit(1);
267 }
268 execv(rtpath, rtargv);
269 perror(rtpath); /* execv() should not return */
270 exit(1);
271 }
272 if (nprocs > 1) { /* add persist file if parallel */
273 rtargv[rtargc++] = "-PP";
274 rtargv[rtargc++] = mktemp(persistfn);
275 }
276 /* add format string */
277 sprintf(fmt, "-f%cf", inpfmt);
278 rtargv[rtargc++] = fmt;
279 /* octree argument is last */
280 if (i <= 0 || i != argc-1 || argv[i][0] == '-')
281 error(USER, "missing octree argument");
282 rtargv[rtargc++] = octree = argv[i];
283 rtargv[rtargc] = NULL;
284 /* start rtrace & compute contributions */
285 init(nprocs);
286 trace_contribs(stdin);
287 quit(0);
288 }
289
290 /* kill persistent rtrace process */
291 static void
292 killpersist(void)
293 {
294 FILE *fp = fopen(persistfn, "r");
295 int pid;
296
297 if (fp == NULL)
298 return;
299 if (fscanf(fp, "%*s %d", &pid) != 1 || kill(pid, SIGALRM) < 0)
300 unlink(persistfn);
301 fclose(fp);
302 }
303
304 /* close rtrace processes and clean up */
305 int
306 done_rprocs(struct rtproc *rtp)
307 {
308 int st0, st1 = 0;
309
310 if (rtp->next != NULL) { /* close last opened first! */
311 st1 = done_rprocs(rtp->next);
312 free((void *)rtp->next);
313 rtp->next = NULL;
314 }
315 st0 = close_process(&rtp->pd);
316 if (st0 < 0)
317 error(WARNING, "unknown return status from rtrace process");
318 else if (st0 > 0)
319 return(st0);
320 return(st1);
321 }
322
323 /* exit with status */
324 void
325 quit(int status)
326 {
327 int rtstat;
328
329 if (rt0.next != NULL) /* terminate persistent rtrace */
330 killpersist();
331 /* clean up rtrace process(es) */
332 rtstat = done_rprocs(&rt0);
333 if (status == 0)
334 status = rtstat;
335 exit(status); /* flushes all output streams */
336 }
337
338 /* start rtrace processes and initialize */
339 void
340 init(int np)
341 {
342 struct rtproc *rtp;
343 int i;
344 int maxbytes;
345 /* make sure we have something to do */
346 if (!nmods)
347 error(USER, "No modifiers specified");
348 /* assign ray variables */
349 scompile("Dx=$1;Dy=$2;Dz=$3;", NULL, 0);
350 scompile("Px=$4;Py=$5;Pz=$6;", NULL, 0);
351 /* set up signal handling */
352 signal(SIGINT, quit);
353 #ifdef SIGHUP
354 signal(SIGHUP, quit);
355 #endif
356 #ifdef SIGTERM
357 signal(SIGTERM, quit);
358 #endif
359 #ifdef SIGPIPE
360 signal(SIGPIPE, quit);
361 #endif
362 rtp = &rt0; /* start rtrace process(es) */
363 for (i = 0; i++ < np; ) {
364 errno = 0;
365 maxbytes = open_process(&rtp->pd, rtargv);
366 if (maxbytes == 0) {
367 eputs(rtargv[0]);
368 eputs(": command not found\n");
369 exit(1);
370 }
371 if (maxbytes < 0)
372 error(SYSTEM, "cannot start rtrace process");
373 if (maxbytes > treebufsiz)
374 treebufsiz = maxbytes;
375 rtp->raynum = 0;
376 rtp->bsiz = 0;
377 rtp->buf = NULL;
378 rtp->nbr = 0;
379 if (i == np) /* last process? */
380 break;
381 if (i == 1)
382 sleep(2); /* wait for persist file */
383 rtp->next = (struct rtproc *)malloc(sizeof(struct rtproc));
384 if (rtp->next == NULL)
385 error(SYSTEM, "out of memory in init");
386 rtp = rtp->next;
387 }
388 rtp->next = NULL; /* terminate list */
389 if (yres > 0) {
390 if (xres > 0)
391 raysleft = xres*yres;
392 else
393 raysleft = yres;
394 } else
395 raysleft = 0;
396 waitflush = xres;
397 }
398
399 /* add modifier to our list to track */
400 MODCONT *
401 addmodifier(char *modn, char *outf, char *binv)
402 {
403 LUENT *lep = lu_find(&modconttab, modn);
404 MODCONT *mp;
405
406 if (lep->data != NULL) {
407 sprintf(errmsg, "duplicate modifier '%s'", modn);
408 error(USER, errmsg);
409 }
410 if (nmods >= MAXMODLIST)
411 error(USER, "too many modifiers");
412 modname[nmods++] = modn; /* XXX assumes static string */
413 lep->key = modn; /* XXX assumes static string */
414 mp = (MODCONT *)malloc(sizeof(MODCONT));
415 if (mp == NULL)
416 error(SYSTEM, "out of memory in addmodifier");
417 lep->data = (char *)mp;
418 mp->outspec = outf; /* XXX assumes static string */
419 mp->modname = modn; /* XXX assumes static string */
420 if (binv != NULL)
421 mp->binv = eparse(binv);
422 else
423 mp->binv = eparse("0");
424 mp->nbins = 1;
425 setcolor(mp->cbin[0], 0., 0., 0.);
426 return mp;
427 }
428
429 /* put string to stderr */
430 void
431 eputs(char *s)
432 {
433 static int midline = 0;
434
435 if (!*s) return;
436 if (!midline) {
437 fputs(progname, stderr);
438 fputs(": ", stderr);
439 }
440 fputs(s, stderr);
441 midline = s[strlen(s)-1] != '\n';
442 }
443
444 /* write header to the given output stream */
445 void
446 printheader(FILE *fout)
447 {
448 extern char VersionID[];
449 FILE *fin = fopen(octree, "r");
450
451 if (fin == NULL)
452 quit(1);
453 checkheader(fin, "ignore", fout); /* copy octree header */
454 fclose(fin);
455 printargs(gargc-1, gargv, fout); /* add our command */
456 fprintf(fout, "SOFTWARE= %s\n", VersionID);
457 fputnow(fout);
458 switch (outfmt) { /* add output format */
459 case 'a':
460 fputformat("ascii", fout);
461 break;
462 case 'f':
463 fputformat("float", fout);
464 break;
465 case 'd':
466 fputformat("double", fout);
467 break;
468 case 'c':
469 fputformat(COLRFMT, fout);
470 break;
471 }
472 fputc('\n', fout);
473 if (xres > 0) {
474 if (yres > 0) /* resolution string */
475 fprtresolu(xres, yres, fout);
476 fflush(fout);
477 }
478 }
479
480 /* Get output file pointer (open and write header if new) */
481 FILE *
482 getofile(const char *ospec, const char *mname, int bn)
483 {
484 const char *mnp = NULL;
485 const char *bnp = NULL;
486 const char *cp;
487 char ofname[1024];
488 LUENT *lep;
489
490 if (ospec == NULL) { /* use stdout? */
491 if (!using_stdout && header)
492 printheader(stdout);
493 using_stdout = 1;
494 return stdout;
495 }
496 for (cp = ospec; *cp; cp++) /* check format position(s) */
497 if (*cp == '%') {
498 do
499 ++cp;
500 while (isdigit(*cp));
501 switch (*cp) {
502 case '%':
503 break;
504 case 's':
505 if (mnp != NULL)
506 goto badspec;
507 mnp = cp;
508 break;
509 case 'd':
510 if (bnp != NULL)
511 goto badspec;
512 bnp = cp;
513 break;
514 default:
515 goto badspec;
516 }
517 }
518 if (mnp != NULL) { /* create file name */
519 if (bnp != NULL) {
520 if (bnp > mnp)
521 sprintf(ofname, ospec, mname, bn);
522 else
523 sprintf(ofname, ospec, bn, mname);
524 } else
525 sprintf(ofname, ospec, mname);
526 } else if (bnp != NULL)
527 sprintf(ofname, ospec, bn);
528 else
529 strcpy(ofname, ospec);
530 lep = lu_find(&ofiletab, ofname); /* look it up */
531 if (lep->key == NULL) /* new entry */
532 lep->key = strcpy((char *)malloc(strlen(ofname)+1), ofname);
533 if (lep->data == NULL) { /* open output file */
534 FILE *fp = fopen(ofname, "w");
535 int i;
536 if (fp == NULL) {
537 sprintf(errmsg, "cannot open '%s' for writing", ofname);
538 error(SYSTEM, errmsg);
539 }
540 if (header)
541 printheader(fp);
542 /* play catch-up */
543 for (i = 0; i < lastdone; i++) {
544 static const DCOLOR nocontrib = BLKCOLOR;
545 putcontrib(nocontrib, fp);
546 if (outfmt == 'a')
547 putc('\n', fp);
548 }
549 if (xres > 0)
550 fflush(fp);
551 lep->data = (char *)fp;
552 }
553 return (FILE *)lep->data; /* return open file pointer */
554 badspec:
555 sprintf(errmsg, "bad output format '%s'", ospec);
556 error(USER, errmsg);
557 return NULL; /* pro forma return */
558 }
559
560 /* read input ray into buffer */
561 int
562 getinp(char *buf, FILE *fp)
563 {
564 char *cp;
565 int i;
566
567 switch (inpfmt) {
568 case 'a':
569 cp = buf; /* make sure we get 6 floats */
570 for (i = 0; i < 6; i++) {
571 if (fgetword(cp, buf+127-cp, fp) == NULL)
572 return 0;
573 if ((cp = fskip(cp)) == NULL || *cp)
574 return 0;
575 *cp++ = ' ';
576 }
577 getc(fp); /* get/put eol */
578 *cp-- = '\0'; *cp = '\n';
579 return strlen(buf);
580 case 'f':
581 if (fread(buf, sizeof(float), 6, fp) < 6)
582 return 0;
583 return sizeof(float)*6;
584 case 'd':
585 if (fread(buf, sizeof(double), 6, fp) < 6)
586 return 0;
587 return sizeof(double)*6;
588 }
589 error(INTERNAL, "botched input format");
590 return 0; /* pro forma return */
591 }
592
593 static float rparams[9]; /* traced ray parameters */
594
595 /* return channel (ray) value */
596 double
597 chanvalue(int n)
598 {
599 if (--n < 0 || n >= 6)
600 error(USER, "illegal channel number ($N)");
601 return rparams[n+3];
602 }
603
604 /* add current ray contribution to the appropriate modifier bin */
605 void
606 add_contrib(const char *modn)
607 {
608 LUENT *le = lu_find(&modconttab, modn);
609 MODCONT *mp = (MODCONT *)le->data;
610 int bn;
611
612 if (mp == NULL) {
613 sprintf(errmsg, "unexpected modifier '%s' from rtrace", modn);
614 error(USER, errmsg);
615 }
616 eclock++; /* get bin number */
617 bn = (int)(evalue(mp->binv) + .5);
618 if (bn <= 0)
619 bn = 0;
620 else if (bn > mp->nbins) { /* new bin */
621 mp = (MODCONT *)realloc(mp, sizeof(MODCONT) +
622 bn*sizeof(DCOLOR));
623 if (mp == NULL)
624 error(SYSTEM, "out of memory in add_contrib");
625 memset(mp->cbin+mp->nbins, 0, sizeof(DCOLOR)*(bn+1-mp->nbins));
626 mp->nbins = bn+1;
627 le->data = (char *)mp;
628 }
629 addcolor(mp->cbin[bn], rparams);
630 }
631
632 /* output newline to ASCII file and/or flush as requested */
633 static int
634 puteol(const LUENT *e, void *p)
635 {
636 FILE *fp = (FILE *)e->data;
637
638 if (outfmt == 'a')
639 putc('\n', fp);
640 if (!waitflush)
641 fflush(fp);
642 if (ferror(fp)) {
643 sprintf(errmsg, "write error on file '%s'", e->key);
644 error(SYSTEM, errmsg);
645 }
646 return 0;
647 }
648
649 /* put out ray contribution to file */
650 void
651 putcontrib(const DCOLOR cnt, FILE *fout)
652 {
653 float fv[3];
654 COLR cv;
655
656 switch (outfmt) {
657 case 'a':
658 fprintf(fout, "%.6e\t%.6e\t%.6e\t", cnt[0], cnt[1], cnt[2]);
659 break;
660 case 'f':
661 fv[0] = cnt[0];
662 fv[1] = cnt[1];
663 fv[2] = cnt[2];
664 fwrite(fv, sizeof(float), 3, fout);
665 break;
666 case 'd':
667 fwrite(cnt, sizeof(double), 3, fout);
668 break;
669 case 'c':
670 setcolr(cv, cnt[0], cnt[1], cnt[2]);
671 fwrite(cv, sizeof(cv), 1, fout);
672 break;
673 default:
674 error(INTERNAL, "botched output format");
675 }
676 }
677
678 /* output ray tallies and clear for next primary */
679 void
680 done_contrib(void)
681 {
682 int i, j;
683 MODCONT *mp;
684 /* output modifiers in order */
685 for (i = 0; i < nmods; i++) {
686 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
687 for (j = 0; j < mp->nbins; j++)
688 putcontrib(mp->cbin[j],
689 getofile(mp->outspec, mp->modname, j));
690 /* clear for next ray tree */
691 memset(mp->cbin, 0, sizeof(DCOLOR)*mp->nbins);
692 }
693 --waitflush; /* terminate records */
694 lu_doall(&ofiletab, puteol, NULL);
695 if (using_stdout & (outfmt == 'a'))
696 putc('\n', stdout);
697 if (!waitflush) {
698 waitflush = xres;
699 if (using_stdout)
700 fflush(stdout);
701 }
702 }
703
704 /* queue completed ray tree produced by rtrace process */
705 void
706 queue_raytree(struct rtproc *rtp)
707 {
708 struct rtproc *rtu, *rtl = NULL;
709 /* insert following ray order */
710 for (rtu = rt_unproc; rtu != NULL; rtu = (rtl=rtu)->next)
711 if (rtp->raynum < rtu->raynum)
712 break;
713 rtu = (struct rtproc *)malloc(sizeof(struct rtproc));
714 if (rtu == NULL)
715 error(SYSTEM, "out of memory in queue_raytree");
716 *rtu = *rtp;
717 if (rtl == NULL) {
718 rtu->next = rt_unproc;
719 rt_unproc = rtu;
720 } else {
721 rtu->next = rtl->next;
722 rtl->next = rtu;
723 }
724 rtp->raynum = 0; /* clear path for next ray tree */
725 rtp->bsiz = 0;
726 rtp->buf = NULL;
727 rtp->nbr = 0;
728 }
729
730 /* process completed ray trees from our queue */
731 void
732 process_queue(void)
733 {
734 char modname[128];
735 /* ray-ordered queue */
736 while (rt_unproc != NULL && rt_unproc->raynum == lastdone+1) {
737 struct rtproc *rtp = rt_unproc;
738 int n = rtp->nbr;
739 const char *cp = rtp->buf;
740 while (n > 0) { /* process rays */
741 register char *mnp = modname;
742 /* skip leading tabs */
743 while (n > 0 && *cp == '\t') {
744 cp++; n--;
745 }
746 if (!n || !(isalpha(*cp) | (*cp == '_')))
747 error(USER, "bad modifier name from rtrace");
748 /* get modifier name */
749 while (n > 0 && *cp != '\t') {
750 *mnp++ = *cp++; n--;
751 }
752 *mnp = '\0';
753 cp++; n--; /* eat following tab */
754 if (n < (int)(sizeof(float)*9))
755 error(USER, "incomplete ray value from rtrace");
756 /* add ray contribution */
757 memcpy(rparams, cp, sizeof(float)*9);
758 cp += sizeof(float)*9; n -= sizeof(float)*9;
759 add_contrib(modname);
760 }
761 done_contrib(); /* sum up contributions & output */
762 lastdone = rtp->raynum;
763 free(rtp->buf); /* free up buffer space */
764 rt_unproc = rtp->next;
765 free(rtp); /* done with this ray tree */
766 }
767 }
768
769 /* wait for rtrace process to finish with ray tree */
770 struct rtproc *
771 wait_rproc(void)
772 {
773 struct rtproc *rtfree = NULL;
774 fd_set readset, errset;
775 int nr;
776 struct rtproc *rt;
777 int n;
778
779 do {
780 nr = 0; /* prepare select call */
781 FD_ZERO(&readset); FD_ZERO(&errset); n = 0;
782 for (rt = &rt0; rt != NULL; rt = rt->next) {
783 if (rt->raynum) {
784 FD_SET(rt->pd.r, &readset);
785 ++nr;
786 }
787 FD_SET(rt->pd.r, &errset);
788 if (rt->pd.r >= n)
789 n = rt->pd.r + 1;
790 }
791 if (!nr) /* no rays pending */
792 break;
793 if (nr > 1) { /* call select for multiple proc's */
794 errno = 0;
795 if (select(n, &readset, NULL, &errset, NULL) < 0)
796 error(SYSTEM, "select call error in wait_rproc()");
797 } else
798 FD_ZERO(&errset);
799 nr = 0;
800 for (rt = &rt0; rt != NULL; rt = rt->next) {
801 if (!FD_ISSET(rt->pd.r, &readset) &&
802 !FD_ISSET(rt->pd.r, &errset))
803 continue;
804 if (rt->buf == NULL) {
805 rt->bsiz = treebufsiz;
806 rt->buf = (char *)malloc(treebufsiz);
807 } else if (rt->nbr + BUFSIZ > rt->bsiz) {
808 if (rt->bsiz + BUFSIZ <= treebufsiz)
809 rt->bsiz = treebufsiz;
810 else
811 rt->bsiz = treebufsiz += BUFSIZ;
812 rt->buf = (char *)realloc(rt->buf, rt->bsiz);
813 }
814 if (rt->buf == NULL)
815 error(SYSTEM, "out of memory in wait_rproc");
816 nr = read(rt->pd.r, rt->buf+rt->nbr, rt->bsiz-rt->nbr);
817 if (nr <= 0)
818 error(USER, "rtrace process died");
819 rt->nbr += nr; /* advance & check */
820 if (rt->nbr >= 4 && !memcmp(rt->buf+rt->nbr-4,
821 "~\t~\t", 4)) {
822 rt->nbr -= 4; /* elide terminator */
823 queue_raytree(rt);
824 rtfree = rt; /* ready for next ray */
825 }
826 }
827 } while ((rtfree == NULL) & (nr > 0)); /* repeat until ready or out */
828 return rtfree;
829 }
830
831 /* return next available rtrace process */
832 struct rtproc *
833 get_rproc(void)
834 {
835 struct rtproc *rtp;
836 /* check for idle rtrace */
837 for (rtp = &rt0; rtp != NULL; rtp = rtp->next)
838 if (!rtp->raynum)
839 return rtp;
840 return wait_rproc(); /* need to wait for one */
841 }
842
843 /* trace ray contributions (main loop) */
844 void
845 trace_contribs(FILE *fin)
846 {
847 char inpbuf[128];
848 int iblen;
849 struct rtproc *rtp;
850 /* loop over input */
851 while ((iblen = getinp(inpbuf, fin)) > 0) {
852 if (lastray+1 < lastray) { /* counter rollover? */
853 while (wait_rproc() != NULL)
854 process_queue();
855 lastdone = lastray = 0;
856 }
857 rtp = get_rproc(); /* get avail. rtrace process */
858 rtp->raynum = ++lastray; /* assign ray to it */
859 writebuf(rtp->pd.w, inpbuf, iblen);
860 if (!--raysleft)
861 break;
862 process_queue(); /* catch up with results */
863 }
864 while (wait_rproc() != NULL) /* process outstanding rays */
865 process_queue();
866 if (raysleft > 0)
867 error(USER, "unexpected EOF on input");
868 }