ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.13
Committed: Thu Jul 24 16:28:17 2014 UTC (9 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad4R2, rad4R2P1
Changes since 2.12: +9 -5 lines
Log Message:
Made NROWS/NCOLS more consistent with resolution string

File Contents

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