Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F87124275
rtrace.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Oct 10, 19:04
Size
18 KB
Mime Type
text/x-c
Expires
Sat, Oct 12, 19:04 (2 d)
Engine
blob
Format
Raw Data
Handle
21540163
Attached To
R10977 RADIANCE Photon Map
rtrace.c
View Options
#ifndef lint
static const char RCSid[] = "$Id: rtrace.c,v 2.102 2021/04/16 16:31:35 greg Exp $";
#endif
/*
* rtrace.c - program and variables for individual ray tracing.
*/
#include "copyright.h"
/*
* Input is in the form:
*
* xorg yorg zorg xdir ydir zdir
*
* The direction need not be normalized. Output is flexible.
* If the direction vector is (0,0,0), then the output is flushed.
* All values default to ascii representation of real
* numbers. Binary representations can be selected
* with '-ff' for float or '-fd' for double. By default,
* radiance is computed. The '-i' or '-I' options indicate that
* irradiance values are desired.
*/
#include <time.h>
#include "platform.h"
#include "ray.h"
#include "ambient.h"
#include "source.h"
#include "otypes.h"
#include "otspecial.h"
#include "resolu.h"
#include "random.h"
extern int inform; /* input format */
extern int outform; /* output format */
extern char *outvals; /* output values */
extern int imm_irrad; /* compute immediate irradiance? */
extern int lim_dist; /* limit distance? */
extern char *tralist[]; /* list of modifers to trace (or no) */
extern int traincl; /* include == 1, exclude == 0 */
extern int hresolu; /* horizontal resolution */
extern int vresolu; /* vertical resolution */
int castonly = 0; /* only doing ray-casting? */
#ifndef MAXTSET
#define MAXTSET 8191 /* maximum number in trace set */
#endif
OBJECT traset[MAXTSET+1]={0}; /* trace include/exclude set */
static int Tflag = 0; /* source tracing enabled? */
static RAY thisray; /* for our convenience */
static FILE *inpfp = NULL; /* input stream pointer */
static FVECT *inp_queue = NULL; /* ray input queue if flushing */
static int inp_qpos = 0; /* next ray to return */
static int inp_qend = 0; /* number of rays in this work group */
typedef void putf_t(RREAL *v, int n);
static putf_t puta, putd, putf, putrgbe;
typedef void oputf_t(RAY *r);
static oputf_t oputo, oputd, oputv, oputV, oputl, oputL, oputc, oputp,
oputr, oputR, oputx, oputX, oputn, oputN, oputs,
oputw, oputW, oputm, oputM, oputtilde;
extern void tranotify(OBJECT obj);
static int is_fifo(FILE *fp);
static void bogusray(void);
static void raycast(RAY *r);
static void rayirrad(RAY *r);
static void rtcompute(FVECT org, FVECT dir, double dmax);
static int printvals(RAY *r);
static int getvec(FVECT vec, int fmt, FILE *fp);
static int iszerovec(const FVECT vec);
static double nextray(FVECT org, FVECT dir);
static void tabin(RAY *r);
static void ourtrace(RAY *r);
static oputf_t *ray_out[32], *every_out[32];
static putf_t *putreal;
void
quit( /* quit program */
int code
)
{
if (ray_pnprocs > 0) /* close children if any */
ray_pclose(0);
else if (ray_pnprocs < 0)
_exit(code); /* avoid flush() in child */
#ifndef NON_POSIX
else {
headclean(); /* delete header file */
pfclean(); /* clean up persist files */
}
#endif
exit(code);
}
char *
formstr( /* return format identifier */
int f
)
{
switch (f) {
case 'a': return("ascii");
case 'f': return("float");
case 'd': return("double");
case 'c': return(COLRFMT);
}
return("unknown");
}
static void
trace_sources(void) /* trace rays to light sources, also */
{
int sn;
for (sn = 0; sn < nsources; sn++)
source[sn].sflags |= SFOLLOW;
}
void
rtrace( /* trace rays from file */
char *fname,
int nproc
)
{
unsigned long vcount = (hresolu > 1) ? (unsigned long)hresolu*vresolu
: (unsigned long)vresolu;
long nextflush = (!vresolu | (hresolu <= 1)) * hresolu;
int something2flush = 0;
FILE *fp;
double d;
FVECT orig, direc;
/* set up input */
if (fname == NULL)
inpfp = stdin;
else if ((inpfp = fopen(fname, "r")) == NULL) {
sprintf(errmsg, "cannot open input file \"%s\"", fname);
error(SYSTEM, errmsg);
}
#ifdef getc_unlocked
flockfile(inpfp); /* avoid lock/unlock overhead */
flockfile(stdout);
#endif
if (inform != 'a')
SET_FILE_BINARY(inpfp);
/* set up output */
if (castonly || every_out[0] != NULL)
nproc = 1; /* don't bother multiprocessing */
if (Tflag && every_out[0] != NULL)
trace_sources(); /* asking to trace light sources */
if ((nextflush > 0) & (nproc > nextflush)) {
error(WARNING, "reducing number of processes to match flush interval");
nproc = nextflush;
}
switch (outform) {
case 'a': putreal = puta; break;
case 'f': putreal = putf; break;
case 'd': putreal = putd; break;
case 'c':
if (outvals[1] || !strchr("vrx", outvals[0]))
error(USER, "color format only with -ov, -or, -ox");
putreal = putrgbe; break;
default:
error(CONSISTENCY, "botched output format");
}
if (nproc > 1) { /* start multiprocessing */
ray_popen(nproc);
ray_fifo_out = printvals;
}
if (hresolu > 0) {
if (vresolu > 0)
fprtresolu(hresolu, vresolu, stdout);
else
fflush(stdout);
}
/* process input rays */
while ((d = nextray(orig, direc)) >= 0.0) {
if (d == 0.0) { /* flush request? */
if (something2flush) {
if (ray_pnprocs > 1 && ray_fifo_flush() < 0)
error(USER, "child(ren) died");
bogusray();
fflush(stdout);
nextflush = (!vresolu | (hresolu <= 1)) * hresolu;
something2flush = 0;
} else
bogusray();
} else { /* compute and print */
rtcompute(orig, direc, lim_dist ? d : 0.0);
if (!--nextflush) { /* flush if time */
if (ray_pnprocs > 1 && ray_fifo_flush() < 0)
error(USER, "child(ren) died");
fflush(stdout);
nextflush = hresolu;
} else
something2flush = 1;
}
if (ferror(stdout))
error(SYSTEM, "write error");
if (vcount && !--vcount) /* check for end */
break;
}
if (ray_pnprocs > 1) { /* clean up children */
if (ray_fifo_flush() < 0)
error(USER, "unable to complete processing");
ray_pclose(0);
}
if (vcount)
error(WARNING, "unexpected EOF on input");
if (fflush(stdout) < 0)
error(SYSTEM, "write error");
if (fname != NULL) {
fclose(inpfp);
inpfp = NULL;
}
nextray(NULL, NULL);
}
int
setrtoutput(void) /* set up output tables, return #comp */
{
char *vs = outvals;
oputf_t **table = ray_out;
int ncomp = 0;
if (!*vs)
error(USER, "empty output specification");
castonly = 1; /* sets castonly as side-effect */
do
switch (*vs) {
case 'T': /* trace sources */
Tflag++;
/* fall through */
case 't': /* trace */
if (!vs[1]) break;
*table = NULL;
table = every_out;
trace = ourtrace;
castonly = 0;
break;
case 'o': /* origin */
*table++ = oputo;
ncomp += 3;
break;
case 'd': /* direction */
*table++ = oputd;
ncomp += 3;
break;
case 'r': /* reflected contrib. */
*table++ = oputr;
ncomp += 3;
castonly = 0;
break;
case 'R': /* reflected distance */
*table++ = oputR;
ncomp++;
castonly = 0;
break;
case 'x': /* xmit contrib. */
*table++ = oputx;
ncomp += 3;
castonly = 0;
break;
case 'X': /* xmit distance */
*table++ = oputX;
ncomp++;
castonly = 0;
break;
case 'v': /* value */
*table++ = oputv;
ncomp += 3;
castonly = 0;
break;
case 'V': /* contribution */
*table++ = oputV;
ncomp += 3;
castonly = 0;
if (ambounce > 0 && (ambacc > FTINY || ambssamp > 0))
error(WARNING,
"-otV accuracy depends on -aa 0 -as 0");
break;
case 'l': /* effective distance */
*table++ = oputl;
ncomp++;
castonly = 0;
break;
case 'c': /* local coordinates */
*table++ = oputc;
ncomp += 2;
break;
case 'L': /* single ray length */
*table++ = oputL;
ncomp++;
break;
case 'p': /* point */
*table++ = oputp;
ncomp += 3;
break;
case 'n': /* perturbed normal */
*table++ = oputn;
ncomp += 3;
castonly = 0;
break;
case 'N': /* unperturbed normal */
*table++ = oputN;
ncomp += 3;
break;
case 's': /* surface */
*table++ = oputs;
ncomp++;
break;
case 'w': /* weight */
*table++ = oputw;
ncomp++;
break;
case 'W': /* coefficient */
*table++ = oputW;
ncomp += 3;
castonly = 0;
if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0))
error(WARNING,
"-otW accuracy depends on -aa 0 -as 0");
break;
case 'm': /* modifier */
*table++ = oputm;
ncomp++;
break;
case 'M': /* material */
*table++ = oputM;
ncomp++;
break;
case '~': /* tilde */
*table++ = oputtilde;
break;
default:
sprintf(errmsg, "unrecognized output option '%c'", *vs);
error(USER, errmsg);
}
while (*++vs);
*table = NULL;
if (*every_out != NULL)
ncomp = 0;
/* compatibility */
if ((do_irrad | imm_irrad) && castonly)
error(USER, "-I+ and -i+ options require some value output");
for (table = ray_out; *table != NULL; table++) {
if ((*table == oputV) | (*table == oputW))
error(WARNING, "-oVW options require trace mode");
if ((do_irrad | imm_irrad) &&
(*table == oputr) | (*table == oputR) |
(*table == oputx) | (*table == oputX))
error(WARNING, "-orRxX options incompatible with -I+ and -i+");
}
return(ncomp);
}
static void
bogusray(void) /* print out empty record */
{
rayorigin(&thisray, PRIMARY, NULL, NULL);
printvals(&thisray);
}
static void
raycast( /* compute first ray intersection only */
RAY *r
)
{
if (!localhit(r, &thescene)) {
if (r->ro == &Aftplane) { /* clipped */
r->ro = NULL;
r->rot = FHUGE;
} else
sourcehit(r);
}
}
static void
rayirrad( /* compute irradiance rather than radiance */
RAY *r
)
{
void (*old_revf)(RAY *) = r->revf;
/* pretend we hit surface */
r->rxt = r->rot = 1e-5;
VSUM(r->rop, r->rorg, r->rdir, r->rot);
r->ron[0] = -r->rdir[0];
r->ron[1] = -r->rdir[1];
r->ron[2] = -r->rdir[2];
r->rod = 1.0;
/* compute result */
r->revf = raytrace;
(*ofun[Lamb.otype].funp)(&Lamb, r);
r->revf = old_revf;
}
static void
rtcompute( /* compute and print ray value(s) */
FVECT org,
FVECT dir,
double dmax
)
{
/* set up ray */
if (imm_irrad) {
VSUM(thisray.rorg, org, dir, 1.1e-4);
thisray.rdir[0] = -dir[0];
thisray.rdir[1] = -dir[1];
thisray.rdir[2] = -dir[2];
thisray.rmax = 0.0;
} else {
VCOPY(thisray.rorg, org);
VCOPY(thisray.rdir, dir);
thisray.rmax = dmax;
}
rayorigin(&thisray, PRIMARY, NULL, NULL);
if (imm_irrad)
thisray.revf = rayirrad;
else if (castonly)
thisray.revf = raycast;
if (ray_pnprocs > 1) { /* multiprocessing FIFO? */
if (ray_fifo_in(&thisray) < 0)
error(USER, "lost children");
return;
}
samplendx++; /* else do it ourselves */
rayvalue(&thisray);
printvals(&thisray);
}
static int
printvals( /* print requested ray values */
RAY *r
)
{
oputf_t **tp;
if (ray_out[0] == NULL)
return(0);
for (tp = ray_out; *tp != NULL; tp++)
(**tp)(r);
if (outform == 'a')
putchar('\n');
return(1);
}
static int
is_fifo( /* check if file pointer connected to pipe */
FILE *fp
)
{
#ifdef S_ISFIFO
struct stat sbuf;
if (fstat(fileno(fp), &sbuf) < 0)
error(SYSTEM, "fstat() failed on input stream");
return(S_ISFIFO(sbuf.st_mode));
#else
return (fp == stdin); /* just a guess, really */
#endif
}
static int
getvec( /* get a vector from fp */
FVECT vec,
int fmt,
FILE *fp
)
{
static float vf[3];
static double vd[3];
char buf[32];
int i;
switch (fmt) {
case 'a': /* ascii */
for (i = 0; i < 3; i++) {
if (fgetword(buf, sizeof(buf), fp) == NULL ||
!isflt(buf))
return(-1);
vec[i] = atof(buf);
}
break;
case 'f': /* binary float */
if (getbinary(vf, sizeof(float), 3, fp) != 3)
return(-1);
VCOPY(vec, vf);
break;
case 'd': /* binary double */
if (getbinary(vd, sizeof(double), 3, fp) != 3)
return(-1);
VCOPY(vec, vd);
break;
default:
error(CONSISTENCY, "botched input format");
}
return(0);
}
static int
iszerovec(const FVECT vec)
{
return (vec[0] == 0.0) & (vec[1] == 0.0) & (vec[2] == 0.0);
}
static double
nextray( /* return next ray in work group (-1.0 if EOF) */
FVECT org,
FVECT dir
)
{
const size_t qlength = !vresolu * hresolu;
if ((org == NULL) | (dir == NULL)) {
if (inp_queue != NULL) /* asking to free queue */
free(inp_queue);
inp_queue = NULL;
inp_qpos = inp_qend = 0;
return(-1.);
}
if (!inp_qend) { /* initialize FIFO queue */
int rsiz = 6*20; /* conservative ascii ray size */
if (inform == 'f') rsiz = 6*sizeof(float);
else if (inform == 'd') rsiz = 6*sizeof(double);
/* check against pipe limit */
if (qlength*rsiz > 512 && is_fifo(inpfp))
inp_queue = (FVECT *)malloc(sizeof(FVECT)*2*qlength);
inp_qend = -(inp_queue == NULL); /* flag for no queue */
}
if (inp_qend < 0) { /* not queuing? */
if (getvec(org, inform, inpfp) < 0 ||
getvec(dir, inform, inpfp) < 0)
return(-1.);
return normalize(dir);
}
if (inp_qpos >= inp_qend) { /* need to refill input queue? */
for (inp_qend = 0; inp_qend < qlength; inp_qend++) {
if (getvec(inp_queue[2*inp_qend], inform, inpfp) < 0
|| getvec(inp_queue[2*inp_qend+1],
inform, inpfp) < 0)
break; /* hit EOF */
if (iszerovec(inp_queue[2*inp_qend+1])) {
++inp_qend; /* flush request */
break;
}
}
inp_qpos = 0;
}
if (inp_qpos >= inp_qend) /* unexpected EOF? */
return(-1.);
VCOPY(org, inp_queue[2*inp_qpos]);
VCOPY(dir, inp_queue[2*inp_qpos+1]);
++inp_qpos;
return normalize(dir);
}
void
tranotify( /* record new modifier */
OBJECT obj
)
{
static int hitlimit = 0;
OBJREC *o = objptr(obj);
char **tralp;
if (obj == OVOID) { /* starting over */
traset[0] = 0;
hitlimit = 0;
return;
}
if (hitlimit || !ismodifier(o->otype))
return;
for (tralp = tralist; *tralp != NULL; tralp++)
if (!strcmp(o->oname, *tralp)) {
if (traset[0] >= MAXTSET) {
error(WARNING, "too many modifiers in trace list");
hitlimit++;
return; /* should this be fatal? */
}
insertelem(traset, obj);
return;
}
}
static void
ourtrace( /* print ray values */
RAY *r
)
{
oputf_t **tp;
if (every_out[0] == NULL)
return;
if (r->ro == NULL) {
if (traincl == 1)
return;
} else if (traincl != -1 && traincl != inset(traset, r->ro->omod))
return;
tabin(r);
for (tp = every_out; *tp != NULL; tp++)
(**tp)(r);
if (outform == 'a')
putchar('\n');
}
static void
tabin( /* tab in appropriate amount */
RAY *r
)
{
const RAY *rp;
for (rp = r->parent; rp != NULL; rp = rp->parent)
putchar('\t');
}
static void
oputo( /* print origin */
RAY *r
)
{
(*putreal)(r->rorg, 3);
}
static void
oputd( /* print direction */
RAY *r
)
{
(*putreal)(r->rdir, 3);
}
static void
oputr( /* print mirrored contribution */
RAY *r
)
{
RREAL cval[3];
cval[0] = colval(r->mcol,RED);
cval[1] = colval(r->mcol,GRN);
cval[2] = colval(r->mcol,BLU);
(*putreal)(cval, 3);
}
static void
oputR( /* print mirrored distance */
RAY *r
)
{
(*putreal)(&r->rmt, 1);
}
static void
oputx( /* print unmirrored contribution */
RAY *r
)
{
RREAL cval[3];
cval[0] = colval(r->rcol,RED) - colval(r->mcol,RED);
cval[1] = colval(r->rcol,GRN) - colval(r->mcol,GRN);
cval[2] = colval(r->rcol,BLU) - colval(r->mcol,BLU);
(*putreal)(cval, 3);
}
static void
oputX( /* print unmirrored distance */
RAY *r
)
{
(*putreal)(&r->rxt, 1);
}
static void
oputv( /* print value */
RAY *r
)
{
RREAL cval[3];
cval[0] = colval(r->rcol,RED);
cval[1] = colval(r->rcol,GRN);
cval[2] = colval(r->rcol,BLU);
(*putreal)(cval, 3);
}
static void
oputV( /* print value contribution */
RAY *r
)
{
RREAL contr[3];
raycontrib(contr, r, PRIMARY);
multcolor(contr, r->rcol);
(*putreal)(contr, 3);
}
static void
oputl( /* print effective distance */
RAY *r
)
{
RREAL d = raydistance(r);
(*putreal)(&d, 1);
}
static void
oputL( /* print single ray length */
RAY *r
)
{
(*putreal)(&r->rot, 1);
}
static void
oputc( /* print local coordinates */
RAY *r
)
{
(*putreal)(r->uv, 2);
}
static RREAL vdummy[3] = {0.0, 0.0, 0.0};
static void
oputp( /* print intersection point */
RAY *r
)
{
(*putreal)(r->rop, 3); /* set to ray origin if distant or no hit */
}
static void
oputN( /* print unperturbed normal */
RAY *r
)
{
if (r->ro == NULL) { /* zero vector if clipped or no hit */
(*putreal)(vdummy, 3);
return;
}
if (r->rflips & 1) { /* undo any flippin' flips */
FVECT unrm;
unrm[0] = -r->ron[0];
unrm[1] = -r->ron[1];
unrm[2] = -r->ron[2];
(*putreal)(unrm, 3);
} else
(*putreal)(r->ron, 3);
}
static void
oputn( /* print perturbed normal */
RAY *r
)
{
FVECT pnorm;
if (r->ro == NULL) { /* clipped or no hit */
(*putreal)(vdummy, 3);
return;
}
raynormal(pnorm, r);
(*putreal)(pnorm, 3);
}
static void
oputs( /* print name */
RAY *r
)
{
if (r->ro != NULL)
fputs(r->ro->oname, stdout);
else
putchar('*');
putchar('\t');
}
static void
oputw( /* print weight */
RAY *r
)
{
RREAL rwt = r->rweight;
(*putreal)(&rwt, 1);
}
static void
oputW( /* print coefficient */
RAY *r
)
{
RREAL contr[3];
/* shadow ray not on source? */
if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
setcolor(contr, 0.0, 0.0, 0.0);
else
raycontrib(contr, r, PRIMARY);
(*putreal)(contr, 3);
}
static void
oputm( /* print modifier */
RAY *r
)
{
if (r->ro != NULL)
if (r->ro->omod != OVOID)
fputs(objptr(r->ro->omod)->oname, stdout);
else
fputs(VOIDID, stdout);
else
putchar('*');
putchar('\t');
}
static void
oputM( /* print material */
RAY *r
)
{
OBJREC *mat;
if (r->ro != NULL) {
if ((mat = findmaterial(r->ro)) != NULL)
fputs(mat->oname, stdout);
else
fputs(VOIDID, stdout);
} else
putchar('*');
putchar('\t');
}
static void
oputtilde( /* output tilde (spacer) */
RAY *r
)
{
fputs("~\t", stdout);
}
static void
puta( /* print ascii value(s) */
RREAL *v, int n
)
{
if (n == 3) {
printf("%e\t%e\t%e\t", v[0], v[1], v[2]);
return;
}
while (n--)
printf("%e\t", *v++);
}
static void
putd(RREAL *v, int n) /* output binary double(s) */
{
#ifdef SMLFLT
double da[3];
int i;
if (n > 3)
error(INTERNAL, "code error in putd()");
for (i = n; i--; )
da[i] = v[i];
putbinary(da, sizeof(double), n, stdout);
#else
putbinary(v, sizeof(RREAL), n, stdout);
#endif
}
static void
putf(RREAL *v, int n) /* output binary float(s) */
{
#ifndef SMLFLT
float fa[3];
int i;
if (n > 3)
error(INTERNAL, "code error in putf()");
for (i = n; i--; )
fa[i] = v[i];
putbinary(fa, sizeof(float), n, stdout);
#else
putbinary(v, sizeof(RREAL), n, stdout);
#endif
}
static void
putrgbe(RREAL *v, int n) /* output RGBE color */
{
COLR cout;
if (n != 3)
error(INTERNAL, "putrgbe() not called with 3 components");
setcolr(cout, v[0], v[1], v[2]);
putbinary(cout, sizeof(cout), 1, stdout);
}
Event Timeline
Log In to Comment