ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.2
Committed: Sun Jun 10 05:25:42 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +12 -10 lines
Log Message:
Tweaks and bug fixes to new code

File Contents

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