ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rtcontrib.c
Revision: 1.1
Committed: Wed May 25 04:45:22 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created rtcontrib program for computing ray contributions and coefficients

File Contents

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