ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.23
Committed: Wed Aug 14 20:07:20 2019 UTC (4 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.22: +3 -1 lines
Log Message:
Added BigEndian= line to binary header output

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.23 static const char RCSid[] = "$Id: rc2.c,v 2.22 2017/02/07 16:48:14 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Accumulate ray contributions for a set of materials
6     * File i/o and recovery
7     */
8    
9 schorsch 2.17 #include <ctype.h>
10     #include "platform.h"
11 greg 2.1 #include "rcontrib.h"
12     #include "resolu.h"
13    
14 greg 2.3 /* Close output stream and free record */
15     static void
16     closestream(void *p)
17     {
18     STREAMOUT *sop = (STREAMOUT *)p;
19    
20     if (sop->ofp != NULL) {
21     int status = 0;
22     if (sop->outpipe)
23     status = pclose(sop->ofp);
24     else if (sop->ofp != stdout)
25     status = fclose(sop->ofp);
26     if (status)
27     error(SYSTEM, "error closing output stream");
28     }
29     free(p);
30     }
31    
32     LUTAB ofiletab = LU_SINIT(free,closestream); /* output file table */
33    
34 greg 2.1 #define OF_MODIFIER 01
35     #define OF_BIN 02
36    
37     /************************** STREAM & FILE I/O ***************************/
38    
39     /* Construct output file name and return flags whether modifier/bin present */
40     static int
41     ofname(char *oname, const char *ospec, const char *mname, int bn)
42     {
43     const char *mnp = NULL;
44     const char *bnp = NULL;
45     const char *cp;
46    
47     if (ospec == NULL)
48     return(-1);
49     for (cp = ospec; *cp; cp++) /* check format position(s) */
50     if (*cp == '%') {
51     do
52     ++cp;
53     while (isdigit(*cp));
54     switch (*cp) {
55     case '%':
56     break;
57     case 's':
58     if (mnp != NULL)
59     return(-1);
60     mnp = cp;
61     break;
62     case 'd':
63     case 'i':
64     case 'o':
65     case 'x':
66     case 'X':
67     if (bnp != NULL)
68     return(-1);
69     bnp = cp;
70     break;
71     default:
72     return(-1);
73     }
74     }
75     if (mnp != NULL) { /* create file name */
76     if (bnp != NULL) {
77     if (bnp > mnp)
78     sprintf(oname, ospec, mname, bn);
79     else
80     sprintf(oname, ospec, bn, mname);
81     return(OF_MODIFIER|OF_BIN);
82     }
83     sprintf(oname, ospec, mname);
84     return(OF_MODIFIER);
85     }
86     if (bnp != NULL) {
87     sprintf(oname, ospec, bn);
88     return(OF_BIN);
89     }
90     strcpy(oname, ospec);
91     return(0);
92     }
93    
94    
95     /* Write header to the given output stream */
96     static void
97     printheader(FILE *fout, const char *info)
98     {
99     extern char VersionID[];
100     /* copy octree header */
101     if (octname[0] == '!') {
102     newheader("RADIANCE", fout);
103     fputs(octname+1, fout);
104     if (octname[strlen(octname)-1] != '\n')
105     fputc('\n', fout);
106     } else {
107 greg 2.2 FILE *fin = fopen(octname, (outfmt=='a') ? "r" : "rb");
108 greg 2.1 if (fin == NULL)
109     quit(1);
110 greg 2.2 checkheader(fin, OCTFMT, fout);
111 greg 2.1 fclose(fin);
112     }
113     printargs(gargc-1, gargv, fout); /* add our command */
114     fprintf(fout, "SOFTWARE= %s\n", VersionID);
115     fputnow(fout);
116 greg 2.9 fputs("NCOMP=3\n", fout); /* always RGB */
117 greg 2.1 if (info != NULL) /* add extra info if given */
118     fputs(info, fout);
119 greg 2.23 if ((outfmt == 'f') | (outfmt == 'd'))
120     fputendian(fout);
121 greg 2.1 fputformat(formstr(outfmt), fout);
122     fputc('\n', fout); /* empty line ends header */
123     }
124    
125    
126     /* Write resolution string to given output stream */
127     static void
128     printresolu(FILE *fout, int xr, int yr)
129     {
130     if ((xr > 0) & (yr > 0)) /* resolution string */
131     fprtresolu(xr, yr, fout);
132     }
133    
134    
135     /* Get output stream pointer (open and write header if new and noopen==0) */
136     STREAMOUT *
137     getostream(const char *ospec, const char *mname, int bn, int noopen)
138     {
139     static STREAMOUT stdos;
140 greg 2.9 char info[1024];
141 greg 2.1 int ofl;
142     char oname[1024];
143     LUENT *lep;
144     STREAMOUT *sop;
145 greg 2.11 char *cp;
146 greg 2.1
147     if (ospec == NULL) { /* use stdout? */
148 greg 2.3 if (!noopen & !using_stdout) {
149 greg 2.1 if (outfmt != 'a')
150     SET_FILE_BINARY(stdout);
151 greg 2.9 if (header) {
152 greg 2.11 cp = info;
153     if (yres > 0) {
154     sprintf(cp, "NROWS=%d\n", yres *
155     (xres + !xres) );
156     while (*cp) ++cp;
157     }
158 greg 2.13 if ((xres <= 0) | (stdos.reclen > 1))
159     sprintf(cp, "NCOLS=%d\n", stdos.reclen);
160 greg 2.9 printheader(stdout, info);
161     }
162 greg 2.13 if (stdos.reclen == 1)
163     printresolu(stdout, xres, yres);
164 greg 2.1 if (waitflush > 0)
165     fflush(stdout);
166     stdos.xr = xres; stdos.yr = yres;
167 greg 2.15 #ifdef getc_unlocked
168 greg 2.1 flockfile(stdout); /* avoid lock/unlock overhead */
169     #endif
170     using_stdout = 1;
171     }
172     stdos.ofp = stdout;
173     stdos.reclen += noopen;
174     return(&stdos);
175     }
176     ofl = ofname(oname, ospec, mname, bn); /* get output name */
177     if (ofl < 0) {
178     sprintf(errmsg, "bad output format '%s'", ospec);
179     error(USER, errmsg);
180     }
181     lep = lu_find(&ofiletab, oname); /* look it up */
182     if (lep->key == NULL) /* new entry */
183     lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
184     sop = (STREAMOUT *)lep->data;
185     if (sop == NULL) { /* allocate stream */
186     sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
187     if (sop == NULL)
188     error(SYSTEM, "out of memory in getostream");
189 greg 2.19 sop->outpipe = (oname[0] == '!');
190 greg 2.1 sop->reclen = 0;
191     sop->ofp = NULL; /* open iff noopen==0 */
192     sop->xr = xres; sop->yr = yres;
193     lep->data = (char *)sop;
194     if (!sop->outpipe & !force_open & !recover &&
195     access(oname, F_OK) == 0) {
196     errno = EEXIST; /* file exists */
197     goto openerr;
198     }
199 greg 2.19 } else if (noopen && outfmt == 'c' && /* stream exists to picture? */
200     (sop->xr > 0) & (sop->yr > 0)) {
201     if (ofl & OF_BIN)
202     return(NULL); /* let caller offset bins */
203     sprintf(errmsg, "output '%s' not a valid picture", oname);
204     error(WARNING, errmsg);
205 greg 2.1 }
206     if (!noopen && sop->ofp == NULL) { /* open output stream */
207     if (oname[0] == '!') /* output to command */
208     sop->ofp = popen(oname+1, "w");
209     else /* else open file */
210     sop->ofp = fopen(oname, "w");
211     if (sop->ofp == NULL)
212     goto openerr;
213     if (outfmt != 'a')
214     SET_FILE_BINARY(sop->ofp);
215 greg 2.15 #ifdef getc_unlocked
216 greg 2.1 flockfile(sop->ofp); /* avoid lock/unlock overhead */
217     #endif
218 greg 2.11 if (accumulate > 0) { /* global resolution */
219     sop->xr = xres; sop->yr = yres;
220     }
221 greg 2.1 if (header) {
222 greg 2.11 cp = info;
223 greg 2.1 if (ofl & OF_MODIFIER || sop->reclen == 1) {
224     sprintf(cp, "MODIFIER=%s\n", mname);
225     while (*cp) ++cp;
226     }
227     if (ofl & OF_BIN) {
228     sprintf(cp, "BIN=%d\n", bn);
229     while (*cp) ++cp;
230     }
231 greg 2.11 if (sop->yr > 0) {
232     sprintf(cp, "NROWS=%d\n", sop->yr *
233     (sop->xr + !sop->xr) );
234     while (*cp) ++cp;
235     }
236 greg 2.13 if ((sop->xr <= 0) | (sop->reclen > 1))
237     sprintf(cp, "NCOLS=%d\n", sop->reclen);
238 greg 2.1 printheader(sop->ofp, info);
239     }
240 greg 2.13 if (sop->reclen == 1)
241     printresolu(sop->ofp, sop->xr, sop->yr);
242 greg 2.1 if (waitflush > 0)
243     fflush(sop->ofp);
244     }
245     sop->reclen += noopen; /* add to length if noopen */
246     return(sop); /* return output stream */
247     openerr:
248     sprintf(errmsg, "cannot open '%s' for writing", oname);
249     error(SYSTEM, errmsg);
250     return(NULL); /* pro forma return */
251     }
252    
253    
254     /* Get a vector from stdin */
255     int
256     getvec(FVECT vec)
257     {
258     float vf[3];
259     double vd[3];
260     char buf[32];
261     int i;
262    
263     switch (inpfmt) {
264     case 'a': /* ascii */
265     for (i = 0; i < 3; i++) {
266     if (fgetword(buf, sizeof(buf), stdin) == NULL ||
267     !isflt(buf))
268     return(-1);
269     vec[i] = atof(buf);
270     }
271     break;
272     case 'f': /* binary float */
273 greg 2.18 if (getbinary((char *)vf, sizeof(float), 3, stdin) != 3)
274 greg 2.1 return(-1);
275     VCOPY(vec, vf);
276     break;
277     case 'd': /* binary double */
278 greg 2.18 if (getbinary((char *)vd, sizeof(double), 3, stdin) != 3)
279 greg 2.1 return(-1);
280     VCOPY(vec, vd);
281     break;
282     default:
283     error(CONSISTENCY, "botched input format");
284     }
285     return(0);
286     }
287    
288    
289     /* Put out ray contribution to file */
290     static void
291     put_contrib(const DCOLOR cnt, FILE *fout)
292     {
293     double sf = 1;
294 greg 2.2 COLOR fv;
295 greg 2.1 COLR cv;
296    
297     if (accumulate > 1)
298     sf = 1./(double)accumulate;
299     switch (outfmt) {
300     case 'a':
301     if (accumulate > 1)
302     fprintf(fout, "%.6e\t%.6e\t%.6e\t",
303     sf*cnt[0], sf*cnt[1], sf*cnt[2]);
304     else
305     fprintf(fout, "%.6e\t%.6e\t%.6e\t",
306     cnt[0], cnt[1], cnt[2]);
307     break;
308     case 'f':
309     if (accumulate > 1) {
310 greg 2.2 copycolor(fv, cnt);
311     scalecolor(fv, sf);
312 greg 2.1 } else
313     copycolor(fv, cnt);
314 greg 2.18 putbinary(fv, sizeof(float), 3, fout);
315 greg 2.1 break;
316     case 'd':
317     if (accumulate > 1) {
318 greg 2.2 DCOLOR dv;
319     copycolor(dv, cnt);
320     scalecolor(dv, sf);
321 greg 2.18 putbinary(dv, sizeof(double), 3, fout);
322 greg 2.1 } else
323 greg 2.18 putbinary(cnt, sizeof(double), 3, fout);
324 greg 2.1 break;
325     case 'c':
326     if (accumulate > 1)
327     setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
328     else
329     setcolr(cv, cnt[0], cnt[1], cnt[2]);
330 greg 2.18 putbinary(cv, sizeof(cv), 1, fout);
331 greg 2.1 break;
332     default:
333     error(INTERNAL, "botched output format");
334     }
335     }
336    
337    
338     /* Output modifier values to appropriate stream(s) */
339     void
340     mod_output(MODCONT *mp)
341     {
342 greg 2.19 STREAMOUT *sop = getostream(mp->outspec, mp->modname, mp->bin0, 0);
343 greg 2.1 int j;
344    
345     put_contrib(mp->cbin[0], sop->ofp);
346     if (mp->nbins > 3 && /* minor optimization */
347 greg 2.19 sop == getostream(mp->outspec, mp->modname, mp->bin0+1, 0)) {
348 greg 2.1 for (j = 1; j < mp->nbins; j++)
349     put_contrib(mp->cbin[j], sop->ofp);
350 greg 2.3 } else {
351 greg 2.1 for (j = 1; j < mp->nbins; j++) {
352 greg 2.19 sop = getostream(mp->outspec, mp->modname, mp->bin0+j, 0);
353 greg 2.1 put_contrib(mp->cbin[j], sop->ofp);
354     }
355 greg 2.3 }
356 greg 2.1 }
357    
358    
359     /* callback to output newline to ASCII file and/or flush as requested */
360     static int
361     puteol(const LUENT *e, void *p)
362     {
363     STREAMOUT *sop = (STREAMOUT *)e->data;
364    
365     if (outfmt == 'a')
366     putc('\n', sop->ofp);
367     if (!waitflush)
368     fflush(sop->ofp);
369     if (ferror(sop->ofp)) {
370     sprintf(errmsg, "write error on file '%s'", e->key);
371     error(SYSTEM, errmsg);
372     }
373     return(0);
374     }
375    
376    
377     /* Terminate record output and flush if time */
378     void
379     end_record()
380     {
381     --waitflush;
382 greg 2.7 lu_doall(&ofiletab, &puteol, NULL);
383 greg 2.1 if (using_stdout & (outfmt == 'a'))
384     putc('\n', stdout);
385     if (!waitflush) {
386     waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
387     if (using_stdout)
388     fflush(stdout);
389     }
390     }
391    
392     /************************** PARTIAL RESULTS RECOVERY ***********************/
393    
394     /* Get ray contribution from previous file */
395     static int
396     get_contrib(DCOLOR cnt, FILE *finp)
397     {
398     COLOR fv;
399     COLR cv;
400    
401     switch (outfmt) {
402     case 'a':
403     return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3);
404     case 'f':
405 greg 2.18 if (getbinary(fv, sizeof(fv[0]), 3, finp) != 3)
406 greg 2.1 return(0);
407     copycolor(cnt, fv);
408     return(1);
409     case 'd':
410 greg 2.18 return(getbinary(cnt, sizeof(cnt[0]), 3, finp) == 3);
411 greg 2.1 case 'c':
412 greg 2.18 if (getbinary(cv, sizeof(cv), 1, finp) != 1)
413 greg 2.1 return(0);
414     colr_color(fv, cv);
415     copycolor(cnt, fv);
416     return(1);
417     default:
418     error(INTERNAL, "botched output format");
419     }
420     return(0); /* pro forma return */
421     }
422    
423    
424     /* Close output file opened for input */
425     static int
426     myclose(const LUENT *e, void *p)
427     {
428     STREAMOUT *sop = (STREAMOUT *)e->data;
429    
430     if (sop->ofp == NULL)
431     return(0);
432     fclose(sop->ofp);
433     sop->ofp = NULL;
434     return(0);
435     }
436    
437    
438     /* Load previously accumulated values */
439     void
440     reload_output()
441     {
442     int i, j;
443     MODCONT *mp;
444     int ofl;
445     char oname[1024];
446     char *fmode = "rb";
447     char *outvfmt;
448     LUENT *oent;
449     int xr, yr;
450 greg 2.20 STREAMOUT *sop;
451 greg 2.1 DCOLOR rgbv;
452    
453     if (outfmt == 'a')
454     fmode = "r";
455     outvfmt = formstr(outfmt);
456     /* reload modifier values */
457     for (i = 0; i < nmods; i++) {
458     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
459     if (mp->outspec == NULL)
460     error(USER, "cannot reload from stdout");
461     if (mp->outspec[0] == '!')
462     error(USER, "cannot reload from command");
463 greg 2.20 for (j = 0; j < mp->nbins; j++) { /* load each modifier bin */
464     ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
465 greg 2.1 if (ofl < 0)
466     error(USER, "bad output file specification");
467     oent = lu_find(&ofiletab, oname);
468 greg 2.20 if (oent->data == NULL)
469     error(INTERNAL, "unallocated stream in reload_output()");
470     sop = (STREAMOUT *)oent->data;
471     if (sop->ofp == NULL) { /* open output as input */
472     sop->ofp = fopen(oname, fmode);
473     if (sop->ofp == NULL) {
474 greg 2.1 sprintf(errmsg, "missing reload file '%s'",
475     oname);
476     error(WARNING, errmsg);
477     break;
478     }
479 greg 2.15 #ifdef getc_unlocked
480 greg 2.20 flockfile(sop->ofp);
481 greg 2.1 #endif
482 greg 2.20 if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
483 greg 2.1 sprintf(errmsg, "format mismatch for '%s'",
484     oname);
485     error(USER, errmsg);
486     }
487 greg 2.20 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
488     (!fscnresolu(&xr, &yr, sop->ofp) ||
489     (xr != sop->xr) |
490     (yr != sop->yr))) {
491 greg 2.1 sprintf(errmsg, "resolution mismatch for '%s'",
492     oname);
493     error(USER, errmsg);
494     }
495     }
496     /* read in RGB value */
497 greg 2.20 if (!get_contrib(rgbv, sop->ofp)) {
498 greg 2.1 if (!j) {
499 greg 2.20 fclose(sop->ofp);
500 greg 2.1 break; /* ignore empty file */
501     }
502     if (j < mp->nbins) {
503     sprintf(errmsg, "missing data in '%s'",
504     oname);
505     error(USER, errmsg);
506     }
507     break;
508 greg 2.20 }
509 greg 2.1 copycolor(mp->cbin[j], rgbv);
510     }
511     }
512 greg 2.7 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
513 greg 2.1 }
514    
515    
516     /* Seek on the given output file */
517     static int
518     myseeko(const LUENT *e, void *p)
519     {
520     STREAMOUT *sop = (STREAMOUT *)e->data;
521     off_t nbytes = *(off_t *)p;
522    
523     if (sop->reclen > 1)
524 greg 2.22 nbytes *= (off_t)sop->reclen;
525 greg 2.1 if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
526     sprintf(errmsg, "seek error on file '%s'", e->key);
527     error(SYSTEM, errmsg);
528     }
529     return(0);
530     }
531    
532    
533     /* Recover output if possible */
534     void
535     recover_output()
536     {
537     off_t lastout = -1;
538     int outvsiz, recsiz;
539     char *outvfmt;
540     int i, j;
541     MODCONT *mp;
542     int ofl;
543     char oname[1024];
544     LUENT *oent;
545 greg 2.20 STREAMOUT *sop;
546 greg 2.1 off_t nvals;
547     int xr, yr;
548    
549     switch (outfmt) {
550     case 'a':
551     error(USER, "cannot recover ASCII output");
552     return;
553     case 'f':
554     outvsiz = sizeof(float)*3;
555     break;
556     case 'd':
557     outvsiz = sizeof(double)*3;
558     break;
559     case 'c':
560     outvsiz = sizeof(COLR);
561     break;
562     default:
563     error(INTERNAL, "botched output format");
564     return;
565     }
566     outvfmt = formstr(outfmt);
567     /* check modifier outputs */
568     for (i = 0; i < nmods; i++) {
569     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
570     if (mp->outspec == NULL)
571     error(USER, "cannot recover from stdout");
572     if (mp->outspec[0] == '!')
573     error(USER, "cannot recover from command");
574 greg 2.20 for (j = 0; j < mp->nbins; j++) { /* check each bin's file */
575     ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
576 greg 2.1 if (ofl < 0)
577     error(USER, "bad output file specification");
578     oent = lu_find(&ofiletab, oname);
579 greg 2.20 if (oent->data == NULL)
580     error(INTERNAL, "unallocated stream in recover_output()");
581     sop = (STREAMOUT *)oent->data;
582     if (sop->ofp != NULL) { /* already open? */
583 greg 2.1 if (ofl & OF_BIN)
584     continue;
585     break;
586     }
587     /* open output */
588 greg 2.20 sop->ofp = fopen(oname, "rb+");
589     if (sop->ofp == NULL) {
590 greg 2.1 sprintf(errmsg, "missing recover file '%s'",
591     oname);
592     error(WARNING, errmsg);
593 greg 2.21 lastout = 0;
594 greg 2.1 break;
595     }
596 greg 2.20 nvals = lseek(fileno(sop->ofp), 0, SEEK_END);
597 greg 2.1 if (nvals <= 0) {
598     lastout = 0; /* empty output, quit here */
599 greg 2.20 fclose(sop->ofp);
600 greg 2.1 break;
601     }
602 greg 2.20 recsiz = outvsiz * sop->reclen;
603 greg 2.1
604 greg 2.20 lseek(fileno(sop->ofp), 0, SEEK_SET);
605     if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
606 greg 2.1 sprintf(errmsg, "format mismatch for '%s'",
607     oname);
608     error(USER, errmsg);
609     }
610 greg 2.20 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
611     (!fscnresolu(&xr, &yr, sop->ofp) ||
612     (xr != sop->xr) |
613     (yr != sop->yr))) {
614 greg 2.1 sprintf(errmsg, "resolution mismatch for '%s'",
615     oname);
616     error(USER, errmsg);
617     }
618 greg 2.20 nvals = (nvals - (off_t)ftell(sop->ofp)) / recsiz;
619 greg 2.1 if ((lastout < 0) | (nvals < lastout))
620     lastout = nvals;
621     if (!(ofl & OF_BIN))
622     break; /* no bin separation */
623     }
624     if (!lastout) { /* empty output */
625     error(WARNING, "no previous data to recover");
626 greg 2.21 /* reclose all outputs */
627     lu_doall(&ofiletab, &myclose, NULL);
628 greg 2.1 return;
629     }
630     }
631     if (lastout < 0) {
632     error(WARNING, "no output files to recover");
633     return;
634     }
635     if (raysleft && lastout >= raysleft/accumulate) {
636     error(WARNING, "output appears to be complete");
637     /* XXX should read & discard input? */
638     quit(0);
639     }
640     /* seek on all files */
641     nvals = lastout * outvsiz;
642 greg 2.7 lu_doall(&ofiletab, &myseeko, &nvals);
643 greg 2.1 /* skip repeated input */
644 greg 2.5 lastout *= accumulate;
645 greg 2.1 for (nvals = 0; nvals < lastout; nvals++) {
646     FVECT vdummy;
647     if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
648     error(USER, "unexpected EOF on input");
649     }
650 greg 2.5 lastray = lastdone = (RNUMBER)lastout;
651 greg 2.1 if (raysleft)
652     raysleft -= lastray;
653     }