Page MenuHomec4science

rc2.c
No OneTemporary

File Metadata

Created
Thu, Sep 26, 04:24
#ifndef lint
static const char RCSid[] = "$Id: rc2.c,v 2.24 2019/09/04 20:19:51 greg Exp $";
#endif
/*
* Accumulate ray contributions for a set of materials
* File i/o and recovery
*/
#include <ctype.h>
#include "platform.h"
#include "rcontrib.h"
#include "resolu.h"
/* Close output stream and free record */
static void
closestream(void *p)
{
STREAMOUT *sop = (STREAMOUT *)p;
if (sop->ofp != NULL) {
int status = 0;
if (sop->outpipe)
status = pclose(sop->ofp);
else if (sop->ofp != stdout)
status = fclose(sop->ofp);
if (status)
error(SYSTEM, "error closing output stream");
}
free(p);
}
LUTAB ofiletab = LU_SINIT(free,closestream); /* output file table */
#define OF_MODIFIER 01
#define OF_BIN 02
/************************** STREAM & FILE I/O ***************************/
/* Construct output file name and return flags whether modifier/bin present */
static int
ofname(char *oname, const char *ospec, const char *mname, int bn)
{
const char *mnp = NULL;
const char *bnp = NULL;
const char *cp;
if (ospec == NULL)
return(-1);
for (cp = ospec; *cp; cp++) /* check format position(s) */
if (*cp == '%') {
do
++cp;
while (isdigit(*cp));
switch (*cp) {
case '%':
break;
case 's':
if (mnp != NULL)
return(-1);
mnp = cp;
break;
case 'd':
case 'i':
case 'o':
case 'x':
case 'X':
if (bnp != NULL)
return(-1);
bnp = cp;
break;
default:
return(-1);
}
}
if (mnp != NULL) { /* create file name */
if (bnp != NULL) {
if (bnp > mnp)
sprintf(oname, ospec, mname, bn);
else
sprintf(oname, ospec, bn, mname);
return(OF_MODIFIER|OF_BIN);
}
sprintf(oname, ospec, mname);
return(OF_MODIFIER);
}
if (bnp != NULL) {
sprintf(oname, ospec, bn);
return(OF_BIN);
}
strcpy(oname, ospec);
return(0);
}
/* Write header to the given output stream */
static void
printheader(FILE *fout, const char *info)
{
extern char VersionID[];
/* copy octree header */
if (octname[0] == '!') {
newheader("RADIANCE", fout);
fputs(octname+1, fout);
if (octname[strlen(octname)-1] != '\n')
fputc('\n', fout);
} else {
FILE *fin = fopen(octname, (outfmt=='a') ? "r" : "rb");
if (fin == NULL)
quit(1);
checkheader(fin, OCTFMT, fout);
fclose(fin);
}
printargs(gargc-1, gargv, fout); /* add our command */
fprintf(fout, "SOFTWARE= %s\n", VersionID);
fputnow(fout);
fputs("NCOMP=3\n", fout); /* always RGB */
if (info != NULL) /* add extra info if given */
fputs(info, fout);
if ((outfmt == 'f') | (outfmt == 'd'))
fputendian(fout);
fputformat(formstr(outfmt), fout);
fputc('\n', fout); /* empty line ends header */
}
/* Write resolution string to given output stream */
static void
printresolu(FILE *fout, int xr, int yr)
{
if ((xr > 0) & (yr > 0)) /* resolution string */
fprtresolu(xr, yr, fout);
}
/* Get output stream pointer (open and write header if new and noopen==0) */
STREAMOUT *
getostream(const char *ospec, const char *mname, int bn, int noopen)
{
static STREAMOUT stdos;
char info[1024];
int ofl;
char oname[1024];
LUENT *lep;
STREAMOUT *sop;
char *cp;
if (ospec == NULL) { /* use stdout? */
if (!noopen & !using_stdout) {
if (outfmt != 'a')
SET_FILE_BINARY(stdout);
#ifdef getc_unlocked
flockfile(stdout); /* avoid lock/unlock overhead */
#endif
if (header) {
cp = info;
if (yres > 0) {
sprintf(cp, "NROWS=%d\n", yres *
(xres + !xres) );
while (*cp) ++cp;
}
if ((xres <= 0) | (stdos.reclen > 1))
sprintf(cp, "NCOLS=%d\n", stdos.reclen);
printheader(stdout, info);
}
if (stdos.reclen == 1)
printresolu(stdout, xres, yres);
if (waitflush > 0)
fflush(stdout);
stdos.xr = xres; stdos.yr = yres;
using_stdout = 1;
}
stdos.ofp = stdout;
stdos.reclen += noopen;
return(&stdos);
}
ofl = ofname(oname, ospec, mname, bn); /* get output name */
if (ofl < 0) {
sprintf(errmsg, "bad output format '%s'", ospec);
error(USER, errmsg);
}
lep = lu_find(&ofiletab, oname); /* look it up */
if (lep->key == NULL) /* new entry */
lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
sop = (STREAMOUT *)lep->data;
if (sop == NULL) { /* allocate stream */
sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
if (sop == NULL)
error(SYSTEM, "out of memory in getostream");
sop->outpipe = (oname[0] == '!');
sop->reclen = 0;
sop->ofp = NULL; /* open iff noopen==0 */
sop->xr = xres; sop->yr = yres;
lep->data = (char *)sop;
if (!sop->outpipe & !force_open & !recover &&
access(oname, F_OK) == 0) {
errno = EEXIST; /* file exists */
goto openerr;
}
} else if (noopen && outfmt == 'c' && /* stream exists to picture? */
(sop->xr > 0) & (sop->yr > 0)) {
if (ofl & OF_BIN)
return(NULL); /* let caller offset bins */
sprintf(errmsg, "output '%s' not a valid picture", oname);
error(WARNING, errmsg);
}
if (!noopen && sop->ofp == NULL) { /* open output stream */
if (oname[0] == '!') /* output to command */
sop->ofp = popen(oname+1, "w");
else /* else open file */
sop->ofp = fopen(oname, "w");
if (sop->ofp == NULL)
goto openerr;
if (outfmt != 'a')
SET_FILE_BINARY(sop->ofp);
#ifdef getc_unlocked
flockfile(sop->ofp); /* avoid lock/unlock overhead */
#endif
if (accumulate > 0) { /* global resolution */
sop->xr = xres; sop->yr = yres;
}
if (header) {
cp = info;
if (ofl & OF_MODIFIER || sop->reclen == 1) {
sprintf(cp, "MODIFIER=%s\n", mname);
while (*cp) ++cp;
}
if (ofl & OF_BIN) {
sprintf(cp, "BIN=%d\n", bn);
while (*cp) ++cp;
}
if (sop->yr > 0) {
sprintf(cp, "NROWS=%d\n", sop->yr *
(sop->xr + !sop->xr) );
while (*cp) ++cp;
}
if ((sop->xr <= 0) | (sop->reclen > 1))
sprintf(cp, "NCOLS=%d\n", sop->reclen);
printheader(sop->ofp, info);
}
if (sop->reclen == 1)
printresolu(sop->ofp, sop->xr, sop->yr);
if (waitflush > 0)
fflush(sop->ofp);
}
sop->reclen += noopen; /* add to length if noopen */
return(sop); /* return output stream */
openerr:
sprintf(errmsg, "cannot open '%s' for writing", oname);
error(SYSTEM, errmsg);
return(NULL); /* pro forma return */
}
/* Get a vector from stdin */
int
getvec(FVECT vec)
{
float vf[3];
double vd[3];
char buf[32];
int i;
switch (inpfmt) {
case 'a': /* ascii */
for (i = 0; i < 3; i++) {
if (fgetword(buf, sizeof(buf), stdin) == NULL ||
!isflt(buf))
return(-1);
vec[i] = atof(buf);
}
break;
case 'f': /* binary float */
if (getbinary((char *)vf, sizeof(float), 3, stdin) != 3)
return(-1);
VCOPY(vec, vf);
break;
case 'd': /* binary double */
if (getbinary((char *)vd, sizeof(double), 3, stdin) != 3)
return(-1);
VCOPY(vec, vd);
break;
default:
error(CONSISTENCY, "botched input format");
}
return(0);
}
/* Put out ray contribution to file */
static void
put_contrib(const DCOLOR cnt, FILE *fout)
{
double sf = 1;
COLOR fv;
COLR cv;
if (accumulate > 1)
sf = 1./(double)accumulate;
switch (outfmt) {
case 'a':
if (accumulate > 1)
fprintf(fout, "%.6e\t%.6e\t%.6e\t",
sf*cnt[0], sf*cnt[1], sf*cnt[2]);
else
fprintf(fout, "%.6e\t%.6e\t%.6e\t",
cnt[0], cnt[1], cnt[2]);
break;
case 'f':
if (accumulate > 1) {
copycolor(fv, cnt);
scalecolor(fv, sf);
} else
copycolor(fv, cnt);
putbinary(fv, sizeof(float), 3, fout);
break;
case 'd':
if (accumulate > 1) {
DCOLOR dv;
copycolor(dv, cnt);
scalecolor(dv, sf);
putbinary(dv, sizeof(double), 3, fout);
} else
putbinary(cnt, sizeof(double), 3, fout);
break;
case 'c':
if (accumulate > 1)
setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
else
setcolr(cv, cnt[0], cnt[1], cnt[2]);
putbinary(cv, sizeof(cv), 1, fout);
break;
default:
error(INTERNAL, "botched output format");
}
}
/* Output modifier values to appropriate stream(s) */
void
mod_output(MODCONT *mp)
{
STREAMOUT *sop = getostream(mp->outspec, mp->modname, mp->bin0, 0);
int j;
put_contrib(mp->cbin[0], sop->ofp);
if (mp->nbins > 3 && /* minor optimization */
sop == getostream(mp->outspec, mp->modname, mp->bin0+1, 0)) {
for (j = 1; j < mp->nbins; j++)
put_contrib(mp->cbin[j], sop->ofp);
} else {
for (j = 1; j < mp->nbins; j++) {
sop = getostream(mp->outspec, mp->modname, mp->bin0+j, 0);
put_contrib(mp->cbin[j], sop->ofp);
}
}
}
/* callback to output newline to ASCII file and/or flush as requested */
static int
puteol(const LUENT *e, void *p)
{
STREAMOUT *sop = (STREAMOUT *)e->data;
if (outfmt == 'a')
putc('\n', sop->ofp);
if (!waitflush)
fflush(sop->ofp);
if (ferror(sop->ofp)) {
sprintf(errmsg, "write error on file '%s'", e->key);
error(SYSTEM, errmsg);
}
return(0);
}
/* Terminate record output and flush if time */
void
end_record()
{
--waitflush;
lu_doall(&ofiletab, &puteol, NULL);
if (using_stdout & (outfmt == 'a'))
putc('\n', stdout);
if (!waitflush) {
waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
if (using_stdout)
fflush(stdout);
}
}
/************************** PARTIAL RESULTS RECOVERY ***********************/
/* Get ray contribution from previous file */
static int
get_contrib(DCOLOR cnt, FILE *finp)
{
COLOR fv;
COLR cv;
switch (outfmt) {
case 'a':
return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3);
case 'f':
if (getbinary(fv, sizeof(fv[0]), 3, finp) != 3)
return(0);
copycolor(cnt, fv);
return(1);
case 'd':
return(getbinary(cnt, sizeof(cnt[0]), 3, finp) == 3);
case 'c':
if (getbinary(cv, sizeof(cv), 1, finp) != 1)
return(0);
colr_color(fv, cv);
copycolor(cnt, fv);
return(1);
default:
error(INTERNAL, "botched output format");
}
return(0); /* pro forma return */
}
/* Close output file opened for input */
static int
myclose(const LUENT *e, void *p)
{
STREAMOUT *sop = (STREAMOUT *)e->data;
if (sop->ofp == NULL)
return(0);
fclose(sop->ofp);
sop->ofp = NULL;
return(0);
}
/* Load previously accumulated values */
void
reload_output()
{
int i, j;
MODCONT *mp;
int ofl;
char oname[1024];
char *fmode = "rb";
char *outvfmt;
LUENT *oent;
int xr, yr;
STREAMOUT *sop;
DCOLOR rgbv;
if (outfmt == 'a')
fmode = "r";
outvfmt = formstr(outfmt);
/* reload modifier values */
for (i = 0; i < nmods; i++) {
mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
if (mp->outspec == NULL)
error(USER, "cannot reload from stdout");
if (mp->outspec[0] == '!')
error(USER, "cannot reload from command");
for (j = 0; j < mp->nbins; j++) { /* load each modifier bin */
ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
if (ofl < 0)
error(USER, "bad output file specification");
oent = lu_find(&ofiletab, oname);
if (oent->data == NULL)
error(INTERNAL, "unallocated stream in reload_output()");
sop = (STREAMOUT *)oent->data;
if (sop->ofp == NULL) { /* open output as input */
sop->ofp = fopen(oname, fmode);
if (sop->ofp == NULL) {
sprintf(errmsg, "missing reload file '%s'",
oname);
error(WARNING, errmsg);
break;
}
#ifdef getc_unlocked
flockfile(sop->ofp);
#endif
if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
sprintf(errmsg, "format mismatch for '%s'",
oname);
error(USER, errmsg);
}
if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
(!fscnresolu(&xr, &yr, sop->ofp) ||
(xr != sop->xr) |
(yr != sop->yr))) {
sprintf(errmsg, "resolution mismatch for '%s'",
oname);
error(USER, errmsg);
}
}
/* read in RGB value */
if (!get_contrib(rgbv, sop->ofp)) {
if (!j) {
fclose(sop->ofp);
break; /* ignore empty file */
}
if (j < mp->nbins) {
sprintf(errmsg, "missing data in '%s'",
oname);
error(USER, errmsg);
}
break;
}
copycolor(mp->cbin[j], rgbv);
}
}
lu_doall(&ofiletab, &myclose, NULL); /* close all files */
}
/* Seek on the given output file */
static int
myseeko(const LUENT *e, void *p)
{
STREAMOUT *sop = (STREAMOUT *)e->data;
off_t nbytes = *(off_t *)p;
if (sop->reclen > 1)
nbytes *= (off_t)sop->reclen;
if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
sprintf(errmsg, "seek error on file '%s'", e->key);
error(SYSTEM, errmsg);
}
return(0);
}
/* Recover output if possible */
void
recover_output()
{
off_t lastout = -1;
int outvsiz, recsiz;
char *outvfmt;
int i, j;
MODCONT *mp;
int ofl;
char oname[1024];
LUENT *oent;
STREAMOUT *sop;
off_t nvals;
int xr, yr;
switch (outfmt) {
case 'a':
error(USER, "cannot recover ASCII output");
return;
case 'f':
outvsiz = sizeof(float)*3;
break;
case 'd':
outvsiz = sizeof(double)*3;
break;
case 'c':
outvsiz = sizeof(COLR);
break;
default:
error(INTERNAL, "botched output format");
return;
}
outvfmt = formstr(outfmt);
/* check modifier outputs */
for (i = 0; i < nmods; i++) {
mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
if (mp->outspec == NULL)
error(USER, "cannot recover from stdout");
if (mp->outspec[0] == '!')
error(USER, "cannot recover from command");
for (j = 0; j < mp->nbins; j++) { /* check each bin's file */
ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
if (ofl < 0)
error(USER, "bad output file specification");
oent = lu_find(&ofiletab, oname);
if (oent->data == NULL)
error(INTERNAL, "unallocated stream in recover_output()");
sop = (STREAMOUT *)oent->data;
if (sop->ofp != NULL) { /* already open? */
if (ofl & OF_BIN)
continue;
break;
}
/* open output */
sop->ofp = fopen(oname, "rb+");
if (sop->ofp == NULL) {
sprintf(errmsg, "missing recover file '%s'",
oname);
error(WARNING, errmsg);
lastout = 0;
break;
}
nvals = lseek(fileno(sop->ofp), 0, SEEK_END);
if (nvals <= 0) {
lastout = 0; /* empty output, quit here */
fclose(sop->ofp);
break;
}
recsiz = outvsiz * sop->reclen;
lseek(fileno(sop->ofp), 0, SEEK_SET);
if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
sprintf(errmsg, "format mismatch for '%s'",
oname);
error(USER, errmsg);
}
if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
(!fscnresolu(&xr, &yr, sop->ofp) ||
(xr != sop->xr) |
(yr != sop->yr))) {
sprintf(errmsg, "resolution mismatch for '%s'",
oname);
error(USER, errmsg);
}
nvals = (nvals - (off_t)ftell(sop->ofp)) / recsiz;
if ((lastout < 0) | (nvals < lastout))
lastout = nvals;
if (!(ofl & OF_BIN))
break; /* no bin separation */
}
if (!lastout) { /* empty output */
error(WARNING, "no previous data to recover");
/* reclose all outputs */
lu_doall(&ofiletab, &myclose, NULL);
return;
}
}
if (lastout < 0) {
error(WARNING, "no output files to recover");
return;
}
if (raysleft && lastout >= raysleft/accumulate) {
error(WARNING, "output appears to be complete");
/* XXX should read & discard input? */
quit(0);
}
/* seek on all files */
nvals = lastout * outvsiz;
lu_doall(&ofiletab, &myseeko, &nvals);
/* skip repeated input */
lastout *= accumulate;
for (nvals = 0; nvals < lastout; nvals++) {
FVECT vdummy;
if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
error(USER, "unexpected EOF on input");
}
lastray = lastdone = (RNUMBER)lastout;
if (raysleft)
raysleft -= lastray;
}

Event Timeline