--- ray/src/rt/ambient.c 2003/02/22 02:07:28 2.47
+++ ray/src/rt/ambient.c 2014/05/09 23:08:50 2.88
@@ -1,5 +1,5 @@
#ifndef lint
-static const char RCSid[] = "$Id: ambient.c,v 2.47 2003/02/22 02:07:28 greg Exp $";
+static const char RCSid[] = "$Id: ambient.c,v 2.88 2014/05/09 23:08:50 greg Exp $";
#endif
/*
* ambient.c - routines dealing with ambient (inter-reflected) component.
@@ -7,69 +7,15 @@ static const char RCSid[] = "$Id: ambient.c,v 2.47 200
* Declarations of external symbols in ambient.h
*/
-/* ====================================================================
- * The Radiance Software License, Version 1.0
- *
- * Copyright (c) 1990 - 2002 The Regents of the University of California,
- * through Lawrence Berkeley National Laboratory. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes Radiance software
- * (http://radsite.lbl.gov/)
- * developed by the Lawrence Berkeley National Laboratory
- * (http://www.lbl.gov/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
- * and "The Regents of the University of California" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact radiance@radsite.lbl.gov.
- *
- * 5. Products derived from this software may not be called "Radiance",
- * nor may "Radiance" appear in their name, without prior written
- * permission of Lawrence Berkeley National Laboratory.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of Lawrence Berkeley National Laboratory. For more
- * information on Lawrence Berkeley National Laboratory, please see
- * .
- */
+#include "copyright.h"
-#include "ray.h"
+#include
+#include "platform.h"
+#include "ray.h"
#include "otypes.h"
-
+#include "resolu.h"
#include "ambient.h"
-
#include "random.h"
#ifndef OCTSCALE
@@ -78,7 +24,9 @@ static const char RCSid[] = "$Id: ambient.c,v 2.47 200
extern char *shm_boundary; /* memory sharing boundary */
-#define MAXASET 511 /* maximum number of elements in ambient set */
+#ifndef MAXASET
+#define MAXASET 4095 /* maximum number of elements in ambient set */
+#endif
OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
double maxarad; /* maximum ambient radius */
@@ -90,10 +38,10 @@ static FILE *ambfp = NULL; /* ambient file pointer */
static int nunflshed = 0; /* number of unflushed ambient values */
#ifndef SORT_THRESH
-#ifdef BIGMEM
-#define SORT_THRESH ((9L<<20)/sizeof(AMBVAL))
+#ifdef SMLMEM
+#define SORT_THRESH ((16L<<20)/sizeof(AMBVAL))
#else
-#define SORT_THRESH ((3L<<20)/sizeof(AMBVAL))
+#define SORT_THRESH ((64L<<20)/sizeof(AMBVAL))
#endif
#endif
#ifndef SORT_INTVL
@@ -103,6 +51,7 @@ static int nunflshed = 0; /* number of unflushed ambi
#define MAX_SORT_INTVL (SORT_INTVL<<6)
#endif
+
static double avsum = 0.; /* computed ambient value sum (log) */
static unsigned int navsum = 0; /* number of values in avsum */
static unsigned int nambvals = 0; /* total number of indirect values */
@@ -130,55 +79,71 @@ static long lastpos = -1; /* last flush position */
#define newambval() (AMBVAL *)malloc(sizeof(AMBVAL))
#define freeav(av) free((void *)av);
-static void initambfile(), avsave(), avinsert(), sortambvals(), unloadatree();
-static int avlmemi();
-static AMBVAL *avstore();
+static void initambfile(int creat);
+static void avsave(AMBVAL *av);
+static AMBVAL *avstore(AMBVAL *aval);
+static AMBTREE *newambtree(void);
+static void freeambtree(AMBTREE *atp);
+
+typedef void unloadtf_t(AMBVAL *);
+static unloadtf_t avinsert;
+static unloadtf_t av2list;
+static unloadtf_t avfree;
+static void unloadatree(AMBTREE *at, unloadtf_t *f);
+
+static int aposcmp(const void *avp1, const void *avp2);
+static int avlmemi(AMBVAL *avaddr);
+static void sortambvals(int always);
+
#ifdef F_SETLKW
-static void aflock();
+static void aflock(int typ);
#endif
void
-setambres(ar) /* set ambient resolution */
-int ar;
+setambres( /* set ambient resolution */
+ int ar
+)
{
ambres = ar < 0 ? 0 : ar; /* may be done already */
/* set min & max radii */
if (ar <= 0) {
minarad = 0;
- maxarad = thescene.cusize / 2.0;
+ maxarad = thescene.cusize*0.5;
} else {
minarad = thescene.cusize / ar;
- maxarad = 64 * minarad; /* heuristic */
- if (maxarad > thescene.cusize / 2.0)
- maxarad = thescene.cusize / 2.0;
+ maxarad = 64.0 * minarad; /* heuristic */
+ if (maxarad > thescene.cusize*0.5)
+ maxarad = thescene.cusize*0.5;
}
if (minarad <= FTINY)
- minarad = 10*FTINY;
+ minarad = 10.0*FTINY;
if (maxarad <= minarad)
- maxarad = 64 * minarad;
+ maxarad = 64.0 * minarad;
}
void
-setambacc(newa) /* set ambient accuracy */
-double newa;
+setambacc( /* set ambient accuracy */
+ double newa
+)
{
- double ambdiff;
-
- if (newa < 0.0)
- newa = 0.0;
- ambdiff = fabs(newa - ambacc);
- if (ambdiff >= .01 && (ambacc = newa) > FTINY && nambvals > 0)
- sortambvals(1); /* rebuild tree */
+ static double olda; /* remember previous setting here */
+
+ newa *= (newa > 0);
+ if (fabs(newa - olda) >= .05*(newa + olda)) {
+ ambacc = newa;
+ if (nambvals > 0)
+ sortambvals(1); /* rebuild tree */
+ }
}
void
-setambient() /* initialize calculation */
+setambient(void) /* initialize calculation */
{
int readonly = 0;
- long pos, flen;
+ long flen;
AMBVAL amb;
/* make sure we're fresh */
ambdone();
@@ -198,9 +163,9 @@ setambient() /* initialize calculation */
readonly = (ambfp = fopen(ambfile, "r")) != NULL;
if (ambfp != NULL) {
initambfile(0); /* file exists */
- pos = ftell(ambfp);
+ lastpos = ftell(ambfp);
while (readambval(&amb, ambfp))
- avinsert(avstore(&amb));
+ avstore(&amb);
nambshare = nambvals; /* share loaded values */
if (readonly) {
sprintf(errmsg,
@@ -212,29 +177,37 @@ setambient() /* initialize calculation */
return; /* avoid ambsync() */
}
/* align file pointer */
- pos += (long)nambvals*AMBVALSIZ;
- flen = lseek(fileno(ambfp), (off_t)0L, 2);
- if (flen != pos) {
+ lastpos += (long)nambvals*AMBVALSIZ;
+ flen = lseek(fileno(ambfp), (off_t)0, SEEK_END);
+ if (flen != lastpos) {
sprintf(errmsg,
"ignoring last %ld values in ambient file (corrupted)",
- (flen - pos)/AMBVALSIZ);
+ (flen - lastpos)/AMBVALSIZ);
error(WARNING, errmsg);
- fseek(ambfp, pos, 0);
- ftruncate(fileno(ambfp), (off_t)pos);
+ fseek(ambfp, lastpos, SEEK_SET);
+#ifndef _WIN32 /* XXX we need a replacement for that one */
+ ftruncate(fileno(ambfp), (off_t)lastpos);
+#endif
}
} else if ((ambfp = fopen(ambfile, "w+")) != NULL) {
initambfile(1); /* else create new file */
+ fflush(ambfp);
+ lastpos = ftell(ambfp);
} else {
sprintf(errmsg, "cannot open ambient file \"%s\"", ambfile);
error(SYSTEM, errmsg);
}
- nunflshed++; /* lie */
- ambsync();
+#ifdef getc_unlocked
+ flockfile(ambfp); /* application-level lock */
+#endif
+#ifdef F_SETLKW
+ aflock(F_UNLCK); /* release file */
+#endif
}
void
-ambdone() /* close ambient file and free memory */
+ambdone(void) /* close ambient file and free memory */
{
if (ambfp != NULL) { /* close ambient file */
ambsync();
@@ -247,7 +220,7 @@ ambdone() /* close ambient file and free memory */
lastpos = -1;
}
/* free ambient tree */
- unloadatree(&atrunk, free);
+ unloadatree(&atrunk, &avfree);
/* reset state variables */
avsum = 0.;
navsum = 0;
@@ -260,12 +233,13 @@ ambdone() /* close ambient file and free memory */
void
-ambnotify(obj) /* record new modifier */
-OBJECT obj;
+ambnotify( /* record new modifier */
+ OBJECT obj
+)
{
static int hitlimit = 0;
- register OBJREC *o;
- register char **amblp;
+ OBJREC *o;
+ char **amblp;
if (obj == OVOID) { /* starting over */
ambset[0] = 0;
@@ -287,14 +261,29 @@ OBJECT obj;
}
}
+/************ THE FOLLOWING ROUTINES DIFFER BETWEEN NEW & OLD ***************/
+#ifdef NEWAMB
+
+#define tfunc(lwr, x, upr) (((x)-(lwr))/((upr)-(lwr)))
+
+static int plugaleak(RAY *r, AMBVAL *ap, FVECT anorm, double ang);
+static double sumambient(COLOR acol, RAY *r, FVECT rn, int al,
+ AMBTREE *at, FVECT c0, double s);
+static int makeambient(COLOR acol, RAY *r, FVECT rn, int al);
+static void extambient(COLOR cr, AMBVAL *ap, FVECT pv, FVECT nv,
+ FVECT uvw[3]);
+
void
-ambient(acol, r, nrm) /* compute ambient component for ray */
-COLOR acol;
-register RAY *r;
-FVECT nrm;
+multambient( /* compute ambient component & multiply by coef. */
+ COLOR aval,
+ RAY *r,
+ FVECT nrm
+)
{
static int rdepth = 0; /* ambient recursion */
+ COLOR acol;
+ int ok;
double d, l;
if (ambdiv <= 0) /* no ambient calculation */
@@ -308,62 +297,421 @@ FVECT nrm;
goto dumbamb;
if (ambacc <= FTINY) { /* no ambient storage */
+ copycolor(acol, aval);
rdepth++;
+ ok = doambient(acol, r, r->rweight,
+ NULL, NULL, NULL, NULL, NULL);
+ rdepth--;
+ if (!ok)
+ goto dumbamb;
+ copycolor(aval, acol);
+ return;
+ }
+
+ if (tracktime) /* sort to minimize thrashing */
+ sortambvals(0);
+ /* interpolate ambient value */
+ setcolor(acol, 0.0, 0.0, 0.0);
+ d = sumambient(acol, r, nrm, rdepth,
+ &atrunk, thescene.cuorg, thescene.cusize);
+ if (d > FTINY) {
+ d = 1.0/d;
+ scalecolor(acol, d);
+ multcolor(aval, acol);
+ return;
+ }
+ rdepth++; /* need to cache new value */
+ ok = makeambient(acol, r, nrm, rdepth-1);
+ rdepth--;
+ if (ok) {
+ multcolor(aval, acol); /* computed new value */
+ return;
+ }
+dumbamb: /* return global value */
+ if ((ambvwt <= 0) | (navsum == 0)) {
+ multcolor(aval, ambval);
+ return;
+ }
+ l = bright(ambval); /* average in computations */
+ if (l > FTINY) {
+ d = (log(l)*(double)ambvwt + avsum) /
+ (double)(ambvwt + navsum);
+ d = exp(d) / l;
+ scalecolor(aval, d);
+ multcolor(aval, ambval); /* apply color of ambval */
+ } else {
+ d = exp( avsum / (double)navsum );
+ scalecolor(aval, d); /* neutral color */
+ }
+}
+
+
+/* Plug a potential leak where ambient cache value is occluded */
+static int
+plugaleak(RAY *r, AMBVAL *ap, FVECT anorm, double ang)
+{
+ const double cost70sq = 0.1169778; /* cos(70deg)^2 */
+ RAY rtst;
+ FVECT vdif;
+ double normdot, ndotd, nadotd;
+ double a, b, c, t[2];
+
+ ang += 2.*PI*(ang < 0); /* check direction flags */
+ if ( !(ap->corral>>(int)(ang*(16./PI)) & 1) )
+ return(0);
+ /*
+ * Generate test ray, targeting 20 degrees above sample point plane
+ * along surface normal from cache position. This should be high
+ * enough to miss local geometry we don't really care about.
+ */
+ VSUB(vdif, ap->pos, r->rop);
+ normdot = DOT(anorm, r->ron);
+ ndotd = DOT(vdif, r->ron);
+ nadotd = DOT(vdif, anorm);
+ a = normdot*normdot - cost70sq;
+ b = 2.0*(normdot*ndotd - nadotd*cost70sq);
+ c = ndotd*ndotd - DOT(vdif,vdif)*cost70sq;
+ if (quadratic(t, a, b, c) != 2)
+ return(1); /* should rarely happen */
+ if (t[1] <= FTINY)
+ return(0); /* should fail behind test */
+ rayorigin(&rtst, SHADOW, r, NULL);
+ VSUM(rtst.rdir, vdif, anorm, t[1]); /* further dist. > plane */
+ rtst.rmax = normalize(rtst.rdir); /* short ray test */
+ while (localhit(&rtst, &thescene)) { /* check for occluder */
+ if (rtst.ro->omod != OVOID &&
+ (rtst.clipset == NULL ||
+ !inset(rtst.clipset, rtst.ro->omod)))
+ return(1); /* plug light leak */
+ VCOPY(rtst.rorg, rtst.rop); /* skip invisible surface */
+ rtst.rmax -= rtst.rot;
+ rayclear(&rtst);
+ }
+ return(0); /* seems we're OK */
+}
+
+
+static double
+sumambient( /* get interpolated ambient value */
+ COLOR acol,
+ RAY *r,
+ FVECT rn,
+ int al,
+ AMBTREE *at,
+ FVECT c0,
+ double s
+)
+{ /* initial limit is 10 degrees plus ambacc radians */
+ const double minangle = 10.0 * PI/180.;
+ double maxangle = minangle + ambacc;
+ double wsum = 0.0;
+ FVECT ck0;
+ int i, j;
+ AMBVAL *av;
+
+ if (at->kid != NULL) { /* sum children first */
+ s *= 0.5;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 3; j++) {
+ ck0[j] = c0[j];
+ if (1<rop[j] < ck0[j] - OCTSCALE*s)
+ break;
+ if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
+ break;
+ }
+ if (j == 3)
+ wsum += sumambient(acol, r, rn, al,
+ at->kid+i, ck0, s);
+ }
+ /* good enough? */
+ if (wsum >= 0.05 && s > minarad*10.0)
+ return(wsum);
+ }
+ /* adjust maximum angle */
+ if (at->alist != NULL && (at->alist->lvl <= al) & (r->rweight < 0.6))
+ maxangle = (maxangle - PI/2.)*pow(r->rweight,0.13) + PI/2.;
+ /* sum this node */
+ for (av = at->alist; av != NULL; av = av->next) {
+ double u, v, d, delta_r2, delta_t2;
+ COLOR ct;
+ FVECT uvw[3];
+ /* record access */
+ if (tracktime)
+ av->latick = ambclock;
+ /*
+ * Ambient level test
+ */
+ if (av->lvl > al || /* list sorted, so this works */
+ (av->lvl == al) & (av->weight < 0.9*r->rweight))
+ break;
+ /*
+ * Direction test using unperturbed normal
+ */
+ decodedir(uvw[2], av->ndir);
+ d = DOT(uvw[2], r->ron);
+ if (d <= 0.0) /* >= 90 degrees */
+ continue;
+ delta_r2 = 2.0 - 2.0*d; /* approx. radians^2 */
+ if (delta_r2 >= maxangle*maxangle)
+ continue;
+ /*
+ * Modified ray behind test
+ */
+ VSUB(ck0, r->rop, av->pos);
+ d = DOT(ck0, uvw[2]);
+ if (d < -minarad*ambacc-.001)
+ continue;
+ d /= av->rad[0];
+ delta_t2 = d*d;
+ if (delta_t2 >= ambacc*ambacc)
+ continue;
+ /*
+ * Elliptical radii test based on Hessian
+ */
+ decodedir(uvw[0], av->udir);
+ VCROSS(uvw[1], uvw[2], uvw[0]);
+ d = (u = DOT(ck0, uvw[0])) / av->rad[0];
+ delta_t2 += d*d;
+ d = (v = DOT(ck0, uvw[1])) / av->rad[1];
+ delta_t2 += d*d;
+ if (delta_t2 >= ambacc*ambacc)
+ continue;
+ /*
+ * Test for potential light leak
+ */
+ if (av->corral && plugaleak(r, av, uvw[2], atan2a(v,u)))
+ continue;
+ /*
+ * Extrapolate value and compute final weight (hat function)
+ */
+ extambient(ct, av, r->rop, rn, uvw);
+ d = tfunc(maxangle, sqrt(delta_r2), 0.0) *
+ tfunc(ambacc, sqrt(delta_t2), 0.0);
+ scalecolor(ct, d);
+ addcolor(acol, ct);
+ wsum += d;
+ }
+ return(wsum);
+}
+
+
+static int
+makeambient( /* make a new ambient value for storage */
+ COLOR acol,
+ RAY *r,
+ FVECT rn,
+ int al
+)
+{
+ AMBVAL amb;
+ FVECT uvw[3];
+ int i;
+
+ amb.weight = 1.0; /* compute weight */
+ for (i = al; i-- > 0; )
+ amb.weight *= AVGREFL;
+ if (r->rweight < 0.1*amb.weight) /* heuristic override */
+ amb.weight = 1.25*r->rweight;
+ setcolor(acol, AVGREFL, AVGREFL, AVGREFL);
+ /* compute ambient */
+ i = doambient(acol, r, amb.weight,
+ uvw, amb.rad, amb.gpos, amb.gdir, &amb.corral);
+ scalecolor(acol, 1./AVGREFL); /* undo assumed reflectance */
+ if (i <= 0 || amb.rad[0] <= FTINY) /* no Hessian or zero radius */
+ return(i);
+ /* store value */
+ VCOPY(amb.pos, r->rop);
+ amb.ndir = encodedir(r->ron);
+ amb.udir = encodedir(uvw[0]);
+ amb.lvl = al;
+ copycolor(amb.val, acol);
+ /* insert into tree */
+ avsave(&amb); /* and save to file */
+ if (rn != r->ron) { /* texture */
+ VCOPY(uvw[2], r->ron);
+ extambient(acol, &amb, r->rop, rn, uvw);
+ }
+ return(1);
+}
+
+
+static void
+extambient( /* extrapolate value at pv, nv */
+ COLOR cr,
+ AMBVAL *ap,
+ FVECT pv,
+ FVECT nv,
+ FVECT uvw[3]
+)
+{
+ static FVECT my_uvw[3];
+ FVECT v1;
+ int i;
+ double d = 1.0; /* zeroeth order */
+
+ if (uvw == NULL) { /* need local coordinates? */
+ decodedir(my_uvw[2], ap->ndir);
+ decodedir(my_uvw[0], ap->udir);
+ VCROSS(my_uvw[1], my_uvw[2], my_uvw[0]);
+ uvw = my_uvw;
+ }
+ for (i = 3; i--; ) /* gradient due to translation */
+ d += (pv[i] - ap->pos[i]) *
+ (ap->gpos[0]*uvw[0][i] + ap->gpos[1]*uvw[1][i]);
+
+ VCROSS(v1, uvw[2], nv); /* gradient due to rotation */
+ for (i = 3; i--; )
+ d += v1[i] * (ap->gdir[0]*uvw[0][i] + ap->gdir[1]*uvw[1][i]);
+
+ if (d <= 0.0) {
+ setcolor(cr, 0.0, 0.0, 0.0);
+ return;
+ }
+ copycolor(cr, ap->val);
+ scalecolor(cr, d);
+}
+
+
+static void
+avinsert( /* insert ambient value in our tree */
+ AMBVAL *av
+)
+{
+ AMBTREE *at;
+ AMBVAL *ap;
+ AMBVAL avh;
+ FVECT ck0;
+ double s;
+ int branch;
+ int i;
+
+ if (av->rad[0] <= FTINY)
+ error(CONSISTENCY, "zero ambient radius in avinsert");
+ at = &atrunk;
+ VCOPY(ck0, thescene.cuorg);
+ s = thescene.cusize;
+ while (s*(OCTSCALE/2) > av->rad[1]*ambacc) {
+ if (at->kid == NULL)
+ if ((at->kid = newambtree()) == NULL)
+ error(SYSTEM, "out of memory in avinsert");
+ s *= 0.5;
+ branch = 0;
+ for (i = 0; i < 3; i++)
+ if (av->pos[i] > ck0[i] + s) {
+ ck0[i] += s;
+ branch |= 1 << i;
+ }
+ at = at->kid + branch;
+ }
+ avh.next = at->alist; /* order by increasing level */
+ for (ap = &avh; ap->next != NULL; ap = ap->next)
+ if ( ap->next->lvl > av->lvl ||
+ (ap->next->lvl == av->lvl) &
+ (ap->next->weight <= av->weight) )
+ break;
+ av->next = ap->next;
+ ap->next = (AMBVAL*)av;
+ at->alist = avh.next;
+}
+
+
+#else /* ! NEWAMB */
+
+static double sumambient(COLOR acol, RAY *r, FVECT rn, int al,
+ AMBTREE *at, FVECT c0, double s);
+static double makeambient(COLOR acol, RAY *r, FVECT rn, int al);
+static void extambient(COLOR cr, AMBVAL *ap, FVECT pv, FVECT nv);
+
+
+void
+multambient( /* compute ambient component & multiply by coef. */
+ COLOR aval,
+ RAY *r,
+ FVECT nrm
+)
+{
+ static int rdepth = 0; /* ambient recursion */
+ COLOR acol;
+ double d, l;
+
+ if (ambdiv <= 0) /* no ambient calculation */
+ goto dumbamb;
+ /* check number of bounces */
+ if (rdepth >= ambounce)
+ goto dumbamb;
+ /* check ambient list */
+ if (ambincl != -1 && r->ro != NULL &&
+ ambincl != inset(ambset, r->ro->omod))
+ goto dumbamb;
+
+ if (ambacc <= FTINY) { /* no ambient storage */
+ copycolor(acol, aval);
+ rdepth++;
d = doambient(acol, r, r->rweight, NULL, NULL);
rdepth--;
if (d <= FTINY)
goto dumbamb;
+ copycolor(aval, acol);
return;
}
if (tracktime) /* sort to minimize thrashing */
sortambvals(0);
- /* get ambient value */
+ /* interpolate ambient value */
setcolor(acol, 0.0, 0.0, 0.0);
d = sumambient(acol, r, nrm, rdepth,
&atrunk, thescene.cuorg, thescene.cusize);
if (d > FTINY) {
- scalecolor(acol, 1.0/d);
+ d = 1.0/d;
+ scalecolor(acol, d);
+ multcolor(aval, acol);
return;
}
rdepth++; /* need to cache new value */
d = makeambient(acol, r, nrm, rdepth-1);
rdepth--;
- if (d > FTINY)
+ if (d > FTINY) {
+ multcolor(aval, acol); /* got new value */
return;
+ }
dumbamb: /* return global value */
- copycolor(acol, ambval);
- if (ambvwt <= 0 | navsum == 0)
+ if ((ambvwt <= 0) | (navsum == 0)) {
+ multcolor(aval, ambval);
return;
+ }
l = bright(ambval); /* average in computations */
if (l > FTINY) {
d = (log(l)*(double)ambvwt + avsum) /
(double)(ambvwt + navsum);
d = exp(d) / l;
- scalecolor(acol, d); /* apply color of ambval */
+ scalecolor(aval, d);
+ multcolor(aval, ambval); /* apply color of ambval */
} else {
d = exp( avsum / (double)navsum );
- setcolor(acol, d, d, d); /* neutral color */
+ scalecolor(aval, d); /* neutral color */
}
}
-double
-sumambient(acol, r, rn, al, at, c0, s) /* get interpolated ambient value */
-COLOR acol;
-register RAY *r;
-FVECT rn;
-int al;
-AMBTREE *at;
-FVECT c0;
-double s;
+static double
+sumambient( /* get interpolated ambient value */
+ COLOR acol,
+ RAY *r,
+ FVECT rn,
+ int al,
+ AMBTREE *at,
+ FVECT c0,
+ double s
+)
{
double d, e1, e2, wt, wsum;
COLOR ct;
FVECT ck0;
int i;
- register int j;
- register AMBVAL *av;
+ int j;
+ AMBVAL *av;
wsum = 0.0;
/* do this node */
@@ -374,20 +722,14 @@ double s;
/*
* Ambient level test.
*/
- if (av->lvl > al) /* list sorted, so this works */
+ if (av->lvl > al || /* list sorted, so this works */
+ (av->lvl == al) & (av->weight < 0.9*r->rweight))
break;
- if (av->weight < r->rweight-FTINY)
- continue;
/*
* Ambient radius test.
*/
- d = av->pos[0] - r->rop[0];
- e1 = d * d;
- d = av->pos[1] - r->rop[1];
- e1 += d * d;
- d = av->pos[2] - r->rop[2];
- e1 += d * d;
- e1 /= av->rad * av->rad;
+ VSUB(ck0, av->pos, r->rop);
+ e1 = DOT(ck0, ck0) / (av->rad * av->rad);
if (e1 > ambacc*ambacc*1.21)
continue;
/*
@@ -404,8 +746,9 @@ double s;
}
}
e2 = (1.0 - d) * r->rweight;
- if (e2 < 0.0) e2 = 0.0;
- if (e1 + e2 > ambacc*ambacc*1.21)
+ if (e2 < 0.0)
+ e2 = 0.0;
+ else if (e1 + e2 > ambacc*ambacc*1.21)
continue;
/*
* Ray behind test.
@@ -455,30 +798,39 @@ double s;
break;
}
if (j == 3)
- wsum += sumambient(acol, r, rn, al, at->kid+i, ck0, s);
+ wsum += sumambient(acol, r, rn, al,
+ at->kid+i, ck0, s);
}
return(wsum);
}
-double
-makeambient(acol, r, rn, al) /* make a new ambient value */
-COLOR acol;
-register RAY *r;
-FVECT rn;
-int al;
+static double
+makeambient( /* make a new ambient value for storage */
+ COLOR acol,
+ RAY *r,
+ FVECT rn,
+ int al
+)
{
AMBVAL amb;
FVECT gp, gd;
- /* compute weight */
- amb.weight = pow(AVGREFL, (double)al);
- if (r->rweight < 0.1*amb.weight) /* heuristic */
- amb.weight = r->rweight;
+ int i;
+
+ amb.weight = 1.0; /* compute weight */
+ for (i = al; i-- > 0; )
+ amb.weight *= AVGREFL;
+ if (r->rweight < 0.1*amb.weight) /* heuristic override */
+ amb.weight = 1.25*r->rweight;
+ setcolor(acol, AVGREFL, AVGREFL, AVGREFL);
/* compute ambient */
amb.rad = doambient(acol, r, amb.weight, gp, gd);
- if (amb.rad <= FTINY)
+ if (amb.rad <= FTINY) {
+ setcolor(acol, 0.0, 0.0, 0.0);
return(0.0);
- /* store it */
+ }
+ scalecolor(acol, 1./AVGREFL); /* undo assumed reflectance */
+ /* store value */
VCOPY(amb.pos, r->rop);
VCOPY(amb.dir, r->ron);
amb.lvl = al;
@@ -493,14 +845,16 @@ int al;
}
-void
-extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
-COLOR cr;
-register AMBVAL *ap;
-FVECT pv, nv;
+static void
+extambient( /* extrapolate value at pv, nv */
+ COLOR cr,
+ AMBVAL *ap,
+ FVECT pv,
+ FVECT nv
+)
{
FVECT v1;
- register int i;
+ int i;
double d;
d = 1.0; /* zeroeth order */
@@ -520,22 +874,67 @@ FVECT pv, nv;
static void
-initambfile(creat) /* initialize ambient file */
-int creat;
+avinsert( /* insert ambient value in our tree */
+ AMBVAL *av
+)
{
+ AMBTREE *at;
+ AMBVAL *ap;
+ AMBVAL avh;
+ FVECT ck0;
+ double s;
+ int branch;
+ int i;
+
+ if (av->rad <= FTINY)
+ error(CONSISTENCY, "zero ambient radius in avinsert");
+ at = &atrunk;
+ VCOPY(ck0, thescene.cuorg);
+ s = thescene.cusize;
+ while (s*(OCTSCALE/2) > av->rad*ambacc) {
+ if (at->kid == NULL)
+ if ((at->kid = newambtree()) == NULL)
+ error(SYSTEM, "out of memory in avinsert");
+ s *= 0.5;
+ branch = 0;
+ for (i = 0; i < 3; i++)
+ if (av->pos[i] > ck0[i] + s) {
+ ck0[i] += s;
+ branch |= 1 << i;
+ }
+ at = at->kid + branch;
+ }
+ avh.next = at->alist; /* order by increasing level */
+ for (ap = &avh; ap->next != NULL; ap = ap->next)
+ if ( ap->next->lvl > av->lvl ||
+ (ap->next->lvl == av->lvl) &
+ (ap->next->weight <= av->weight) )
+ break;
+ av->next = ap->next;
+ ap->next = (AMBVAL*)av;
+ at->alist = avh.next;
+}
+
+#endif /* ! NEWAMB */
+
+/************* FOLLOWING ROUTINES SAME FOR NEW & OLD METHODS ***************/
+
+static void
+initambfile( /* initialize ambient file */
+ int cre8
+)
+{
extern char *progname, *octname;
static char *mybuf = NULL;
#ifdef F_SETLKW
- aflock(creat ? F_WRLCK : F_RDLCK);
+ aflock(cre8 ? F_WRLCK : F_RDLCK);
#endif
-#ifdef MSDOS
- setmode(fileno(ambfp), O_BINARY);
-#endif
+ SET_FILE_BINARY(ambfp);
if (mybuf == NULL)
mybuf = (char *)bmalloc(BUFSIZ+8);
setbuf(ambfp, mybuf);
- if (creat) { /* new file */
+ if (cre8) { /* new file */
newheader("RADIANCE", ambfp);
fprintf(ambfp, "%s -av %g %g %g -aw %d -ab %d -aa %g ",
progname, colval(ambval,RED),
@@ -544,13 +943,12 @@ int creat;
fprintf(ambfp, "-ad %d -as %d -ar %d ",
ambdiv, ambssamp, ambres);
if (octname != NULL)
- printargs(1, &octname, ambfp);
- else
- fputc('\n', ambfp);
+ fputs(octname, ambfp);
+ fputc('\n', ambfp);
fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
fputnow(ambfp);
fputformat(AMBFMT, ambfp);
- putc('\n', ambfp);
+ fputc('\n', ambfp);
putambmagic(ambfp);
} else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
error(USER, "bad ambient file");
@@ -558,10 +956,11 @@ int creat;
static void
-avsave(av) /* insert and save an ambient value */
-AMBVAL *av;
+avsave( /* insert and save an ambient value */
+ AMBVAL *av
+)
{
- avinsert(avstore(av));
+ avstore(av);
if (ambfp == NULL)
return;
if (writambval(av, ambfp) < 0)
@@ -576,15 +975,16 @@ writerr:
static AMBVAL *
-avstore(aval) /* allocate memory and store aval */
-register AMBVAL *aval;
+avstore( /* allocate memory and save aval */
+ AMBVAL *aval
+)
{
- register AMBVAL *av;
+ AMBVAL *av;
double d;
if ((av = newambval()) == NULL)
error(SYSTEM, "out of memory in avstore");
- copystruct(av, aval);
+ *av = *aval;
av->latick = ambclock;
av->next = NULL;
nambvals++;
@@ -593,6 +993,7 @@ register AMBVAL *aval;
avsum += log(d);
navsum++;
}
+ avinsert(av); /* insert in our cache tree */
return(av);
}
@@ -603,9 +1004,9 @@ static AMBTREE *atfreelist = NULL; /* free ambient tr
static AMBTREE *
-newambtree() /* allocate 8 ambient tree structs */
+newambtree(void) /* allocate 8 ambient tree structs */
{
- register AMBTREE *atp, *upperlim;
+ AMBTREE *atp, *upperlim;
if (atfreelist == NULL) { /* get more nodes */
atfreelist = (AMBTREE *)malloc(ATALLOCSZ*8*sizeof(AMBTREE));
@@ -619,14 +1020,15 @@ newambtree() /* allocate 8 ambient tree structs */
}
atp = atfreelist;
atfreelist = atp->kid;
- bzero((char *)atp, 8*sizeof(AMBTREE));
+ memset((char *)atp, '\0', 8*sizeof(AMBTREE));
return(atp);
}
static void
-freeambtree(atp) /* free 8 ambient tree structs */
-AMBTREE *atp;
+freeambtree( /* free 8 ambient tree structs */
+ AMBTREE *atp
+)
{
atp->kid = atfreelist;
atfreelist = atp;
@@ -634,52 +1036,13 @@ AMBTREE *atp;
static void
-avinsert(av) /* insert ambient value in our tree */
-register AMBVAL *av;
+unloadatree( /* unload an ambient value tree */
+ AMBTREE *at,
+ unloadtf_t *f
+)
{
- register AMBTREE *at;
- register AMBVAL *ap;
- AMBVAL avh;
- FVECT ck0;
- double s;
- int branch;
- register int i;
-
- if (av->rad <= FTINY)
- error(CONSISTENCY, "zero ambient radius in avinsert");
- at = &atrunk;
- VCOPY(ck0, thescene.cuorg);
- s = thescene.cusize;
- while (s*(OCTSCALE/2) > av->rad*ambacc) {
- if (at->kid == NULL)
- if ((at->kid = newambtree()) == NULL)
- error(SYSTEM, "out of memory in avinsert");
- s *= 0.5;
- branch = 0;
- for (i = 0; i < 3; i++)
- if (av->pos[i] > ck0[i] + s) {
- ck0[i] += s;
- branch |= 1 << i;
- }
- at = at->kid + branch;
- }
- avh.next = at->alist; /* order by increasing level */
- for (ap = &avh; ap->next != NULL; ap = ap->next)
- if (ap->next->lvl >= av->lvl)
- break;
- av->next = ap->next;
- ap->next = av;
- at->alist = avh.next;
-}
-
-
-static void
-unloadatree(at, f) /* unload an ambient value tree */
-register AMBTREE *at;
-void (*f)();
-{
- register AMBVAL *av;
- register int i;
+ AMBVAL *av;
+ int i;
/* transfer values at this node */
for (av = at->alist; av != NULL; av = at->alist) {
at->alist = av->next;
@@ -701,25 +1064,35 @@ static struct avl {
static AMBVAL **avlist2; /* memory positions for sorting */
static int i_avlist; /* index for lists */
+static int alatcmp(const void *av1, const void *av2);
-static int
-av2list(av)
-register AMBVAL *av;
+static void
+avfree(AMBVAL *av)
{
+ free(av);
+}
+
+static void
+av2list(
+ AMBVAL *av
+)
+{
#ifdef DEBUG
if (i_avlist >= nambvals)
error(CONSISTENCY, "too many ambient values in av2list1");
#endif
- avlist1[i_avlist].p = avlist2[i_avlist] = av;
+ avlist1[i_avlist].p = avlist2[i_avlist] = (AMBVAL*)av;
avlist1[i_avlist++].t = av->latick;
}
static int
-alatcmp(av1, av2) /* compare ambient values for MRA */
-struct avl *av1, *av2;
+alatcmp( /* compare ambient values for MRA */
+ const void *av1,
+ const void *av2
+)
{
- register long lc = av2->t - av1->t;
+ long lc = ((struct avl *)av2)->t - ((struct avl *)av1)->t;
return(lc<0 ? -1 : lc>0 ? 1 : 0);
}
@@ -731,41 +1104,41 @@ struct avl *av1, *av2;
* assumes pointers differ by exact struct size increments.
*/
static int
-aposcmp(avp1, avp2) /* compare ambient value positions */
-const void *avp1, *avp2;
+aposcmp( /* compare ambient value positions */
+ const void *avp1,
+ const void *avp2
+)
{
- register long diff = *(char * const *)avp1 - *(char * const *)avp2;
+ long diff = *(char * const *)avp1 - *(char * const *)avp2;
if (diff < 0)
return(-1);
return(diff > 0);
}
-#if 1
+
static int
-avlmemi(avaddr) /* find list position from address */
-AMBVAL *avaddr;
+avlmemi( /* find list position from address */
+ AMBVAL *avaddr
+)
{
- register AMBVAL **avlpp;
+ AMBVAL **avlpp;
avlpp = (AMBVAL **)bsearch((char *)&avaddr, (char *)avlist2,
- nambvals, sizeof(AMBVAL *), aposcmp);
+ nambvals, sizeof(AMBVAL *), &aposcmp);
if (avlpp == NULL)
error(CONSISTENCY, "address not found in avlmemi");
return(avlpp - avlist2);
}
-#else
-#define avlmemi(avaddr) ((AMBVAL **)bsearch((char *)&avaddr,(char *)avlist2, \
- nambvals,sizeof(AMBVAL *),aposcmp) - avlist2)
-#endif
static void
-sortambvals(always) /* resort ambient values */
-int always;
+sortambvals( /* resort ambient values */
+ int always
+)
{
AMBTREE oldatrunk;
AMBVAL tav, *tap, *pnext;
- register int i, j;
+ int i, j;
/* see if it's time yet */
if (!always && (ambclock++ < lastsort+sortintvl ||
nambvals < SORT_THRESH))
@@ -796,10 +1169,10 @@ int always;
if (avlist2 != NULL)
free((void *)avlist2);
if (always) { /* rebuild without sorting */
- copystruct(&oldatrunk, &atrunk);
+ oldatrunk = atrunk;
atrunk.alist = NULL;
atrunk.kid = NULL;
- unloadatree(&oldatrunk, avinsert);
+ unloadatree(&oldatrunk, &avinsert);
}
} else { /* sort memory by last access time */
/*
@@ -816,25 +1189,25 @@ int always;
eputs(errmsg);
#endif
i_avlist = 0;
- unloadatree(&atrunk, av2list); /* empty current tree */
+ unloadatree(&atrunk, &av2list); /* empty current tree */
#ifdef DEBUG
if (i_avlist < nambvals)
error(CONSISTENCY, "missing ambient values in sortambvals");
#endif
- qsort((char *)avlist1, nambvals, sizeof(struct avl), alatcmp);
- qsort((char *)avlist2, nambvals, sizeof(AMBVAL *), aposcmp);
+ qsort((char *)avlist1, nambvals, sizeof(struct avl), &alatcmp);
+ qsort((char *)avlist2, nambvals, sizeof(AMBVAL *), &aposcmp);
for (i = 0; i < nambvals; i++) {
if (avlist1[i].p == NULL)
continue;
tap = avlist2[i];
- copystruct(&tav, tap);
+ tav = *tap;
for (j = i; (pnext = avlist1[j].p) != tap;
j = avlmemi(pnext)) {
- copystruct(avlist2[j], pnext);
+ *(avlist2[j]) = *pnext;
avinsert(avlist2[j]);
avlist1[j].p = NULL;
}
- copystruct(avlist2[j], &tav);
+ *(avlist2[j]) = tav;
avinsert(avlist2[j]);
avlist1[j].p = NULL;
}
@@ -859,11 +1232,14 @@ int always;
#ifdef F_SETLKW
static void
-aflock(typ) /* lock/unlock ambient file */
-int typ;
+aflock( /* lock/unlock ambient file */
+ int typ
+)
{
static struct flock fls; /* static so initialized to zeroes */
+ if (typ == fls.l_type) /* already called? */
+ return;
fls.l_type = typ;
if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
error(SYSTEM, "cannot (un)lock ambient file");
@@ -871,28 +1247,26 @@ int typ;
int
-ambsync() /* synchronize ambient file */
+ambsync(void) /* synchronize ambient file */
{
long flen;
AMBVAL avs;
- register int n;
+ int n;
- if (nunflshed == 0)
+ if (ambfp == NULL) /* no ambient file? */
return(0);
- if (lastpos < 0) /* initializing (locked in initambfile) */
- goto syncend;
- /* gain exclusive access */
- aflock(F_WRLCK);
+ /* gain appropriate access */
+ aflock(nunflshed ? F_WRLCK : F_RDLCK);
/* see if file has grown */
- if ((flen = lseek(fileno(ambfp), (off_t)0L, 2)) < 0)
+ if ((flen = lseek(fileno(ambfp), (off_t)0, SEEK_END)) < 0)
goto seekerr;
- if (n = flen - lastpos) { /* file has grown */
+ if ((n = flen - lastpos) > 0) { /* file has grown */
if (ambinp == NULL) { /* use duplicate filedes */
ambinp = fdopen(dup(fileno(ambfp)), "r");
if (ambinp == NULL)
error(SYSTEM, "fdopen failed in ambsync");
}
- if (fseek(ambinp, lastpos, 0) < 0)
+ if (fseek(ambinp, lastpos, SEEK_SET) < 0)
goto seekerr;
while (n >= AMBVALSIZ) { /* load contributed values */
if (!readambval(&avs, ambinp)) {
@@ -902,42 +1276,38 @@ ambsync() /* synchronize ambient file */
error(WARNING, errmsg);
break;
}
- avinsert(avstore(&avs));
+ avstore(&avs);
n -= AMBVALSIZ;
}
+ lastpos = flen - n;
/*** seek always as safety measure
if (n) ***/ /* alignment */
- if (lseek(fileno(ambfp), (off_t)(flen-n), 0) < 0)
+ if (lseek(fileno(ambfp), (off_t)lastpos, SEEK_SET) < 0)
goto seekerr;
}
-#ifdef DEBUG
- if (ambfp->_ptr - ambfp->_base != nunflshed*AMBVALSIZ) {
- sprintf(errmsg, "ambient file buffer at %d rather than %d",
- ambfp->_ptr - ambfp->_base,
- nunflshed*AMBVALSIZ);
- error(CONSISTENCY, errmsg);
- }
-#endif
-syncend:
n = fflush(ambfp); /* calls write() at last */
- if ((lastpos = lseek(fileno(ambfp), (off_t)0L, 1)) < 0)
+ if (n != EOF)
+ lastpos += (long)nunflshed*AMBVALSIZ;
+ else if ((lastpos = lseek(fileno(ambfp), (off_t)0, SEEK_CUR)) < 0)
goto seekerr;
+
aflock(F_UNLCK); /* release file */
nunflshed = 0;
return(n);
seekerr:
error(SYSTEM, "seek failed in ambsync");
+ return -1; /* pro forma return */
}
-#else
+#else /* ! F_SETLKW */
int
-ambsync() /* flush ambient file */
+ambsync(void) /* flush ambient file */
{
- if (nunflshed == 0)
+ if (ambfp == NULL)
return(0);
nunflshed = 0;
return(fflush(ambfp));
}
-#endif
+#endif /* ! F_SETLKW */