ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.17
Committed: Sun Mar 6 01:13:18 2016 UTC (8 years, 2 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.16: +3 -2 lines
Log Message:
Prepare for SCons build on Win32 and Win64

File Contents

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