ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rtcontrib.c
Revision: 1.2
Committed: Thu May 26 06:55:22 2005 UTC (18 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.1: +183 -164 lines
Log Message:
Got rtcontrib working and wrote basic man page

File Contents

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