ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.24
Committed: Wed Sep 4 20:19:51 2019 UTC (4 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.23: +4 -4 lines
Log Message:
Minor change should not affect behavior

File Contents

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