--- ray/src/rt/rtrace.c 2020/04/03 17:06:16 2.89 +++ ray/src/rt/rtrace.c 2023/12/11 18:33:53 2.110 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: rtrace.c,v 2.89 2020/04/03 17:06:16 greg Exp $"; +static const char RCSid[] = "$Id: rtrace.c,v 2.110 2023/12/11 18:33:53 greg Exp $"; #endif /* * rtrace.c - program and variables for individual ray tracing. @@ -45,13 +45,19 @@ extern int traincl; /* include == 1, exclude == 0 * extern int hresolu; /* horizontal resolution */ extern int vresolu; /* vertical resolution */ -static int castonly = 0; +extern int castonly; /* only doing ray-casting? */ +extern double (*sens_curve)(SCOLOR scol); /* spectral conversion for 1-channel */ +extern double out_scalefactor; /* output calibration scale factor */ +extern RGBPRIMP out_prims; /* output color primitives (NULL if spectral) */ + #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 */ @@ -61,15 +67,15 @@ 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; +static putf_t puta, putd, putf; 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; -static void setoutput(char *vs); 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); @@ -81,6 +87,8 @@ static double nextray(FVECT org, FVECT dir); static void tabin(RAY *r); static void ourtrace(RAY *r); +static void putscolor(COLORV *scol); + static oputf_t *ray_out[32], *every_out[32]; static putf_t *putreal; @@ -92,8 +100,10 @@ quit( /* quit program */ { 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 if (!ray_pnprocs) { + else { headclean(); /* delete header file */ pfclean(); /* clean up persist files */ } @@ -102,7 +112,7 @@ quit( /* quit program */ } -char * +const char * formstr( /* return format identifier */ int f ) @@ -111,13 +121,28 @@ formstr( /* return format identifier */ case 'a': return("ascii"); case 'f': return("float"); case 'd': return("double"); - case 'c': return(COLRFMT); + case 'c': + if (out_prims == NULL) + return(SPECFMT); + if (out_prims == xyzprims) + return(CIEFMT); + return(COLRFMT); } return("unknown"); } -extern void +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 @@ -144,26 +169,17 @@ rtrace( /* trace rays from file */ if (inform != 'a') SET_FILE_BINARY(inpfp); /* set up output */ - setoutput(outvals); - if (imm_irrad) - castonly = 0; - else if (castonly) + if (castonly || every_out[0] != NULL) nproc = 1; /* don't bother multiprocessing */ + if (every_out[0] != NULL) { + trace = ourtrace; /* enable full tree tracing */ + if (Tflag) /* light sources, too? */ + trace_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[0] && (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; @@ -218,97 +234,121 @@ rtrace( /* trace rays from file */ } -static void -trace_sources(void) /* trace rays to light sources, also */ +int +setrtoutput(void) /* set up output tables, return #comp */ { - int sn; - - for (sn = 0; sn < nsources; sn++) - source[sn].sflags |= SFOLLOW; -} - - -static void -setoutput( /* set up output tables */ - char *vs -) -{ + char *vs = outvals; oputf_t **table = ray_out; + const int nco = (sens_curve != NULL) ? 1 : + (out_prims != NULL) ? 3 : NCSAMP; + int ncomp = 0; - castonly = 1; - while (*vs) - switch (*vs++) { + if (!*vs) + error(USER, "empty output specification"); + + switch (outform) { /* make sure (*putreal)() calls someone! */ + 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"); + if (nco < 3) + error(USER, "color format incompatible with -pY, -pS, -pM"); + break; + default: + error(CONSISTENCY, "botched output format"); + } + castonly = 1; /* sets castonly as side-effect */ + do + switch (*vs) { case 'T': /* trace sources */ - if (!*vs) break; - trace_sources(); + Tflag++; /* fall through */ case 't': /* trace */ - if (!*vs) break; + 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 += nco; castonly = 0; break; case 'R': /* reflected distance */ *table++ = oputR; + ncomp++; castonly = 0; break; case 'x': /* xmit contrib. */ *table++ = oputx; + ncomp += nco; castonly = 0; break; case 'X': /* xmit distance */ *table++ = oputX; + ncomp++; castonly = 0; break; case 'v': /* value */ *table++ = oputv; + ncomp += nco; castonly = 0; break; case 'V': /* contribution */ *table++ = oputV; + ncomp += nco; + 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 += nco; castonly = 0; if (ambounce > 0 && (ambacc > FTINY) | (ambssamp > 0)) error(WARNING, @@ -316,16 +356,27 @@ setoutput( /* set up output tables */ 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"); @@ -334,6 +385,7 @@ setoutput( /* set up output tables */ (*table == oputx) | (*table == oputX)) error(WARNING, "-orRxX options incompatible with -I+ and -i+"); } + return(ncomp); } @@ -388,21 +440,22 @@ rtcompute( /* compute and print ray value(s) */ ) { /* set up ray */ - rayorigin(&thisray, PRIMARY, NULL, NULL); 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; - thisray.revf = rayirrad; } else { VCOPY(thisray.rorg, org); VCOPY(thisray.rdir, dir); thisray.rmax = dmax; - if (castonly) - thisray.revf = raycast; } + 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"); @@ -432,6 +485,23 @@ printvals( /* print requested ray values */ 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, @@ -495,7 +565,8 @@ nextray( /* return next ray in work group (-1.0 if EO int rsiz = 6*20; /* conservative ascii ray size */ if (inform == 'f') rsiz = 6*sizeof(float); else if (inform == 'd') rsiz = 6*sizeof(double); - if ((inpfp == stdin) & (qlength*rsiz > 512)) /* pipe limit */ + /* 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 */ } @@ -637,12 +708,12 @@ oputx( /* print unmirrored contribution */ RAY *r ) { - RREAL cval[3]; + SCOLOR cdiff; - 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); + copyscolor(cdiff, r->rcol); + sopscolor(cdiff, -=, r->mcol); + + putscolor(cdiff); } @@ -660,12 +731,7 @@ 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); + putscolor(r->rcol); } @@ -674,11 +740,11 @@ oputV( /* print value contribution */ RAY *r ) { - RREAL contr[3]; + SCOLOR contr; raycontrib(contr, r, PRIMARY); - multcolor(contr, r->rcol); - (*putreal)(contr, 3); + smultscolor(contr, r->rcol); + putscolor(contr); } @@ -715,14 +781,11 @@ static RREAL vdummy[3] = {0.0, 0.0, 0.0}; static void -oputp( /* print point */ +oputp( /* print intersection point */ RAY *r ) { - if (r->rot < FHUGE*.99) - (*putreal)(r->rop, 3); - else - (*putreal)(vdummy, 3); + (*putreal)(r->rop, 3); /* set to ray origin if distant or no hit */ } @@ -731,17 +794,18 @@ oputN( /* print unperturbed normal */ RAY *r ) { - if (r->rot < FHUGE*.99) { - 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); - } else + 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); } @@ -752,7 +816,7 @@ oputn( /* print perturbed normal */ { FVECT pnorm; - if (r->rot >= FHUGE*.99) { + if (r->ro == NULL) { /* clipped or no hit */ (*putreal)(vdummy, 3); return; } @@ -790,14 +854,14 @@ oputW( /* print coefficient */ RAY *r ) { - RREAL contr[3]; + SCOLOR contr; /* shadow ray not on source? */ if (r->rsrc >= 0 && source[r->rsrc].so != r->ro) - setcolor(contr, 0.0, 0.0, 0.0); + scolorblack(contr); else raycontrib(contr, r, PRIMARY); - (*putreal)(contr, 3); + putscolor(contr); } @@ -862,10 +926,10 @@ static void putd(RREAL *v, int n) /* output binary double(s) */ { #ifdef SMLFLT - double da[3]; + double da[MAXCSAMP]; int i; - if (n > 3) + if (n > MAXCSAMP) error(INTERNAL, "code error in putd()"); for (i = n; i--; ) da[i] = v[i]; @@ -880,10 +944,10 @@ static void putf(RREAL *v, int n) /* output binary float(s) */ { #ifndef SMLFLT - float fa[3]; + float fa[MAXCSAMP]; int i; - if (n > 3) + if (n > MAXCSAMP) error(INTERNAL, "code error in putf()"); for (i = n; i--; ) fa[i] = v[i]; @@ -895,12 +959,56 @@ putf(RREAL *v, int n) /* output binary float(s) */ static void -putrgbe(RREAL *v, int n) /* output RGBE color */ +putscolor(COLORV *scol) /* output (spectral) 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); + static COLORMAT xyz2myrgbmat; + SCOLOR my_scol; + COLOR col; + /* apply scalefactor if any */ + if (out_scalefactor != 1.) { + copyscolor(my_scol, scol); + scalescolor(my_scol, out_scalefactor); + scol = my_scol; + } + if (sens_curve != NULL) { /* single channel output */ + RREAL v = (*sens_curve)(scol); + (*putreal)(&v, 1); + return; + } + if (out_prims == NULL) { /* full spectral reporting */ + if (outform == 'c') { + SCOLR sclr; + scolor_scolr(sclr, scol); + putbinary(sclr, LSCOLR, 1, stdout); + } else if (sizeof(RREAL) != sizeof(COLORV)) { + RREAL sreal[MAXCSAMP]; + int i = NCSAMP; + while (i--) sreal[i] = scol[i]; + (*putreal)(sreal, NCSAMP); + } else + (*putreal)((RREAL *)scol, NCSAMP); + return; + } + if (out_prims == xyzprims) { + scolor_cie(col, scol); + } else if (out_prims == stdprims) { + scolor_rgb(col, scol); + } else { + COLOR xyz; + if (xyz2myrgbmat[0][0] == 0) + compxyz2rgbWBmat(xyz2myrgbmat, out_prims); + scolor_cie(xyz, scol); + colortrans(col, xyz2myrgbmat, xyz); + clipgamut(col, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite); + } + if (outform == 'c') { + COLR clr; + setcolr(clr, colval(col,RED), colval(col,GRN), colval(col,BLU)); + putbinary(clr, sizeof(COLR), 1, stdout); + } else if (sizeof(RREAL) != sizeof(COLORV)) { + RREAL creal[3]; + copycolor(creal, col); + (*putreal)(creal, 3); + } else + (*putreal)((RREAL *)col, 3); }