ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.9
Committed: Thu May 29 04:56:43 2014 UTC (9 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +8 -6 lines
Log Message:
Added NCOLS= and NCOMP= to header output

File Contents

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