ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.12
Committed: Wed Jul 9 21:09:28 2014 UTC (9 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +2 -3 lines
Log Message:
Removed redundant NCOLS= line in header

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rc2.c,v 2.11 2014/06/13 01:16:41 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 char *cp;
143
144 if (ospec == NULL) { /* use stdout? */
145 if (!noopen & !using_stdout) {
146 if (outfmt != 'a')
147 SET_FILE_BINARY(stdout);
148 if (header) {
149 cp = info;
150 if (yres > 0) {
151 sprintf(cp, "NROWS=%d\n", yres *
152 (xres + !xres) );
153 while (*cp) ++cp;
154 }
155 sprintf(cp, "NCOLS=%d\n", stdos.reclen);
156 printheader(stdout, info);
157 }
158 printresolu(stdout, xres, yres);
159 if (waitflush > 0)
160 fflush(stdout);
161 stdos.xr = xres; stdos.yr = yres;
162 #ifdef getc_unlocked
163 flockfile(stdout); /* avoid lock/unlock overhead */
164 #endif
165 using_stdout = 1;
166 }
167 stdos.ofp = stdout;
168 stdos.reclen += noopen;
169 return(&stdos);
170 }
171 ofl = ofname(oname, ospec, mname, bn); /* get output name */
172 if (ofl < 0) {
173 sprintf(errmsg, "bad output format '%s'", ospec);
174 error(USER, errmsg);
175 }
176 lep = lu_find(&ofiletab, oname); /* look it up */
177 if (lep->key == NULL) /* new entry */
178 lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
179 sop = (STREAMOUT *)lep->data;
180 if (sop == NULL) { /* allocate stream */
181 sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
182 if (sop == NULL)
183 error(SYSTEM, "out of memory in getostream");
184 sop->outpipe = oname[0] == '!';
185 sop->reclen = 0;
186 sop->ofp = NULL; /* open iff noopen==0 */
187 sop->xr = xres; sop->yr = yres;
188 lep->data = (char *)sop;
189 if (!sop->outpipe & !force_open & !recover &&
190 access(oname, F_OK) == 0) {
191 errno = EEXIST; /* file exists */
192 goto openerr;
193 }
194 }
195 if (!noopen && sop->ofp == NULL) { /* open output stream */
196 if (oname[0] == '!') /* output to command */
197 sop->ofp = popen(oname+1, "w");
198 else /* else open file */
199 sop->ofp = fopen(oname, "w");
200 if (sop->ofp == NULL)
201 goto openerr;
202 if (outfmt != 'a')
203 SET_FILE_BINARY(sop->ofp);
204 #ifdef getc_unlocked
205 flockfile(sop->ofp); /* avoid lock/unlock overhead */
206 #endif
207 if (accumulate > 0) { /* global resolution */
208 sop->xr = xres; sop->yr = yres;
209 }
210 if (header) {
211 cp = info;
212 if (ofl & OF_MODIFIER || sop->reclen == 1) {
213 sprintf(cp, "MODIFIER=%s\n", mname);
214 while (*cp) ++cp;
215 }
216 if (ofl & OF_BIN) {
217 sprintf(cp, "BIN=%d\n", bn);
218 while (*cp) ++cp;
219 }
220 if (sop->yr > 0) {
221 sprintf(cp, "NROWS=%d\n", sop->yr *
222 (sop->xr + !sop->xr) );
223 while (*cp) ++cp;
224 }
225 sprintf(cp, "NCOLS=%d\nNCOMP=3\n", sop->reclen);
226 printheader(sop->ofp, info);
227 }
228 printresolu(sop->ofp, sop->xr, sop->yr);
229 if (waitflush > 0)
230 fflush(sop->ofp);
231 }
232 sop->reclen += noopen; /* add to length if noopen */
233 return(sop); /* return output stream */
234 openerr:
235 sprintf(errmsg, "cannot open '%s' for writing", oname);
236 error(SYSTEM, errmsg);
237 return(NULL); /* pro forma return */
238 }
239
240
241 /* Get a vector from stdin */
242 int
243 getvec(FVECT vec)
244 {
245 float vf[3];
246 double vd[3];
247 char buf[32];
248 int i;
249
250 switch (inpfmt) {
251 case 'a': /* ascii */
252 for (i = 0; i < 3; i++) {
253 if (fgetword(buf, sizeof(buf), stdin) == NULL ||
254 !isflt(buf))
255 return(-1);
256 vec[i] = atof(buf);
257 }
258 break;
259 case 'f': /* binary float */
260 if (fread((char *)vf, sizeof(float), 3, stdin) != 3)
261 return(-1);
262 VCOPY(vec, vf);
263 break;
264 case 'd': /* binary double */
265 if (fread((char *)vd, sizeof(double), 3, stdin) != 3)
266 return(-1);
267 VCOPY(vec, vd);
268 break;
269 default:
270 error(CONSISTENCY, "botched input format");
271 }
272 return(0);
273 }
274
275
276 /* Put out ray contribution to file */
277 static void
278 put_contrib(const DCOLOR cnt, FILE *fout)
279 {
280 double sf = 1;
281 COLOR fv;
282 COLR cv;
283
284 if (accumulate > 1)
285 sf = 1./(double)accumulate;
286 switch (outfmt) {
287 case 'a':
288 if (accumulate > 1)
289 fprintf(fout, "%.6e\t%.6e\t%.6e\t",
290 sf*cnt[0], sf*cnt[1], sf*cnt[2]);
291 else
292 fprintf(fout, "%.6e\t%.6e\t%.6e\t",
293 cnt[0], cnt[1], cnt[2]);
294 break;
295 case 'f':
296 if (accumulate > 1) {
297 copycolor(fv, cnt);
298 scalecolor(fv, sf);
299 } else
300 copycolor(fv, cnt);
301 fwrite(fv, sizeof(float), 3, fout);
302 break;
303 case 'd':
304 if (accumulate > 1) {
305 DCOLOR dv;
306 copycolor(dv, cnt);
307 scalecolor(dv, sf);
308 fwrite(dv, sizeof(double), 3, fout);
309 } else
310 fwrite(cnt, sizeof(double), 3, fout);
311 break;
312 case 'c':
313 if (accumulate > 1)
314 setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
315 else
316 setcolr(cv, cnt[0], cnt[1], cnt[2]);
317 fwrite(cv, sizeof(cv), 1, fout);
318 break;
319 default:
320 error(INTERNAL, "botched output format");
321 }
322 }
323
324
325 /* Output modifier values to appropriate stream(s) */
326 void
327 mod_output(MODCONT *mp)
328 {
329 STREAMOUT *sop = getostream(mp->outspec, mp->modname, 0, 0);
330 int j;
331
332 put_contrib(mp->cbin[0], sop->ofp);
333 if (mp->nbins > 3 && /* minor optimization */
334 sop == getostream(mp->outspec, mp->modname, 1, 0)) {
335 for (j = 1; j < mp->nbins; j++)
336 put_contrib(mp->cbin[j], sop->ofp);
337 } else {
338 for (j = 1; j < mp->nbins; j++) {
339 sop = getostream(mp->outspec, mp->modname, j, 0);
340 put_contrib(mp->cbin[j], sop->ofp);
341 }
342 }
343 }
344
345
346 /* callback to output newline to ASCII file and/or flush as requested */
347 static int
348 puteol(const LUENT *e, void *p)
349 {
350 STREAMOUT *sop = (STREAMOUT *)e->data;
351
352 if (outfmt == 'a')
353 putc('\n', sop->ofp);
354 if (!waitflush)
355 fflush(sop->ofp);
356 if (ferror(sop->ofp)) {
357 sprintf(errmsg, "write error on file '%s'", e->key);
358 error(SYSTEM, errmsg);
359 }
360 return(0);
361 }
362
363
364 /* Terminate record output and flush if time */
365 void
366 end_record()
367 {
368 --waitflush;
369 lu_doall(&ofiletab, &puteol, NULL);
370 if (using_stdout & (outfmt == 'a'))
371 putc('\n', stdout);
372 if (!waitflush) {
373 waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
374 if (using_stdout)
375 fflush(stdout);
376 }
377 }
378
379 /************************** PARTIAL RESULTS RECOVERY ***********************/
380
381 /* Get ray contribution from previous file */
382 static int
383 get_contrib(DCOLOR cnt, FILE *finp)
384 {
385 COLOR fv;
386 COLR cv;
387
388 switch (outfmt) {
389 case 'a':
390 return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3);
391 case 'f':
392 if (fread(fv, sizeof(fv[0]), 3, finp) != 3)
393 return(0);
394 copycolor(cnt, fv);
395 return(1);
396 case 'd':
397 return(fread(cnt, sizeof(cnt[0]), 3, finp) == 3);
398 case 'c':
399 if (fread(cv, sizeof(cv), 1, finp) != 1)
400 return(0);
401 colr_color(fv, cv);
402 copycolor(cnt, fv);
403 return(1);
404 default:
405 error(INTERNAL, "botched output format");
406 }
407 return(0); /* pro forma return */
408 }
409
410
411 /* Close output file opened for input */
412 static int
413 myclose(const LUENT *e, void *p)
414 {
415 STREAMOUT *sop = (STREAMOUT *)e->data;
416
417 if (sop->ofp == NULL)
418 return(0);
419 fclose(sop->ofp);
420 sop->ofp = NULL;
421 return(0);
422 }
423
424
425 /* Load previously accumulated values */
426 void
427 reload_output()
428 {
429 int i, j;
430 MODCONT *mp;
431 int ofl;
432 char oname[1024];
433 char *fmode = "rb";
434 char *outvfmt;
435 LUENT *oent;
436 int xr, yr;
437 STREAMOUT sout;
438 DCOLOR rgbv;
439
440 if (outfmt == 'a')
441 fmode = "r";
442 outvfmt = formstr(outfmt);
443 /* reload modifier values */
444 for (i = 0; i < nmods; i++) {
445 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
446 if (mp->outspec == NULL)
447 error(USER, "cannot reload from stdout");
448 if (mp->outspec[0] == '!')
449 error(USER, "cannot reload from command");
450 for (j = 0; ; j++) { /* load each modifier bin */
451 ofl = ofname(oname, mp->outspec, mp->modname, j);
452 if (ofl < 0)
453 error(USER, "bad output file specification");
454 oent = lu_find(&ofiletab, oname);
455 if (oent->data != NULL) {
456 sout = *(STREAMOUT *)oent->data;
457 } else {
458 sout.reclen = 0;
459 sout.outpipe = 0;
460 sout.xr = xres; sout.yr = yres;
461 sout.ofp = NULL;
462 }
463 if (sout.ofp == NULL) { /* open output as input */
464 sout.ofp = fopen(oname, fmode);
465 if (sout.ofp == NULL) {
466 if (j == mp->nbins)
467 break; /* assume end of modifier */
468 sprintf(errmsg, "missing reload file '%s'",
469 oname);
470 error(WARNING, errmsg);
471 break;
472 }
473 #ifdef getc_unlocked
474 flockfile(sout.ofp);
475 #endif
476 if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
477 sprintf(errmsg, "format mismatch for '%s'",
478 oname);
479 error(USER, errmsg);
480 }
481 if ((sout.xr > 0) & (sout.yr > 0) &&
482 (!fscnresolu(&xr, &yr, sout.ofp) ||
483 (xr != sout.xr) |
484 (yr != sout.yr))) {
485 sprintf(errmsg, "resolution mismatch for '%s'",
486 oname);
487 error(USER, errmsg);
488 }
489 }
490 /* read in RGB value */
491 if (!get_contrib(rgbv, sout.ofp)) {
492 if (!j) {
493 fclose(sout.ofp);
494 break; /* ignore empty file */
495 }
496 if (j < mp->nbins) {
497 sprintf(errmsg, "missing data in '%s'",
498 oname);
499 error(USER, errmsg);
500 }
501 break;
502 }
503 if (j >= mp->nbins) { /* check modifier size */
504 sprintf(errmsg,
505 "mismatched -bn setting for reloading '%s'",
506 modname[i]);
507 error(USER, errmsg);
508 }
509
510 copycolor(mp->cbin[j], rgbv);
511 if (oent->key == NULL) /* new file entry */
512 oent->key = strcpy((char *)
513 malloc(strlen(oname)+1), oname);
514 if (oent->data == NULL)
515 oent->data = (char *)malloc(sizeof(STREAMOUT));
516 *(STREAMOUT *)oent->data = sout;
517 }
518 }
519 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
520 }
521
522
523 /* Seek on the given output file */
524 static int
525 myseeko(const LUENT *e, void *p)
526 {
527 STREAMOUT *sop = (STREAMOUT *)e->data;
528 off_t nbytes = *(off_t *)p;
529
530 if (sop->reclen > 1)
531 nbytes = nbytes * sop->reclen;
532 if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
533 sprintf(errmsg, "seek error on file '%s'", e->key);
534 error(SYSTEM, errmsg);
535 }
536 return(0);
537 }
538
539
540 /* Recover output if possible */
541 void
542 recover_output()
543 {
544 off_t lastout = -1;
545 int outvsiz, recsiz;
546 char *outvfmt;
547 int i, j;
548 MODCONT *mp;
549 int ofl;
550 char oname[1024];
551 LUENT *oent;
552 STREAMOUT sout;
553 off_t nvals;
554 int xr, yr;
555
556 switch (outfmt) {
557 case 'a':
558 error(USER, "cannot recover ASCII output");
559 return;
560 case 'f':
561 outvsiz = sizeof(float)*3;
562 break;
563 case 'd':
564 outvsiz = sizeof(double)*3;
565 break;
566 case 'c':
567 outvsiz = sizeof(COLR);
568 break;
569 default:
570 error(INTERNAL, "botched output format");
571 return;
572 }
573 outvfmt = formstr(outfmt);
574 /* check modifier outputs */
575 for (i = 0; i < nmods; i++) {
576 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
577 if (mp->outspec == NULL)
578 error(USER, "cannot recover from stdout");
579 if (mp->outspec[0] == '!')
580 error(USER, "cannot recover from command");
581 for (j = 0; ; j++) { /* check each bin's file */
582 ofl = ofname(oname, mp->outspec, mp->modname, j);
583 if (ofl < 0)
584 error(USER, "bad output file specification");
585 oent = lu_find(&ofiletab, oname);
586 if (oent->data != NULL) {
587 sout = *(STREAMOUT *)oent->data;
588 } else {
589 sout.reclen = 0;
590 sout.outpipe = 0;
591 sout.ofp = NULL;
592 }
593 if (sout.ofp != NULL) { /* already open? */
594 if (ofl & OF_BIN)
595 continue;
596 break;
597 }
598 /* open output */
599 sout.ofp = fopen(oname, "rb+");
600 if (sout.ofp == NULL) {
601 if (j == mp->nbins)
602 break; /* assume end of modifier */
603 sprintf(errmsg, "missing recover file '%s'",
604 oname);
605 error(WARNING, errmsg);
606 break;
607 }
608 nvals = lseek(fileno(sout.ofp), 0, SEEK_END);
609 if (nvals <= 0) {
610 lastout = 0; /* empty output, quit here */
611 fclose(sout.ofp);
612 break;
613 }
614 if (!sout.reclen) {
615 if (!(ofl & OF_BIN)) {
616 sprintf(errmsg,
617 "need -bn to recover file '%s'",
618 oname);
619 error(USER, errmsg);
620 }
621 recsiz = outvsiz;
622 } else
623 recsiz = outvsiz * sout.reclen;
624
625 lseek(fileno(sout.ofp), 0, SEEK_SET);
626 if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
627 sprintf(errmsg, "format mismatch for '%s'",
628 oname);
629 error(USER, errmsg);
630 }
631 sout.xr = xres; sout.yr = yres;
632 if ((sout.xr > 0) & (sout.yr > 0) &&
633 (!fscnresolu(&xr, &yr, sout.ofp) ||
634 (xr != sout.xr) |
635 (yr != sout.yr))) {
636 sprintf(errmsg, "resolution mismatch for '%s'",
637 oname);
638 error(USER, errmsg);
639 }
640 nvals = (nvals - (off_t)ftell(sout.ofp)) / recsiz;
641 if ((lastout < 0) | (nvals < lastout))
642 lastout = nvals;
643 if (oent->key == NULL) /* new entry */
644 oent->key = strcpy((char *)
645 malloc(strlen(oname)+1), oname);
646 if (oent->data == NULL)
647 oent->data = (char *)malloc(sizeof(STREAMOUT));
648 *(STREAMOUT *)oent->data = sout;
649 if (!(ofl & OF_BIN))
650 break; /* no bin separation */
651 }
652 if (!lastout) { /* empty output */
653 error(WARNING, "no previous data to recover");
654 lu_done(&ofiletab); /* reclose all outputs */
655 return;
656 }
657 if (j > mp->nbins) { /* check modifier size */
658 sprintf(errmsg,
659 "mismatched -bn setting for recovering '%s'",
660 modname[i]);
661 error(USER, errmsg);
662 }
663 }
664 if (lastout < 0) {
665 error(WARNING, "no output files to recover");
666 return;
667 }
668 if (raysleft && lastout >= raysleft/accumulate) {
669 error(WARNING, "output appears to be complete");
670 /* XXX should read & discard input? */
671 quit(0);
672 }
673 /* seek on all files */
674 nvals = lastout * outvsiz;
675 lu_doall(&ofiletab, &myseeko, &nvals);
676 /* skip repeated input */
677 lastout *= accumulate;
678 for (nvals = 0; nvals < lastout; nvals++) {
679 FVECT vdummy;
680 if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
681 error(USER, "unexpected EOF on input");
682 }
683 lastray = lastdone = (RNUMBER)lastout;
684 if (raysleft)
685 raysleft -= lastray;
686 }