| 4 | 
  | 
/* | 
| 5 | 
  | 
 * Routines to compute "ambient" values using Monte Carlo | 
| 6 | 
  | 
 * | 
| 7 | 
+ | 
 *  Hessian calculations based on "Practical Hessian-Based Error Control | 
| 8 | 
+ | 
 *      for Irradiance Caching" by Schwarzhaupt, Wann Jensen, & Jarosz | 
| 9 | 
+ | 
 *      from ACM SIGGRAPH Asia 2012 conference proceedings. | 
| 10 | 
+ | 
 * | 
| 11 | 
+ | 
 *  Added book-keeping optimization to avoid calculations that would | 
| 12 | 
+ | 
 *      cancel due to traversal both directions on edges that are adjacent | 
| 13 | 
+ | 
 *      to same-valued triangles.  This cuts about half of Hessian math. | 
| 14 | 
+ | 
 * | 
| 15 | 
  | 
 *  Declarations of external symbols in ambient.h | 
| 16 | 
  | 
 */ | 
| 17 | 
  | 
 | 
| 18 | 
  | 
#include "copyright.h" | 
| 19 | 
  | 
 | 
| 20 | 
  | 
#include  "ray.h" | 
| 13 | 
– | 
 | 
| 21 | 
  | 
#include  "ambient.h" | 
| 15 | 
– | 
 | 
| 22 | 
  | 
#include  "random.h" | 
| 23 | 
  | 
 | 
| 24 | 
+ | 
#ifndef MINADIV | 
| 25 | 
+ | 
#define MINADIV         7       /* minimum # divisions in each dimension */ | 
| 26 | 
+ | 
#endif | 
| 27 | 
+ | 
#ifndef MINSDIST | 
| 28 | 
+ | 
#define MINSDIST        0.25    /* def. min. spacing = 1/4th division */ | 
| 29 | 
+ | 
#endif | 
| 30 | 
  | 
 | 
| 31 | 
+ | 
typedef struct { | 
| 32 | 
+ | 
        FVECT   p;              /* intersection point */ | 
| 33 | 
+ | 
        float   d;              /* reciprocal distance */ | 
| 34 | 
+ | 
        SCOLOR  v;              /* hemisphere sample value */ | 
| 35 | 
+ | 
} AMBSAMP;              /* sample value */ | 
| 36 | 
+ | 
 | 
| 37 | 
+ | 
typedef struct { | 
| 38 | 
+ | 
        RAY     *rp;            /* originating ray sample */ | 
| 39 | 
+ | 
        int     ns;             /* number of samples per axis */ | 
| 40 | 
+ | 
        int     sampOK;         /* acquired full sample set? */ | 
| 41 | 
+ | 
        int     atyp;           /* RAMBIENT or TAMBIENT */ | 
| 42 | 
+ | 
        SCOLOR  acoef;          /* division contribution coefficient */ | 
| 43 | 
+ | 
        SCOLOR  acol;           /* accumulated color */ | 
| 44 | 
+ | 
        FVECT   onrm;           /* oriented unperturbed surface normal */ | 
| 45 | 
+ | 
        FVECT   ux, uy;         /* tangent axis unit vectors */ | 
| 46 | 
+ | 
        AMBSAMP sa[1];          /* sample array (extends struct) */ | 
| 47 | 
+ | 
}  AMBHEMI;             /* ambient sample hemisphere */ | 
| 48 | 
+ | 
 | 
| 49 | 
+ | 
#define AI(h,i,j)       ((i)*(h)->ns + (j)) | 
| 50 | 
+ | 
#define ambsam(h,i,j)   (h)->sa[AI(h,i,j)] | 
| 51 | 
+ | 
 | 
| 52 | 
+ | 
typedef struct { | 
| 53 | 
+ | 
        FVECT   r_i, r_i1, e_i, rcp, rI2_eJ2; | 
| 54 | 
+ | 
        double  I1, I2; | 
| 55 | 
+ | 
} FFTRI;                /* vectors and coefficients for Hessian calculation */ | 
| 56 | 
+ | 
 | 
| 57 | 
+ | 
 | 
| 58 | 
  | 
static int | 
| 59 | 
< | 
ambcmp(d1, d2)                          /* decreasing order */ | 
| 60 | 
< | 
AMBSAMP  *d1, *d2; | 
| 59 | 
> | 
ambcollision(                           /* proposed direciton collides? */ | 
| 60 | 
> | 
        AMBHEMI *hp, | 
| 61 | 
> | 
        int     i, | 
| 62 | 
> | 
        int     j, | 
| 63 | 
> | 
        FVECT   dv | 
| 64 | 
> | 
) | 
| 65 | 
  | 
{ | 
| 66 | 
< | 
        if (d1->k < d2->k) | 
| 67 | 
< | 
                return(1); | 
| 68 | 
< | 
        if (d1->k > d2->k) | 
| 69 | 
< | 
                return(-1); | 
| 70 | 
< | 
        return(0); | 
| 66 | 
> | 
        double  cos_thresh; | 
| 67 | 
> | 
        int     ii, jj; | 
| 68 | 
> | 
 | 
| 69 | 
> | 
        cos_thresh = (PI*MINSDIST)/(double)hp->ns; | 
| 70 | 
> | 
        cos_thresh = 1. - .5*cos_thresh*cos_thresh; | 
| 71 | 
> | 
                                        /* check existing neighbors */ | 
| 72 | 
> | 
        for (ii = i-1; ii <= i+1; ii++) { | 
| 73 | 
> | 
                if (ii < 0) continue; | 
| 74 | 
> | 
                if (ii >= hp->ns) break; | 
| 75 | 
> | 
                for (jj = j-1; jj <= j+1; jj++) { | 
| 76 | 
> | 
                        AMBSAMP *ap; | 
| 77 | 
> | 
                        FVECT   avec; | 
| 78 | 
> | 
                        double  dprod; | 
| 79 | 
> | 
                        if (jj < 0) continue; | 
| 80 | 
> | 
                        if (jj >= hp->ns) break; | 
| 81 | 
> | 
                        if ((ii==i) & (jj==j)) continue; | 
| 82 | 
> | 
                        ap = &ambsam(hp,ii,jj); | 
| 83 | 
> | 
                        if (ap->d <= .5/FHUGE) | 
| 84 | 
> | 
                                continue;       /* no one home */ | 
| 85 | 
> | 
                        VSUB(avec, ap->p, hp->rp->rop); | 
| 86 | 
> | 
                        dprod = DOT(avec, dv); | 
| 87 | 
> | 
                        if (dprod >= cos_thresh*VLEN(avec)) | 
| 88 | 
> | 
                                return(1);      /* collision */ | 
| 89 | 
> | 
                } | 
| 90 | 
> | 
        } | 
| 91 | 
> | 
        return(0);                      /* nothing to worry about */ | 
| 92 | 
  | 
} | 
| 93 | 
  | 
 | 
| 94 | 
  | 
 | 
| 95 | 
+ | 
#define XLOTSIZ         251             /* size of used car lot */ | 
| 96 | 
+ | 
#define CFIRST          0               /* first corner */ | 
| 97 | 
+ | 
#define COTHER          (CFIRST+4)      /* non-corner sample */ | 
| 98 | 
+ | 
#define CMAXTARGET      (int)(XLOTSIZ*MINSDIST/(1-MINSDIST)) | 
| 99 | 
+ | 
#define CXCOPY(d,s)     (excharr[d][0]=excharr[s][0], excharr[d][1]=excharr[s][1]) | 
| 100 | 
+ | 
 | 
| 101 | 
  | 
static int | 
| 102 | 
< | 
ambnorm(d1, d2)                         /* standard order */ | 
| 33 | 
< | 
AMBSAMP  *d1, *d2; | 
| 102 | 
> | 
psample_class(double ss[2])             /* classify patch sample */ | 
| 103 | 
  | 
{ | 
| 104 | 
< | 
        register int  c; | 
| 104 | 
> | 
        if (ss[0] < MINSDIST) { | 
| 105 | 
> | 
                if (ss[1] < MINSDIST) | 
| 106 | 
> | 
                        return(CFIRST); | 
| 107 | 
> | 
                if (ss[1] > 1.-MINSDIST) | 
| 108 | 
> | 
                        return(CFIRST+2); | 
| 109 | 
> | 
        } else if (ss[0] > 1.-MINSDIST) { | 
| 110 | 
> | 
                if (ss[1] < MINSDIST) | 
| 111 | 
> | 
                        return(CFIRST+1); | 
| 112 | 
> | 
                if (ss[1] > 1.-MINSDIST) | 
| 113 | 
> | 
                        return(CFIRST+3); | 
| 114 | 
> | 
        } | 
| 115 | 
> | 
        return(COTHER);                 /* not in a corner */ | 
| 116 | 
> | 
} | 
| 117 | 
  | 
 | 
| 118 | 
< | 
        if ( (c = d1->t - d2->t) ) | 
| 119 | 
< | 
                return(c); | 
| 120 | 
< | 
        return(d1->p - d2->p); | 
| 118 | 
> | 
static void | 
| 119 | 
> | 
trade_patchsamp(double ss[2])           /* trade in problem patch position */ | 
| 120 | 
> | 
{ | 
| 121 | 
> | 
        static float    excharr[XLOTSIZ][2]; | 
| 122 | 
> | 
        static short    gterm[COTHER+1]; | 
| 123 | 
> | 
        double          srep[2]; | 
| 124 | 
> | 
        int             sclass, rclass; | 
| 125 | 
> | 
        int             x; | 
| 126 | 
> | 
                                        /* reset on corner overload */ | 
| 127 | 
> | 
        if (gterm[COTHER-1] >= (CMAXTARGET+XLOTSIZ)/2) | 
| 128 | 
> | 
                memset(gterm, 0, sizeof(gterm)); | 
| 129 | 
> | 
                                        /* (re-)initialize? */ | 
| 130 | 
> | 
        while (gterm[COTHER] < XLOTSIZ) { | 
| 131 | 
> | 
                excharr[gterm[COTHER]][0] = frandom(); | 
| 132 | 
> | 
                excharr[gterm[COTHER]][1] = frandom(); | 
| 133 | 
> | 
                ++gterm[COTHER]; | 
| 134 | 
> | 
        }                               /* get trade-in candidate... */ | 
| 135 | 
> | 
        sclass = psample_class(ss);     /* submitted corner or not? */ | 
| 136 | 
> | 
        switch (sclass) { | 
| 137 | 
> | 
        case COTHER:                    /* trade mid-edge with corner/any */ | 
| 138 | 
> | 
                x = irandom( gterm[COTHER-1] > CMAXTARGET | 
| 139 | 
> | 
                                ? gterm[COTHER-1] : XLOTSIZ ); | 
| 140 | 
> | 
                break; | 
| 141 | 
> | 
        case CFIRST:                    /* kick out of first corner */ | 
| 142 | 
> | 
                x = gterm[CFIRST] + irandom(XLOTSIZ - gterm[CFIRST]); | 
| 143 | 
> | 
                break; | 
| 144 | 
> | 
        default:                        /* kick out of 2nd-4th corner */ | 
| 145 | 
> | 
                x = irandom(XLOTSIZ - (gterm[sclass] - gterm[sclass-1])); | 
| 146 | 
> | 
                x += (x >= gterm[sclass-1])*(gterm[sclass] - gterm[sclass-1]); | 
| 147 | 
> | 
                break; | 
| 148 | 
> | 
        } | 
| 149 | 
> | 
        srep[0] = excharr[x][0];        /* save selected trade output */ | 
| 150 | 
> | 
        srep[1] = excharr[x][1]; | 
| 151 | 
> | 
                                        /* adjust our lot groups */ | 
| 152 | 
> | 
        for (rclass = CFIRST; rclass < COTHER; rclass++) | 
| 153 | 
> | 
                if (x < gterm[rclass]) | 
| 154 | 
> | 
                        break; | 
| 155 | 
> | 
        if (sclass < rclass) {          /* submitted group before replacement? */ | 
| 156 | 
> | 
                CXCOPY(x, gterm[rclass-1]); | 
| 157 | 
> | 
                while (--rclass > sclass) { | 
| 158 | 
> | 
                        CXCOPY(gterm[rclass], gterm[rclass-1]); | 
| 159 | 
> | 
                        ++gterm[rclass]; | 
| 160 | 
> | 
                } | 
| 161 | 
> | 
                x = gterm[sclass]++; | 
| 162 | 
> | 
        } else if (sclass > rclass) {   /* submitted group after replacement? */ | 
| 163 | 
> | 
                --gterm[rclass]; | 
| 164 | 
> | 
                CXCOPY(x, gterm[rclass]); | 
| 165 | 
> | 
                while (++rclass < sclass) { | 
| 166 | 
> | 
                        --gterm[rclass]; | 
| 167 | 
> | 
                        CXCOPY(gterm[rclass-1], gterm[rclass]); | 
| 168 | 
> | 
                } | 
| 169 | 
> | 
                x = gterm[sclass-1]; | 
| 170 | 
> | 
        } | 
| 171 | 
> | 
        excharr[x][0] = ss[0];          /* complete the transaction */ | 
| 172 | 
> | 
        excharr[x][1] = ss[1]; | 
| 173 | 
> | 
        ss[0] = srep[0]; | 
| 174 | 
> | 
        ss[1] = srep[1]; | 
| 175 | 
  | 
} | 
| 176 | 
  | 
 | 
| 177 | 
+ | 
#undef CXCOPY | 
| 178 | 
+ | 
#undef XLOTSIZ | 
| 179 | 
+ | 
#undef COTHER | 
| 180 | 
+ | 
#undef CFIRST | 
| 181 | 
  | 
 | 
| 43 | 
– | 
int | 
| 44 | 
– | 
divsample(dp, h, r)                     /* sample a division */ | 
| 45 | 
– | 
register AMBSAMP  *dp; | 
| 46 | 
– | 
AMBHEMI  *h; | 
| 47 | 
– | 
RAY  *r; | 
| 48 | 
– | 
{ | 
| 49 | 
– | 
        RAY  ar; | 
| 50 | 
– | 
        int  hlist[3]; | 
| 51 | 
– | 
        double  spt[2]; | 
| 52 | 
– | 
        double  xd, yd, zd; | 
| 53 | 
– | 
        double  b2; | 
| 54 | 
– | 
        double  phi; | 
| 55 | 
– | 
        register int  i; | 
| 182 | 
  | 
 | 
| 183 | 
< | 
        if (rayorigin(&ar, r, AMBIENT, AVGREFL) < 0) | 
| 184 | 
< | 
                return(-1); | 
| 185 | 
< | 
        hlist[0] = r->rno; | 
| 186 | 
< | 
        hlist[1] = dp->t; | 
| 187 | 
< | 
        hlist[2] = dp->p; | 
| 188 | 
< | 
        multisamp(spt, 2, urand(ilhash(hlist,3)+dp->n)); | 
| 189 | 
< | 
        zd = sqrt((dp->t + spt[0])/h->nt); | 
| 190 | 
< | 
        phi = 2.0*PI * (dp->p + spt[1])/h->np; | 
| 191 | 
< | 
        xd = tcos(phi) * zd; | 
| 192 | 
< | 
        yd = tsin(phi) * zd; | 
| 193 | 
< | 
        zd = sqrt(1.0 - zd*zd); | 
| 194 | 
< | 
        for (i = 0; i < 3; i++) | 
| 195 | 
< | 
                ar.rdir[i] =    xd*h->ux[i] + | 
| 196 | 
< | 
                                yd*h->uy[i] + | 
| 197 | 
< | 
                                zd*h->uz[i]; | 
| 198 | 
< | 
        dimlist[ndims++] = dp->t*h->np + dp->p + 90171; | 
| 199 | 
< | 
        rayvalue(&ar); | 
| 183 | 
> | 
static int | 
| 184 | 
> | 
ambsample(                              /* initial ambient division sample */ | 
| 185 | 
> | 
        AMBHEMI *hp, | 
| 186 | 
> | 
        int     i, | 
| 187 | 
> | 
        int     j, | 
| 188 | 
> | 
        int     n | 
| 189 | 
> | 
) | 
| 190 | 
> | 
{ | 
| 191 | 
> | 
        AMBSAMP *ap = &ambsam(hp,i,j); | 
| 192 | 
> | 
        RAY     ar; | 
| 193 | 
> | 
        int     hlist[3], ii; | 
| 194 | 
> | 
        double  ss[2]; | 
| 195 | 
> | 
        RREAL   spt[2]; | 
| 196 | 
> | 
        double  zd; | 
| 197 | 
> | 
                                        /* generate hemispherical sample */ | 
| 198 | 
> | 
                                        /* ambient coefficient for weight */ | 
| 199 | 
> | 
        if (ambacc > FTINY) | 
| 200 | 
> | 
                setscolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL); | 
| 201 | 
> | 
        else | 
| 202 | 
> | 
                copyscolor(ar.rcoef, hp->acoef); | 
| 203 | 
> | 
        if (rayorigin(&ar, hp->atyp, hp->rp, ar.rcoef) < 0) | 
| 204 | 
> | 
                return(0); | 
| 205 | 
> | 
        if (ambacc > FTINY) { | 
| 206 | 
> | 
                smultscolor(ar.rcoef, hp->acoef); | 
| 207 | 
> | 
                scalescolor(ar.rcoef, 1./AVGREFL); | 
| 208 | 
> | 
        } | 
| 209 | 
> | 
        hlist[0] = hp->rp->rno; | 
| 210 | 
> | 
        hlist[1] = AI(hp,i,j); | 
| 211 | 
> | 
        hlist[2] = samplendx; | 
| 212 | 
> | 
        multisamp(ss, 2, urand(ilhash(hlist,3)+n)); | 
| 213 | 
> | 
patch_redo: | 
| 214 | 
> | 
        square2disk(spt, (j+ss[1])/hp->ns, (i+ss[0])/hp->ns); | 
| 215 | 
> | 
        zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]); | 
| 216 | 
> | 
        for (ii = 3; ii--; ) | 
| 217 | 
> | 
                ar.rdir[ii] =   spt[0]*hp->ux[ii] + | 
| 218 | 
> | 
                                spt[1]*hp->uy[ii] + | 
| 219 | 
> | 
                                zd*hp->onrm[ii]; | 
| 220 | 
> | 
        checknorm(ar.rdir); | 
| 221 | 
> | 
                                        /* avoid coincident samples */ | 
| 222 | 
> | 
        if (!n & (hp->ns >= 4) && ambcollision(hp, i, j, ar.rdir)) { | 
| 223 | 
> | 
                trade_patchsamp(ss); | 
| 224 | 
> | 
                goto patch_redo; | 
| 225 | 
> | 
        } | 
| 226 | 
> | 
        dimlist[ndims++] = AI(hp,i,j) + 90171; | 
| 227 | 
> | 
        rayvalue(&ar);                  /* evaluate ray */ | 
| 228 | 
  | 
        ndims--; | 
| 229 | 
< | 
        addcolor(dp->v, ar.rcol); | 
| 230 | 
< | 
                                        /* use rt to improve gradient calc */ | 
| 231 | 
< | 
        if (ar.rt > FTINY && ar.rt < FHUGE) | 
| 232 | 
< | 
                dp->r += 1.0/ar.rt; | 
| 233 | 
< | 
                                        /* (re)initialize error */ | 
| 234 | 
< | 
        if (dp->n++) { | 
| 235 | 
< | 
                b2 = bright(dp->v)/dp->n - bright(ar.rcol); | 
| 236 | 
< | 
                b2 = b2*b2 + dp->k*((dp->n-1)*(dp->n-1)); | 
| 237 | 
< | 
                dp->k = b2/(dp->n*dp->n); | 
| 238 | 
< | 
        } else | 
| 239 | 
< | 
                dp->k = 0.0; | 
| 240 | 
< | 
        return(0); | 
| 229 | 
> | 
        zd = raydistance(&ar); | 
| 230 | 
> | 
        if (zd <= FTINY) | 
| 231 | 
> | 
                return(0);              /* should never happen */ | 
| 232 | 
> | 
        smultscolor(ar.rcol, ar.rcoef); /* apply coefficient */ | 
| 233 | 
> | 
        if (zd*ap->d < 1.0)             /* new/closer distance? */ | 
| 234 | 
> | 
                ap->d = 1.0/zd; | 
| 235 | 
> | 
        if (!n) {                       /* record first vertex & value */ | 
| 236 | 
> | 
                if (zd > 10.0*thescene.cusize + 1000.) | 
| 237 | 
> | 
                        zd = 10.0*thescene.cusize + 1000.; | 
| 238 | 
> | 
                VSUM(ap->p, ar.rorg, ar.rdir, zd); | 
| 239 | 
> | 
                copyscolor(ap->v, ar.rcol); | 
| 240 | 
> | 
        } else {                        /* else update recorded value */ | 
| 241 | 
> | 
                sopscolor(hp->acol, -=, ap->v); | 
| 242 | 
> | 
                zd = 1.0/(double)(n+1); | 
| 243 | 
> | 
                scalescolor(ar.rcol, zd); | 
| 244 | 
> | 
                zd *= (double)n; | 
| 245 | 
> | 
                scalescolor(ap->v, zd); | 
| 246 | 
> | 
                saddscolor(ap->v, ar.rcol); | 
| 247 | 
> | 
        } | 
| 248 | 
> | 
        saddscolor(hp->acol, ap->v);    /* add to our sum */ | 
| 249 | 
> | 
        return(1); | 
| 250 | 
  | 
} | 
| 251 | 
  | 
 | 
| 252 | 
  | 
 | 
| 253 | 
< | 
double | 
| 254 | 
< | 
doambient(acol, r, wt, pg, dg)          /* compute ambient component */ | 
| 255 | 
< | 
COLOR  acol; | 
| 93 | 
< | 
RAY  *r; | 
| 94 | 
< | 
double  wt; | 
| 95 | 
< | 
FVECT  pg, dg; | 
| 253 | 
> | 
/* Estimate variance based on ambient division differences */ | 
| 254 | 
> | 
static float * | 
| 255 | 
> | 
getambdiffs(AMBHEMI *hp) | 
| 256 | 
  | 
{ | 
| 257 | 
< | 
        double  b, d; | 
| 258 | 
< | 
        AMBHEMI  hemi; | 
| 259 | 
< | 
        AMBSAMP  *div; | 
| 260 | 
< | 
        AMBSAMP  dnew; | 
| 261 | 
< | 
        register AMBSAMP  *dp; | 
| 262 | 
< | 
        double  arad; | 
| 263 | 
< | 
        int  ndivs, ns; | 
| 264 | 
< | 
        register int  i, j; | 
| 265 | 
< | 
                                        /* initialize color */ | 
| 266 | 
< | 
        setcolor(acol, 0.0, 0.0, 0.0); | 
| 267 | 
< | 
                                        /* initialize hemisphere */ | 
| 268 | 
< | 
        inithemi(&hemi, r, wt); | 
| 269 | 
< | 
        ndivs = hemi.nt * hemi.np; | 
| 270 | 
< | 
        if (ndivs == 0) | 
| 271 | 
< | 
                return(0.0); | 
| 272 | 
< | 
                                        /* set number of super-samples */ | 
| 273 | 
< | 
        ns = ambssamp * wt + 0.5; | 
| 274 | 
< | 
        if (ns > 0 || pg != NULL || dg != NULL) { | 
| 275 | 
< | 
                div = (AMBSAMP *)malloc(ndivs*sizeof(AMBSAMP)); | 
| 276 | 
< | 
                if (div == NULL) | 
| 277 | 
< | 
                        error(SYSTEM, "out of memory in doambient"); | 
| 118 | 
< | 
        } else | 
| 119 | 
< | 
                div = NULL; | 
| 120 | 
< | 
                                        /* sample the divisions */ | 
| 121 | 
< | 
        arad = 0.0; | 
| 122 | 
< | 
        if ((dp = div) == NULL) | 
| 123 | 
< | 
                dp = &dnew; | 
| 124 | 
< | 
        for (i = 0; i < hemi.nt; i++) | 
| 125 | 
< | 
                for (j = 0; j < hemi.np; j++) { | 
| 126 | 
< | 
                        dp->t = i; dp->p = j; | 
| 127 | 
< | 
                        setcolor(dp->v, 0.0, 0.0, 0.0); | 
| 128 | 
< | 
                        dp->r = 0.0; | 
| 129 | 
< | 
                        dp->n = 0; | 
| 130 | 
< | 
                        if (divsample(dp, &hemi, r) < 0) | 
| 131 | 
< | 
                                goto oopsy; | 
| 132 | 
< | 
                        arad += dp->r; | 
| 133 | 
< | 
                        if (div != NULL) | 
| 134 | 
< | 
                                dp++; | 
| 135 | 
< | 
                        else | 
| 136 | 
< | 
                                addcolor(acol, dp->v); | 
| 257 | 
> | 
        const double    normf = 1./(pbright(hp->acoef) + FTINY); | 
| 258 | 
> | 
        float   *earr = (float *)calloc(2*hp->ns*hp->ns, sizeof(float)); | 
| 259 | 
> | 
        float   *ep; | 
| 260 | 
> | 
        AMBSAMP *ap; | 
| 261 | 
> | 
        double  b, b1, d2; | 
| 262 | 
> | 
        int     i, j; | 
| 263 | 
> | 
 | 
| 264 | 
> | 
        if (earr == NULL)               /* out of memory? */ | 
| 265 | 
> | 
                return(NULL); | 
| 266 | 
> | 
                                        /* sum squared neighbor diffs */ | 
| 267 | 
> | 
        ap = hp->sa; | 
| 268 | 
> | 
        ep = earr + hp->ns*hp->ns;      /* original estimates to scratch */ | 
| 269 | 
> | 
        for (i = 0; i < hp->ns; i++) | 
| 270 | 
> | 
            for (j = 0; j < hp->ns; j++, ap++, ep++) { | 
| 271 | 
> | 
                b = pbright(ap[0].v); | 
| 272 | 
> | 
                if (i) {                /* from above */ | 
| 273 | 
> | 
                        b1 = pbright(ap[-hp->ns].v); | 
| 274 | 
> | 
                        d2 = b - b1; | 
| 275 | 
> | 
                        d2 *= d2*normf/(b + b1 + FTINY); | 
| 276 | 
> | 
                        ep[0] += d2; | 
| 277 | 
> | 
                        ep[-hp->ns] += d2; | 
| 278 | 
  | 
                } | 
| 279 | 
< | 
        if (ns > 0 && arad > FTINY && ndivs/arad < minarad) | 
| 280 | 
< | 
                ns = 0;                 /* close enough */ | 
| 281 | 
< | 
        else if (ns > 0) {              /* else perform super-sampling */ | 
| 282 | 
< | 
                comperrs(div, &hemi);                   /* compute errors */ | 
| 283 | 
< | 
                qsort(div, ndivs, sizeof(AMBSAMP), ambcmp);     /* sort divs */ | 
| 284 | 
< | 
                                                /* super-sample */ | 
| 285 | 
< | 
                for (i = ns; i > 0; i--) { | 
| 286 | 
< | 
                        dnew = *div; | 
| 287 | 
< | 
                        if (divsample(&dnew, &hemi, r) < 0) | 
| 288 | 
< | 
                                goto oopsy; | 
| 289 | 
< | 
                                                        /* reinsert */ | 
| 290 | 
< | 
                        dp = div; | 
| 291 | 
< | 
                        j = ndivs < i ? ndivs : i; | 
| 292 | 
< | 
                        while (--j > 0 && dnew.k < dp[1].k) { | 
| 293 | 
< | 
                                *dp = *(dp+1); | 
| 294 | 
< | 
                                dp++; | 
| 295 | 
< | 
                        } | 
| 296 | 
< | 
                        *dp = dnew; | 
| 297 | 
< | 
                } | 
| 298 | 
< | 
                if (pg != NULL || dg != NULL)   /* restore order */ | 
| 299 | 
< | 
                        qsort(div, ndivs, sizeof(AMBSAMP), ambnorm); | 
| 279 | 
> | 
                if (!j) continue; | 
| 280 | 
> | 
                                        /* from behind */ | 
| 281 | 
> | 
                b1 = pbright(ap[-1].v); | 
| 282 | 
> | 
                d2 = b - b1; | 
| 283 | 
> | 
                d2 *= d2*normf/(b + b1 + FTINY); | 
| 284 | 
> | 
                ep[0] += d2; | 
| 285 | 
> | 
                ep[-1] += d2; | 
| 286 | 
> | 
                if (!i) continue; | 
| 287 | 
> | 
                                        /* diagonal */ | 
| 288 | 
> | 
                b1 = pbright(ap[-hp->ns-1].v); | 
| 289 | 
> | 
                d2 = b - b1; | 
| 290 | 
> | 
                d2 *= d2*normf/(b + b1 + FTINY); | 
| 291 | 
> | 
                ep[0] += d2; | 
| 292 | 
> | 
                ep[-hp->ns-1] += d2; | 
| 293 | 
> | 
            } | 
| 294 | 
> | 
                                        /* correct for number of neighbors */ | 
| 295 | 
> | 
        ep = earr + hp->ns*hp->ns; | 
| 296 | 
> | 
        ep[0] *= 6./3.; | 
| 297 | 
> | 
        ep[hp->ns-1] *= 6./3.; | 
| 298 | 
> | 
        ep[(hp->ns-1)*hp->ns] *= 6./3.; | 
| 299 | 
> | 
        ep[(hp->ns-1)*hp->ns + hp->ns-1] *= 6./3.; | 
| 300 | 
> | 
        for (i = 1; i < hp->ns-1; i++) { | 
| 301 | 
> | 
                ep[i*hp->ns] *= 6./5.; | 
| 302 | 
> | 
                ep[i*hp->ns + hp->ns-1] *= 6./5.; | 
| 303 | 
  | 
        } | 
| 304 | 
< | 
                                        /* compute returned values */ | 
| 305 | 
< | 
        if (div != NULL) { | 
| 306 | 
< | 
                arad = 0.0; | 
| 163 | 
< | 
                for (i = ndivs, dp = div; i-- > 0; dp++) { | 
| 164 | 
< | 
                        arad += dp->r; | 
| 165 | 
< | 
                        if (dp->n > 1) { | 
| 166 | 
< | 
                                b = 1.0/dp->n; | 
| 167 | 
< | 
                                scalecolor(dp->v, b); | 
| 168 | 
< | 
                                dp->r *= b; | 
| 169 | 
< | 
                                dp->n = 1; | 
| 170 | 
< | 
                        } | 
| 171 | 
< | 
                        addcolor(acol, dp->v); | 
| 172 | 
< | 
                } | 
| 173 | 
< | 
                b = bright(acol); | 
| 174 | 
< | 
                if (b > FTINY) { | 
| 175 | 
< | 
                        b = ndivs/b; | 
| 176 | 
< | 
                        if (pg != NULL) { | 
| 177 | 
< | 
                                posgradient(pg, div, &hemi); | 
| 178 | 
< | 
                                for (i = 0; i < 3; i++) | 
| 179 | 
< | 
                                        pg[i] *= b; | 
| 180 | 
< | 
                        } | 
| 181 | 
< | 
                        if (dg != NULL) { | 
| 182 | 
< | 
                                dirgradient(dg, div, &hemi); | 
| 183 | 
< | 
                                for (i = 0; i < 3; i++) | 
| 184 | 
< | 
                                        dg[i] *= b; | 
| 185 | 
< | 
                        } | 
| 186 | 
< | 
                } else { | 
| 187 | 
< | 
                        if (pg != NULL) | 
| 188 | 
< | 
                                for (i = 0; i < 3; i++) | 
| 189 | 
< | 
                                        pg[i] = 0.0; | 
| 190 | 
< | 
                        if (dg != NULL) | 
| 191 | 
< | 
                                for (i = 0; i < 3; i++) | 
| 192 | 
< | 
                                        dg[i] = 0.0; | 
| 193 | 
< | 
                } | 
| 194 | 
< | 
                free((void *)div); | 
| 304 | 
> | 
        for (j = 1; j < hp->ns-1; j++) { | 
| 305 | 
> | 
                ep[j] *= 6./5.; | 
| 306 | 
> | 
                ep[(hp->ns-1)*hp->ns + j] *= 6./5.; | 
| 307 | 
  | 
        } | 
| 308 | 
< | 
        b = 1.0/ndivs; | 
| 309 | 
< | 
        scalecolor(acol, b); | 
| 310 | 
< | 
        if (arad <= FTINY) | 
| 311 | 
< | 
                arad = maxarad; | 
| 312 | 
< | 
        else | 
| 313 | 
< | 
                arad = (ndivs+ns)/arad; | 
| 314 | 
< | 
        if (pg != NULL) {               /* reduce radius if gradient large */ | 
| 315 | 
< | 
                d = DOT(pg,pg); | 
| 316 | 
< | 
                if (d*arad*arad > 1.0) | 
| 317 | 
< | 
                        arad = 1.0/sqrt(d); | 
| 308 | 
> | 
                                        /* blur final map to reduce bias */ | 
| 309 | 
> | 
        for (i = 0; i < hp->ns-1; i++) { | 
| 310 | 
> | 
            float  *ep2; | 
| 311 | 
> | 
            ep = earr + i*hp->ns; | 
| 312 | 
> | 
            ep2 = ep + hp->ns*hp->ns; | 
| 313 | 
> | 
            for (j = 0; j < hp->ns-1; j++, ep++, ep2++) { | 
| 314 | 
> | 
                ep[0] += .5*ep2[0] + .125*(ep2[1] + ep2[hp->ns]); | 
| 315 | 
> | 
                ep[1] += .125*ep2[0]; | 
| 316 | 
> | 
                ep[hp->ns] += .125*ep2[0]; | 
| 317 | 
> | 
            } | 
| 318 | 
  | 
        } | 
| 319 | 
< | 
        if (arad < minarad) { | 
| 320 | 
< | 
                arad = minarad; | 
| 321 | 
< | 
                if (pg != NULL && d*arad*arad > 1.0) {  /* cap gradient */ | 
| 322 | 
< | 
                        d = 1.0/arad/sqrt(d); | 
| 323 | 
< | 
                        for (i = 0; i < 3; i++) | 
| 324 | 
< | 
                                pg[i] *= d; | 
| 325 | 
< | 
                } | 
| 319 | 
> | 
        return(earr); | 
| 320 | 
> | 
} | 
| 321 | 
> | 
 | 
| 322 | 
> | 
 | 
| 323 | 
> | 
/* Perform super-sampling on hemisphere (introduces bias) */ | 
| 324 | 
> | 
static void | 
| 325 | 
> | 
ambsupersamp(AMBHEMI *hp, int cnt) | 
| 326 | 
> | 
{ | 
| 327 | 
> | 
        float   *earr = getambdiffs(hp); | 
| 328 | 
> | 
        double  e2rem = 0; | 
| 329 | 
> | 
        float   *ep; | 
| 330 | 
> | 
        int     i, j, n, nss; | 
| 331 | 
> | 
 | 
| 332 | 
> | 
        if (earr == NULL)               /* just skip calc. if no memory */ | 
| 333 | 
> | 
                return; | 
| 334 | 
> | 
                                        /* accumulate estimated variances */ | 
| 335 | 
> | 
        for (ep = earr + hp->ns*hp->ns; ep > earr; ) | 
| 336 | 
> | 
                e2rem += *--ep; | 
| 337 | 
> | 
        ep = earr;                      /* perform super-sampling */ | 
| 338 | 
> | 
        for (i = 0; i < hp->ns; i++) | 
| 339 | 
> | 
            for (j = 0; j < hp->ns; j++) { | 
| 340 | 
> | 
                if (e2rem <= FTINY) | 
| 341 | 
> | 
                        goto done;      /* nothing left to do */ | 
| 342 | 
> | 
                nss = *ep/e2rem*cnt + frandom(); | 
| 343 | 
> | 
                for (n = 1; n <= nss && ambsample(hp,i,j,n); n++) | 
| 344 | 
> | 
                        if (!--cnt) goto done; | 
| 345 | 
> | 
                e2rem -= *ep++;         /* update remainder */ | 
| 346 | 
  | 
        } | 
| 347 | 
< | 
        if ((arad /= sqrt(wt)) > maxarad) | 
| 348 | 
< | 
                arad = maxarad; | 
| 217 | 
< | 
        return(arad); | 
| 218 | 
< | 
oopsy: | 
| 219 | 
< | 
        if (div != NULL) | 
| 220 | 
< | 
                free((void *)div); | 
| 221 | 
< | 
        return(0.0); | 
| 347 | 
> | 
done: | 
| 348 | 
> | 
        free(earr); | 
| 349 | 
  | 
} | 
| 350 | 
  | 
 | 
| 351 | 
  | 
 | 
| 352 | 
< | 
void | 
| 353 | 
< | 
inithemi(hp, r, wt)             /* initialize sampling hemisphere */ | 
| 354 | 
< | 
register AMBHEMI  *hp; | 
| 355 | 
< | 
RAY  *r; | 
| 356 | 
< | 
double  wt; | 
| 352 | 
> | 
static AMBHEMI * | 
| 353 | 
> | 
samp_hemi(                              /* sample indirect hemisphere */ | 
| 354 | 
> | 
        SCOLOR  rcol, | 
| 355 | 
> | 
        RAY     *r, | 
| 356 | 
> | 
        double  wt | 
| 357 | 
> | 
) | 
| 358 | 
  | 
{ | 
| 359 | 
< | 
        register int  i; | 
| 359 | 
> | 
        int     backside = (wt < 0); | 
| 360 | 
> | 
        AMBHEMI *hp; | 
| 361 | 
> | 
        double  d; | 
| 362 | 
> | 
        int     n, i, j; | 
| 363 | 
> | 
                                        /* insignificance check */ | 
| 364 | 
> | 
        d = sintens(rcol); | 
| 365 | 
> | 
        if (d <= FTINY) | 
| 366 | 
> | 
                return(NULL); | 
| 367 | 
  | 
                                        /* set number of divisions */ | 
| 368 | 
< | 
        hp->nt = sqrt(ambdiv * wt / PI) + 0.5; | 
| 369 | 
< | 
        i = ambacc > FTINY ? 3 : 1;     /* minimum number of samples */ | 
| 370 | 
< | 
        if (hp->nt < i) | 
| 371 | 
< | 
                hp->nt = i; | 
| 372 | 
< | 
        hp->np = PI * hp->nt + 0.5; | 
| 373 | 
< | 
                                        /* make axes */ | 
| 374 | 
< | 
        VCOPY(hp->uz, r->ron); | 
| 375 | 
< | 
        hp->uy[0] = hp->uy[1] = hp->uy[2] = 0.0; | 
| 376 | 
< | 
        for (i = 0; i < 3; i++) | 
| 377 | 
< | 
                if (hp->uz[i] < 0.6 && hp->uz[i] > -0.6) | 
| 378 | 
< | 
                        break; | 
| 379 | 
< | 
        if (i >= 3) | 
| 380 | 
< | 
                error(CONSISTENCY, "bad ray direction in inithemi"); | 
| 381 | 
< | 
        hp->uy[i] = 1.0; | 
| 382 | 
< | 
        fcross(hp->ux, hp->uy, hp->uz); | 
| 383 | 
< | 
        normalize(hp->ux); | 
| 384 | 
< | 
        fcross(hp->uy, hp->uz, hp->ux); | 
| 368 | 
> | 
        if (backside) wt = -wt; | 
| 369 | 
> | 
        if (ambacc <= FTINY && | 
| 370 | 
> | 
                        wt > (d *= 0.8*r->rweight/(ambdiv*minweight + 1e-20))) | 
| 371 | 
> | 
                wt = d;                 /* avoid ray termination */ | 
| 372 | 
> | 
        n = sqrt(ambdiv * wt) + 0.5; | 
| 373 | 
> | 
        i = 1 + (MINADIV-1)*(ambacc > FTINY); | 
| 374 | 
> | 
        if (n < i)                      /* use minimum number of samples? */ | 
| 375 | 
> | 
                n = i; | 
| 376 | 
> | 
                                        /* allocate sampling array */ | 
| 377 | 
> | 
        hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1)); | 
| 378 | 
> | 
        if (hp == NULL) | 
| 379 | 
> | 
                error(SYSTEM, "out of memory in samp_hemi"); | 
| 380 | 
> | 
 | 
| 381 | 
> | 
        if (backside) { | 
| 382 | 
> | 
                hp->atyp = TAMBIENT; | 
| 383 | 
> | 
                hp->onrm[0] = -r->ron[0]; | 
| 384 | 
> | 
                hp->onrm[1] = -r->ron[1]; | 
| 385 | 
> | 
                hp->onrm[2] = -r->ron[2]; | 
| 386 | 
> | 
        } else { | 
| 387 | 
> | 
                hp->atyp = RAMBIENT; | 
| 388 | 
> | 
                VCOPY(hp->onrm, r->ron); | 
| 389 | 
> | 
        } | 
| 390 | 
> | 
        hp->rp = r; | 
| 391 | 
> | 
        hp->ns = n; | 
| 392 | 
> | 
        scolorblack(hp->acol); | 
| 393 | 
> | 
        memset(hp->sa, 0, sizeof(AMBSAMP)*n*n); | 
| 394 | 
> | 
        hp->sampOK = 0; | 
| 395 | 
> | 
                                        /* assign coefficient */ | 
| 396 | 
> | 
        copyscolor(hp->acoef, rcol); | 
| 397 | 
> | 
        d = 1.0/(n*n); | 
| 398 | 
> | 
        scalescolor(hp->acoef, d); | 
| 399 | 
> | 
                                        /* make tangent plane axes */ | 
| 400 | 
> | 
        if (!getperpendicular(hp->ux, hp->onrm, 1)) | 
| 401 | 
> | 
                error(CONSISTENCY, "bad ray direction in samp_hemi"); | 
| 402 | 
> | 
        VCROSS(hp->uy, hp->onrm, hp->ux); | 
| 403 | 
> | 
                                        /* sample divisions */ | 
| 404 | 
> | 
        for (i = hp->ns; i--; ) | 
| 405 | 
> | 
            for (j = hp->ns; j--; ) | 
| 406 | 
> | 
                hp->sampOK += ambsample(hp, i, j, 0); | 
| 407 | 
> | 
        copyscolor(rcol, hp->acol); | 
| 408 | 
> | 
        if (!hp->sampOK) {              /* utter failure? */ | 
| 409 | 
> | 
                free(hp); | 
| 410 | 
> | 
                return(NULL); | 
| 411 | 
> | 
        } | 
| 412 | 
> | 
        if (hp->sampOK < hp->ns*hp->ns) { | 
| 413 | 
> | 
                hp->sampOK *= -1;       /* soft failure */ | 
| 414 | 
> | 
                return(hp); | 
| 415 | 
> | 
        } | 
| 416 | 
> | 
        if (hp->sampOK <= MINADIV*MINADIV) | 
| 417 | 
> | 
                return(hp);             /* don't bother super-sampling */ | 
| 418 | 
> | 
        n = ambssamp*wt + 0.5; | 
| 419 | 
> | 
        if (n >= 4*hp->ns) {            /* perform super-sampling? */ | 
| 420 | 
> | 
                ambsupersamp(hp, n); | 
| 421 | 
> | 
                copyscolor(rcol, hp->acol); | 
| 422 | 
> | 
        } | 
| 423 | 
> | 
        return(hp);                     /* all is well */ | 
| 424 | 
  | 
} | 
| 425 | 
  | 
 | 
| 426 | 
  | 
 | 
| 427 | 
< | 
void | 
| 428 | 
< | 
comperrs(da, hp)                /* compute initial error estimates */ | 
| 429 | 
< | 
AMBSAMP  *da;           /* assumes standard ordering */ | 
| 256 | 
< | 
register AMBHEMI  *hp; | 
| 427 | 
> | 
/* Return brightness of farthest ambient sample */ | 
| 428 | 
> | 
static double | 
| 429 | 
> | 
back_ambval(AMBHEMI *hp, const int n1, const int n2, const int n3) | 
| 430 | 
  | 
{ | 
| 431 | 
< | 
        double  b, b2; | 
| 432 | 
< | 
        int  i, j; | 
| 433 | 
< | 
        register AMBSAMP  *dp; | 
| 434 | 
< | 
                                /* sum differences from neighbors */ | 
| 435 | 
< | 
        dp = da; | 
| 436 | 
< | 
        for (i = 0; i < hp->nt; i++) | 
| 437 | 
< | 
                for (j = 0; j < hp->np; j++) { | 
| 438 | 
< | 
#ifdef  DEBUG | 
| 266 | 
< | 
                        if (dp->t != i || dp->p != j) | 
| 267 | 
< | 
                                error(CONSISTENCY, | 
| 268 | 
< | 
                                        "division order in comperrs"); | 
| 269 | 
< | 
#endif | 
| 270 | 
< | 
                        b = bright(dp[0].v); | 
| 271 | 
< | 
                        if (i > 0) {            /* from above */ | 
| 272 | 
< | 
                                b2 = bright(dp[-hp->np].v) - b; | 
| 273 | 
< | 
                                b2 *= b2 * 0.25; | 
| 274 | 
< | 
                                dp[0].k += b2; | 
| 275 | 
< | 
                                dp[-hp->np].k += b2; | 
| 276 | 
< | 
                        } | 
| 277 | 
< | 
                        if (j > 0) {            /* from behind */ | 
| 278 | 
< | 
                                b2 = bright(dp[-1].v) - b; | 
| 279 | 
< | 
                                b2 *= b2 * 0.25; | 
| 280 | 
< | 
                                dp[0].k += b2; | 
| 281 | 
< | 
                                dp[-1].k += b2; | 
| 282 | 
< | 
                        } else {                /* around */ | 
| 283 | 
< | 
                                b2 = bright(dp[hp->np-1].v) - b; | 
| 284 | 
< | 
                                b2 *= b2 * 0.25; | 
| 285 | 
< | 
                                dp[0].k += b2; | 
| 286 | 
< | 
                                dp[hp->np-1].k += b2; | 
| 287 | 
< | 
                        } | 
| 288 | 
< | 
                        dp++; | 
| 289 | 
< | 
                } | 
| 290 | 
< | 
                                /* divide by number of neighbors */ | 
| 291 | 
< | 
        dp = da; | 
| 292 | 
< | 
        for (j = 0; j < hp->np; j++)            /* top row */ | 
| 293 | 
< | 
                (dp++)->k *= 1.0/3.0; | 
| 294 | 
< | 
        if (hp->nt < 2) | 
| 295 | 
< | 
                return; | 
| 296 | 
< | 
        for (i = 1; i < hp->nt-1; i++)          /* central region */ | 
| 297 | 
< | 
                for (j = 0; j < hp->np; j++) | 
| 298 | 
< | 
                        (dp++)->k *= 0.25; | 
| 299 | 
< | 
        for (j = 0; j < hp->np; j++)            /* bottom row */ | 
| 300 | 
< | 
                (dp++)->k *= 1.0/3.0; | 
| 431 | 
> | 
        if (hp->sa[n1].d <= hp->sa[n2].d) { | 
| 432 | 
> | 
                if (hp->sa[n1].d <= hp->sa[n3].d) | 
| 433 | 
> | 
                        return(hp->sa[n1].v[0]); | 
| 434 | 
> | 
                return(hp->sa[n3].v[0]); | 
| 435 | 
> | 
        } | 
| 436 | 
> | 
        if (hp->sa[n2].d <= hp->sa[n3].d) | 
| 437 | 
> | 
                return(hp->sa[n2].v[0]); | 
| 438 | 
> | 
        return(hp->sa[n3].v[0]); | 
| 439 | 
  | 
} | 
| 440 | 
  | 
 | 
| 441 | 
  | 
 | 
| 442 | 
< | 
void | 
| 443 | 
< | 
posgradient(gv, da, hp)                         /* compute position gradient */ | 
| 444 | 
< | 
FVECT  gv; | 
| 307 | 
< | 
AMBSAMP  *da;                   /* assumes standard ordering */ | 
| 308 | 
< | 
register AMBHEMI  *hp; | 
| 442 | 
> | 
/* Compute vectors and coefficients for Hessian/gradient calcs */ | 
| 443 | 
> | 
static void | 
| 444 | 
> | 
comp_fftri(FFTRI *ftp, AMBHEMI *hp, const int n0, const int n1) | 
| 445 | 
  | 
{ | 
| 446 | 
< | 
        register int  i, j; | 
| 447 | 
< | 
        double  nextsine, lastsine, b, d; | 
| 312 | 
< | 
        double  mag0, mag1; | 
| 313 | 
< | 
        double  phi, cosp, sinp, xd, yd; | 
| 314 | 
< | 
        register AMBSAMP  *dp; | 
| 446 | 
> | 
        double  rdot_cp, dot_e, dot_er, rdot_r, rdot_r1, J2; | 
| 447 | 
> | 
        int     ii; | 
| 448 | 
  | 
 | 
| 449 | 
< | 
        xd = yd = 0.0; | 
| 450 | 
< | 
        for (j = 0; j < hp->np; j++) { | 
| 451 | 
< | 
                dp = da + j; | 
| 452 | 
< | 
                mag0 = mag1 = 0.0; | 
| 453 | 
< | 
                lastsine = 0.0; | 
| 454 | 
< | 
                for (i = 0; i < hp->nt; i++) { | 
| 455 | 
< | 
#ifdef  DEBUG | 
| 456 | 
< | 
                        if (dp->t != i || dp->p != j) | 
| 457 | 
< | 
                                error(CONSISTENCY, | 
| 458 | 
< | 
                                        "division order in posgradient"); | 
| 459 | 
< | 
#endif | 
| 460 | 
< | 
                        b = bright(dp->v); | 
| 461 | 
< | 
                        if (i > 0) { | 
| 462 | 
< | 
                                d = dp[-hp->np].r; | 
| 463 | 
< | 
                                if (dp[0].r > d) d = dp[0].r; | 
| 464 | 
< | 
                                                        /* sin(t)*cos(t)^2 */ | 
| 465 | 
< | 
                                d *= lastsine * (1.0 - (double)i/hp->nt); | 
| 466 | 
< | 
                                mag0 += d*(b - bright(dp[-hp->np].v)); | 
| 467 | 
< | 
                        } | 
| 468 | 
< | 
                        nextsine = sqrt((double)(i+1)/hp->nt); | 
| 469 | 
< | 
                        if (j > 0) { | 
| 470 | 
< | 
                                d = dp[-1].r; | 
| 471 | 
< | 
                                if (dp[0].r > d) d = dp[0].r; | 
| 472 | 
< | 
                                mag1 += d * (nextsine - lastsine) * | 
| 473 | 
< | 
                                                (b - bright(dp[-1].v)); | 
| 474 | 
< | 
                        } else { | 
| 475 | 
< | 
                                d = dp[hp->np-1].r; | 
| 476 | 
< | 
                                if (dp[0].r > d) d = dp[0].r; | 
| 477 | 
< | 
                                mag1 += d * (nextsine - lastsine) * | 
| 478 | 
< | 
                                                (b - bright(dp[hp->np-1].v)); | 
| 479 | 
< | 
                        } | 
| 480 | 
< | 
                        dp += hp->np; | 
| 481 | 
< | 
                        lastsine = nextsine; | 
| 449 | 
> | 
        VSUB(ftp->r_i, hp->sa[n0].p, hp->rp->rop); | 
| 450 | 
> | 
        VSUB(ftp->r_i1, hp->sa[n1].p, hp->rp->rop); | 
| 451 | 
> | 
        VSUB(ftp->e_i, hp->sa[n1].p, hp->sa[n0].p); | 
| 452 | 
> | 
        VCROSS(ftp->rcp, ftp->r_i, ftp->r_i1); | 
| 453 | 
> | 
        rdot_cp = 1.0/DOT(ftp->rcp,ftp->rcp); | 
| 454 | 
> | 
        dot_e = DOT(ftp->e_i,ftp->e_i); | 
| 455 | 
> | 
        dot_er = DOT(ftp->e_i, ftp->r_i); | 
| 456 | 
> | 
        rdot_r = 1.0/DOT(ftp->r_i,ftp->r_i); | 
| 457 | 
> | 
        rdot_r1 = 1.0/DOT(ftp->r_i1,ftp->r_i1); | 
| 458 | 
> | 
        ftp->I1 = acos( DOT(ftp->r_i, ftp->r_i1) * sqrt(rdot_r*rdot_r1) ) * | 
| 459 | 
> | 
                        sqrt( rdot_cp ); | 
| 460 | 
> | 
        ftp->I2 = ( DOT(ftp->e_i, ftp->r_i1)*rdot_r1 - dot_er*rdot_r + | 
| 461 | 
> | 
                        dot_e*ftp->I1 )*0.5*rdot_cp; | 
| 462 | 
> | 
        J2 =  ( 0.5*(rdot_r - rdot_r1) - dot_er*ftp->I2 ) / dot_e; | 
| 463 | 
> | 
        for (ii = 3; ii--; ) | 
| 464 | 
> | 
                ftp->rI2_eJ2[ii] = ftp->I2*ftp->r_i[ii] + J2*ftp->e_i[ii]; | 
| 465 | 
> | 
} | 
| 466 | 
> | 
 | 
| 467 | 
> | 
 | 
| 468 | 
> | 
/* Compose 3x3 matrix from two vectors */ | 
| 469 | 
> | 
static void | 
| 470 | 
> | 
compose_matrix(FVECT mat[3], FVECT va, FVECT vb) | 
| 471 | 
> | 
{ | 
| 472 | 
> | 
        mat[0][0] = 2.0*va[0]*vb[0]; | 
| 473 | 
> | 
        mat[1][1] = 2.0*va[1]*vb[1]; | 
| 474 | 
> | 
        mat[2][2] = 2.0*va[2]*vb[2]; | 
| 475 | 
> | 
        mat[0][1] = mat[1][0] = va[0]*vb[1] + va[1]*vb[0]; | 
| 476 | 
> | 
        mat[0][2] = mat[2][0] = va[0]*vb[2] + va[2]*vb[0]; | 
| 477 | 
> | 
        mat[1][2] = mat[2][1] = va[1]*vb[2] + va[2]*vb[1]; | 
| 478 | 
> | 
} | 
| 479 | 
> | 
 | 
| 480 | 
> | 
 | 
| 481 | 
> | 
/* Compute partial 3x3 Hessian matrix for edge */ | 
| 482 | 
> | 
static void | 
| 483 | 
> | 
comp_hessian(FVECT hess[3], FFTRI *ftp, FVECT nrm) | 
| 484 | 
> | 
{ | 
| 485 | 
> | 
        FVECT   ncp; | 
| 486 | 
> | 
        FVECT   m1[3], m2[3], m3[3], m4[3]; | 
| 487 | 
> | 
        double  d1, d2, d3, d4; | 
| 488 | 
> | 
        double  I3, J3, K3; | 
| 489 | 
> | 
        int     i, j; | 
| 490 | 
> | 
                                        /* compute intermediate coefficients */ | 
| 491 | 
> | 
        d1 = 1.0/DOT(ftp->r_i,ftp->r_i); | 
| 492 | 
> | 
        d2 = 1.0/DOT(ftp->r_i1,ftp->r_i1); | 
| 493 | 
> | 
        d3 = 1.0/DOT(ftp->e_i,ftp->e_i); | 
| 494 | 
> | 
        d4 = DOT(ftp->e_i, ftp->r_i); | 
| 495 | 
> | 
        I3 = ( DOT(ftp->e_i, ftp->r_i1)*d2*d2 - d4*d1*d1 + 3.0/d3*ftp->I2 ) | 
| 496 | 
> | 
                        / ( 4.0*DOT(ftp->rcp,ftp->rcp) ); | 
| 497 | 
> | 
        J3 = 0.25*d3*(d1*d1 - d2*d2) - d4*d3*I3; | 
| 498 | 
> | 
        K3 = d3*(ftp->I2 - I3/d1 - 2.0*d4*J3); | 
| 499 | 
> | 
                                        /* intermediate matrices */ | 
| 500 | 
> | 
        VCROSS(ncp, nrm, ftp->e_i); | 
| 501 | 
> | 
        compose_matrix(m1, ncp, ftp->rI2_eJ2); | 
| 502 | 
> | 
        compose_matrix(m2, ftp->r_i, ftp->r_i); | 
| 503 | 
> | 
        compose_matrix(m3, ftp->e_i, ftp->e_i); | 
| 504 | 
> | 
        compose_matrix(m4, ftp->r_i, ftp->e_i); | 
| 505 | 
> | 
        d1 = DOT(nrm, ftp->rcp); | 
| 506 | 
> | 
        d2 = -d1*ftp->I2; | 
| 507 | 
> | 
        d1 *= 2.0; | 
| 508 | 
> | 
        for (i = 3; i--; )              /* final matrix sum */ | 
| 509 | 
> | 
            for (j = 3; j--; ) { | 
| 510 | 
> | 
                hess[i][j] = m1[i][j] + d1*( I3*m2[i][j] + K3*m3[i][j] + | 
| 511 | 
> | 
                                                2.0*J3*m4[i][j] ); | 
| 512 | 
> | 
                hess[i][j] += d2*(i==j); | 
| 513 | 
> | 
                hess[i][j] *= -1.0/PI; | 
| 514 | 
> | 
            } | 
| 515 | 
> | 
} | 
| 516 | 
> | 
 | 
| 517 | 
> | 
 | 
| 518 | 
> | 
/* Reverse hessian calculation result for edge in other direction */ | 
| 519 | 
> | 
static void | 
| 520 | 
> | 
rev_hessian(FVECT hess[3]) | 
| 521 | 
> | 
{ | 
| 522 | 
> | 
        int     i; | 
| 523 | 
> | 
 | 
| 524 | 
> | 
        for (i = 3; i--; ) { | 
| 525 | 
> | 
                hess[i][0] = -hess[i][0]; | 
| 526 | 
> | 
                hess[i][1] = -hess[i][1]; | 
| 527 | 
> | 
                hess[i][2] = -hess[i][2]; | 
| 528 | 
> | 
        } | 
| 529 | 
> | 
} | 
| 530 | 
> | 
 | 
| 531 | 
> | 
 | 
| 532 | 
> | 
/* Add to radiometric Hessian from the given triangle */ | 
| 533 | 
> | 
static void | 
| 534 | 
> | 
add2hessian(FVECT hess[3], FVECT ehess1[3], | 
| 535 | 
> | 
                FVECT ehess2[3], FVECT ehess3[3], double v) | 
| 536 | 
> | 
{ | 
| 537 | 
> | 
        int     i, j; | 
| 538 | 
> | 
 | 
| 539 | 
> | 
        for (i = 3; i--; ) | 
| 540 | 
> | 
            for (j = 3; j--; ) | 
| 541 | 
> | 
                hess[i][j] += v*( ehess1[i][j] + ehess2[i][j] + ehess3[i][j] ); | 
| 542 | 
> | 
} | 
| 543 | 
> | 
 | 
| 544 | 
> | 
 | 
| 545 | 
> | 
/* Compute partial displacement form factor gradient for edge */ | 
| 546 | 
> | 
static void | 
| 547 | 
> | 
comp_gradient(FVECT grad, FFTRI *ftp, FVECT nrm) | 
| 548 | 
> | 
{ | 
| 549 | 
> | 
        FVECT   ncp; | 
| 550 | 
> | 
        double  f1; | 
| 551 | 
> | 
        int     i; | 
| 552 | 
> | 
 | 
| 553 | 
> | 
        f1 = 2.0*DOT(nrm, ftp->rcp); | 
| 554 | 
> | 
        VCROSS(ncp, nrm, ftp->e_i); | 
| 555 | 
> | 
        for (i = 3; i--; ) | 
| 556 | 
> | 
                grad[i] = (0.5/PI)*( ftp->I1*ncp[i] + f1*ftp->rI2_eJ2[i] ); | 
| 557 | 
> | 
} | 
| 558 | 
> | 
 | 
| 559 | 
> | 
 | 
| 560 | 
> | 
/* Reverse gradient calculation result for edge in other direction */ | 
| 561 | 
> | 
static void | 
| 562 | 
> | 
rev_gradient(FVECT grad) | 
| 563 | 
> | 
{ | 
| 564 | 
> | 
        grad[0] = -grad[0]; | 
| 565 | 
> | 
        grad[1] = -grad[1]; | 
| 566 | 
> | 
        grad[2] = -grad[2]; | 
| 567 | 
> | 
} | 
| 568 | 
> | 
 | 
| 569 | 
> | 
 | 
| 570 | 
> | 
/* Add to displacement gradient from the given triangle */ | 
| 571 | 
> | 
static void | 
| 572 | 
> | 
add2gradient(FVECT grad, FVECT egrad1, FVECT egrad2, FVECT egrad3, double v) | 
| 573 | 
> | 
{ | 
| 574 | 
> | 
        int     i; | 
| 575 | 
> | 
 | 
| 576 | 
> | 
        for (i = 3; i--; ) | 
| 577 | 
> | 
                grad[i] += v*( egrad1[i] + egrad2[i] + egrad3[i] ); | 
| 578 | 
> | 
} | 
| 579 | 
> | 
 | 
| 580 | 
> | 
 | 
| 581 | 
> | 
/* Compute anisotropic radii and eigenvector directions */ | 
| 582 | 
> | 
static void | 
| 583 | 
> | 
eigenvectors(FVECT uv[2], float ra[2], FVECT hessian[3]) | 
| 584 | 
> | 
{ | 
| 585 | 
> | 
        double  hess2[2][2]; | 
| 586 | 
> | 
        FVECT   a, b; | 
| 587 | 
> | 
        double  evalue[2], slope1, xmag1; | 
| 588 | 
> | 
        int     i; | 
| 589 | 
> | 
                                        /* project Hessian to sample plane */ | 
| 590 | 
> | 
        for (i = 3; i--; ) { | 
| 591 | 
> | 
                a[i] = DOT(hessian[i], uv[0]); | 
| 592 | 
> | 
                b[i] = DOT(hessian[i], uv[1]); | 
| 593 | 
> | 
        } | 
| 594 | 
> | 
        hess2[0][0] = DOT(uv[0], a); | 
| 595 | 
> | 
        hess2[0][1] = DOT(uv[0], b); | 
| 596 | 
> | 
        hess2[1][0] = DOT(uv[1], a); | 
| 597 | 
> | 
        hess2[1][1] = DOT(uv[1], b); | 
| 598 | 
> | 
                                        /* compute eigenvalue(s) */ | 
| 599 | 
> | 
        i = quadratic(evalue, 1.0, -hess2[0][0]-hess2[1][1], | 
| 600 | 
> | 
                        hess2[0][0]*hess2[1][1]-hess2[0][1]*hess2[1][0]); | 
| 601 | 
> | 
        if (i == 1)                     /* double-root (circle) */ | 
| 602 | 
> | 
                evalue[1] = evalue[0]; | 
| 603 | 
> | 
        if (!i || ((evalue[0] = fabs(evalue[0])) <= FTINY*FTINY) | | 
| 604 | 
> | 
                        ((evalue[1] = fabs(evalue[1])) <= FTINY*FTINY) ) { | 
| 605 | 
> | 
                ra[0] = ra[1] = maxarad; | 
| 606 | 
> | 
                return; | 
| 607 | 
> | 
        } | 
| 608 | 
> | 
        if (evalue[0] > evalue[1]) { | 
| 609 | 
> | 
                ra[0] = sqrt(sqrt(4.0/evalue[0])); | 
| 610 | 
> | 
                ra[1] = sqrt(sqrt(4.0/evalue[1])); | 
| 611 | 
> | 
                slope1 = evalue[1]; | 
| 612 | 
> | 
        } else { | 
| 613 | 
> | 
                ra[0] = sqrt(sqrt(4.0/evalue[1])); | 
| 614 | 
> | 
                ra[1] = sqrt(sqrt(4.0/evalue[0])); | 
| 615 | 
> | 
                slope1 = evalue[0]; | 
| 616 | 
> | 
        } | 
| 617 | 
> | 
                                        /* compute unit eigenvectors */ | 
| 618 | 
> | 
        if (fabs(hess2[0][1]) <= FTINY) | 
| 619 | 
> | 
                return;                 /* uv OK as is */ | 
| 620 | 
> | 
        slope1 = (slope1 - hess2[0][0]) / hess2[0][1]; | 
| 621 | 
> | 
        xmag1 = sqrt(1.0/(1.0 + slope1*slope1)); | 
| 622 | 
> | 
        for (i = 3; i--; ) { | 
| 623 | 
> | 
                b[i] = xmag1*uv[0][i] + slope1*xmag1*uv[1][i]; | 
| 624 | 
> | 
                a[i] = slope1*xmag1*uv[0][i] - xmag1*uv[1][i]; | 
| 625 | 
> | 
        } | 
| 626 | 
> | 
        VCOPY(uv[0], a); | 
| 627 | 
> | 
        VCOPY(uv[1], b); | 
| 628 | 
> | 
} | 
| 629 | 
> | 
 | 
| 630 | 
> | 
 | 
| 631 | 
> | 
static void | 
| 632 | 
> | 
ambHessian(                             /* anisotropic radii & pos. gradient */ | 
| 633 | 
> | 
        AMBHEMI *hp, | 
| 634 | 
> | 
        FVECT   uv[2],                  /* returned */ | 
| 635 | 
> | 
        float   ra[2],                  /* returned (optional) */ | 
| 636 | 
> | 
        float   pg[2]                   /* returned (optional) */ | 
| 637 | 
> | 
) | 
| 638 | 
> | 
{ | 
| 639 | 
> | 
        static char     memerrmsg[] = "out of memory in ambHessian()"; | 
| 640 | 
> | 
        FVECT           (*hessrow)[3] = NULL; | 
| 641 | 
> | 
        FVECT           *gradrow = NULL; | 
| 642 | 
> | 
        FVECT           hessian[3]; | 
| 643 | 
> | 
        FVECT           gradient; | 
| 644 | 
> | 
        FFTRI           fftr; | 
| 645 | 
> | 
        int             i, j; | 
| 646 | 
> | 
                                        /* be sure to assign unit vectors */ | 
| 647 | 
> | 
        VCOPY(uv[0], hp->ux); | 
| 648 | 
> | 
        VCOPY(uv[1], hp->uy); | 
| 649 | 
> | 
                        /* clock-wise vertex traversal from sample POV */ | 
| 650 | 
> | 
        if (ra != NULL) {               /* initialize Hessian row buffer */ | 
| 651 | 
> | 
                hessrow = (FVECT (*)[3])malloc(sizeof(FVECT)*3*(hp->ns-1)); | 
| 652 | 
> | 
                if (hessrow == NULL) | 
| 653 | 
> | 
                        error(SYSTEM, memerrmsg); | 
| 654 | 
> | 
                memset(hessian, 0, sizeof(hessian)); | 
| 655 | 
> | 
        } else if (pg == NULL)          /* bogus call? */ | 
| 656 | 
> | 
                return; | 
| 657 | 
> | 
        if (pg != NULL) {               /* initialize form factor row buffer */ | 
| 658 | 
> | 
                gradrow = (FVECT *)malloc(sizeof(FVECT)*(hp->ns-1)); | 
| 659 | 
> | 
                if (gradrow == NULL) | 
| 660 | 
> | 
                        error(SYSTEM, memerrmsg); | 
| 661 | 
> | 
                memset(gradient, 0, sizeof(gradient)); | 
| 662 | 
> | 
        } | 
| 663 | 
> | 
                                        /* compute first row of edges */ | 
| 664 | 
> | 
        for (j = 0; j < hp->ns-1; j++) { | 
| 665 | 
> | 
                comp_fftri(&fftr, hp, AI(hp,0,j), AI(hp,0,j+1)); | 
| 666 | 
> | 
                if (hessrow != NULL) | 
| 667 | 
> | 
                        comp_hessian(hessrow[j], &fftr, hp->onrm); | 
| 668 | 
> | 
                if (gradrow != NULL) | 
| 669 | 
> | 
                        comp_gradient(gradrow[j], &fftr, hp->onrm); | 
| 670 | 
> | 
        } | 
| 671 | 
> | 
                                        /* sum each row of triangles */ | 
| 672 | 
> | 
        for (i = 0; i < hp->ns-1; i++) { | 
| 673 | 
> | 
            FVECT       hesscol[3];     /* compute first vertical edge */ | 
| 674 | 
> | 
            FVECT       gradcol; | 
| 675 | 
> | 
            comp_fftri(&fftr, hp, AI(hp,i,0), AI(hp,i+1,0)); | 
| 676 | 
> | 
            if (hessrow != NULL) | 
| 677 | 
> | 
                comp_hessian(hesscol, &fftr, hp->onrm); | 
| 678 | 
> | 
            if (gradrow != NULL) | 
| 679 | 
> | 
                comp_gradient(gradcol, &fftr, hp->onrm); | 
| 680 | 
> | 
            for (j = 0; j < hp->ns-1; j++) { | 
| 681 | 
> | 
                FVECT   hessdia[3];     /* compute triangle contributions */ | 
| 682 | 
> | 
                FVECT   graddia; | 
| 683 | 
> | 
                double  backg; | 
| 684 | 
> | 
                backg = back_ambval(hp, AI(hp,i,j), | 
| 685 | 
> | 
                                        AI(hp,i,j+1), AI(hp,i+1,j)); | 
| 686 | 
> | 
                                        /* diagonal (inner) edge */ | 
| 687 | 
> | 
                comp_fftri(&fftr, hp, AI(hp,i,j+1), AI(hp,i+1,j)); | 
| 688 | 
> | 
                if (hessrow != NULL) { | 
| 689 | 
> | 
                    comp_hessian(hessdia, &fftr, hp->onrm); | 
| 690 | 
> | 
                    rev_hessian(hesscol); | 
| 691 | 
> | 
                    add2hessian(hessian, hessrow[j], hessdia, hesscol, backg); | 
| 692 | 
  | 
                } | 
| 693 | 
< | 
                mag0 *= 2.0*PI / hp->np; | 
| 694 | 
< | 
                phi = 2.0*PI * (double)j/hp->np; | 
| 695 | 
< | 
                cosp = tcos(phi); sinp = tsin(phi); | 
| 696 | 
< | 
                xd += mag0*cosp - mag1*sinp; | 
| 697 | 
< | 
                yd += mag0*sinp + mag1*cosp; | 
| 693 | 
> | 
                if (gradrow != NULL) { | 
| 694 | 
> | 
                    comp_gradient(graddia, &fftr, hp->onrm); | 
| 695 | 
> | 
                    rev_gradient(gradcol); | 
| 696 | 
> | 
                    add2gradient(gradient, gradrow[j], graddia, gradcol, backg); | 
| 697 | 
> | 
                } | 
| 698 | 
> | 
                                        /* initialize edge in next row */ | 
| 699 | 
> | 
                comp_fftri(&fftr, hp, AI(hp,i+1,j+1), AI(hp,i+1,j)); | 
| 700 | 
> | 
                if (hessrow != NULL) | 
| 701 | 
> | 
                    comp_hessian(hessrow[j], &fftr, hp->onrm); | 
| 702 | 
> | 
                if (gradrow != NULL) | 
| 703 | 
> | 
                    comp_gradient(gradrow[j], &fftr, hp->onrm); | 
| 704 | 
> | 
                                        /* new column edge & paired triangle */ | 
| 705 | 
> | 
                backg = back_ambval(hp, AI(hp,i+1,j+1), | 
| 706 | 
> | 
                                        AI(hp,i+1,j), AI(hp,i,j+1)); | 
| 707 | 
> | 
                comp_fftri(&fftr, hp, AI(hp,i,j+1), AI(hp,i+1,j+1)); | 
| 708 | 
> | 
                if (hessrow != NULL) { | 
| 709 | 
> | 
                    comp_hessian(hesscol, &fftr, hp->onrm); | 
| 710 | 
> | 
                    rev_hessian(hessdia); | 
| 711 | 
> | 
                    add2hessian(hessian, hessrow[j], hessdia, hesscol, backg); | 
| 712 | 
> | 
                    if (i < hp->ns-2) | 
| 713 | 
> | 
                        rev_hessian(hessrow[j]); | 
| 714 | 
> | 
                } | 
| 715 | 
> | 
                if (gradrow != NULL) { | 
| 716 | 
> | 
                    comp_gradient(gradcol, &fftr, hp->onrm); | 
| 717 | 
> | 
                    rev_gradient(graddia); | 
| 718 | 
> | 
                    add2gradient(gradient, gradrow[j], graddia, gradcol, backg); | 
| 719 | 
> | 
                    if (i < hp->ns-2) | 
| 720 | 
> | 
                        rev_gradient(gradrow[j]); | 
| 721 | 
> | 
                } | 
| 722 | 
> | 
            } | 
| 723 | 
  | 
        } | 
| 724 | 
< | 
        for (i = 0; i < 3; i++) | 
| 725 | 
< | 
                gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/PI; | 
| 724 | 
> | 
                                        /* release row buffers */ | 
| 725 | 
> | 
        if (hessrow != NULL) free(hessrow); | 
| 726 | 
> | 
        if (gradrow != NULL) free(gradrow); | 
| 727 | 
> | 
         | 
| 728 | 
> | 
        if (ra != NULL)                 /* extract eigenvectors & radii */ | 
| 729 | 
> | 
                eigenvectors(uv, ra, hessian); | 
| 730 | 
> | 
        if (pg != NULL) {               /* tangential position gradient */ | 
| 731 | 
> | 
                pg[0] = DOT(gradient, uv[0]); | 
| 732 | 
> | 
                pg[1] = DOT(gradient, uv[1]); | 
| 733 | 
> | 
        } | 
| 734 | 
  | 
} | 
| 735 | 
  | 
 | 
| 736 | 
  | 
 | 
| 737 | 
< | 
void | 
| 738 | 
< | 
dirgradient(gv, da, hp)                         /* compute direction gradient */ | 
| 739 | 
< | 
FVECT  gv; | 
| 364 | 
< | 
AMBSAMP  *da;                   /* assumes standard ordering */ | 
| 365 | 
< | 
register AMBHEMI  *hp; | 
| 737 | 
> | 
/* Compute direction gradient from a hemispherical sampling */ | 
| 738 | 
> | 
static void | 
| 739 | 
> | 
ambdirgrad(AMBHEMI *hp, FVECT uv[2], float dg[2]) | 
| 740 | 
  | 
{ | 
| 741 | 
< | 
        register int  i, j; | 
| 742 | 
< | 
        double  mag; | 
| 743 | 
< | 
        double  phi, xd, yd; | 
| 744 | 
< | 
        register AMBSAMP  *dp; | 
| 741 | 
> | 
        AMBSAMP *ap; | 
| 742 | 
> | 
        double  dgsum[2]; | 
| 743 | 
> | 
        int     n; | 
| 744 | 
> | 
        FVECT   vd; | 
| 745 | 
> | 
        double  gfact; | 
| 746 | 
  | 
 | 
| 747 | 
< | 
        xd = yd = 0.0; | 
| 748 | 
< | 
        for (j = 0; j < hp->np; j++) { | 
| 749 | 
< | 
                dp = da + j; | 
| 750 | 
< | 
                mag = 0.0; | 
| 751 | 
< | 
                for (i = 0; i < hp->nt; i++) { | 
| 752 | 
< | 
#ifdef  DEBUG | 
| 753 | 
< | 
                        if (dp->t != i || dp->p != j) | 
| 754 | 
< | 
                                error(CONSISTENCY, | 
| 755 | 
< | 
                                        "division order in dirgradient"); | 
| 756 | 
< | 
#endif | 
| 757 | 
< | 
                                                        /* tan(t) */ | 
| 758 | 
< | 
                        mag += bright(dp->v)/sqrt(hp->nt/(i+.5) - 1.0); | 
| 759 | 
< | 
                        dp += hp->np; | 
| 747 | 
> | 
        dgsum[0] = dgsum[1] = 0.0;      /* sum values times -tan(theta) */ | 
| 748 | 
> | 
        for (ap = hp->sa, n = hp->ns*hp->ns; n--; ap++) { | 
| 749 | 
> | 
                                        /* use vector for azimuth + 90deg */ | 
| 750 | 
> | 
                VSUB(vd, ap->p, hp->rp->rop); | 
| 751 | 
> | 
                                        /* brightness over cosine factor */ | 
| 752 | 
> | 
                gfact = ap->v[0] / DOT(hp->onrm, vd); | 
| 753 | 
> | 
                                        /* sine = proj_radius/vd_length */ | 
| 754 | 
> | 
                dgsum[0] -= DOT(uv[1], vd) * gfact; | 
| 755 | 
> | 
                dgsum[1] += DOT(uv[0], vd) * gfact; | 
| 756 | 
> | 
        } | 
| 757 | 
> | 
        dg[0] = dgsum[0] / (hp->ns*hp->ns); | 
| 758 | 
> | 
        dg[1] = dgsum[1] / (hp->ns*hp->ns); | 
| 759 | 
> | 
} | 
| 760 | 
> | 
 | 
| 761 | 
> | 
 | 
| 762 | 
> | 
/* Compute potential light leak direction flags for cache value */ | 
| 763 | 
> | 
static uint32 | 
| 764 | 
> | 
ambcorral(AMBHEMI *hp, FVECT uv[2], const double r0, const double r1) | 
| 765 | 
> | 
{ | 
| 766 | 
> | 
        const double    max_d = 1.0/(minarad*ambacc + 0.001); | 
| 767 | 
> | 
        const double    ang_res = 0.5*PI/hp->ns; | 
| 768 | 
> | 
        const double    ang_step = ang_res/((int)(16/PI*ang_res) + 1.01); | 
| 769 | 
> | 
        double          avg_d = 0; | 
| 770 | 
> | 
        uint32          flgs = 0; | 
| 771 | 
> | 
        FVECT           vec; | 
| 772 | 
> | 
        double          u, v; | 
| 773 | 
> | 
        double          ang, a1; | 
| 774 | 
> | 
        int             i, j; | 
| 775 | 
> | 
                                        /* don't bother for a few samples */ | 
| 776 | 
> | 
        if (hp->ns < 8) | 
| 777 | 
> | 
                return(0); | 
| 778 | 
> | 
                                        /* check distances overhead */ | 
| 779 | 
> | 
        for (i = hp->ns*3/4; i-- > hp->ns>>2; ) | 
| 780 | 
> | 
            for (j = hp->ns*3/4; j-- > hp->ns>>2; ) | 
| 781 | 
> | 
                avg_d += ambsam(hp,i,j).d; | 
| 782 | 
> | 
        avg_d *= 4.0/(hp->ns*hp->ns); | 
| 783 | 
> | 
        if (avg_d*r0 >= 1.0)            /* ceiling too low for corral? */ | 
| 784 | 
> | 
                return(0); | 
| 785 | 
> | 
        if (avg_d >= max_d)             /* insurance */ | 
| 786 | 
> | 
                return(0); | 
| 787 | 
> | 
                                        /* else circle around perimeter */ | 
| 788 | 
> | 
        for (i = 0; i < hp->ns; i++) | 
| 789 | 
> | 
            for (j = 0; j < hp->ns; j += !i|(i==hp->ns-1) ? 1 : hp->ns-1) { | 
| 790 | 
> | 
                AMBSAMP *ap = &ambsam(hp,i,j); | 
| 791 | 
> | 
                if ((ap->d <= FTINY) | (ap->d >= max_d)) | 
| 792 | 
> | 
                        continue;       /* too far or too near */ | 
| 793 | 
> | 
                VSUB(vec, ap->p, hp->rp->rop); | 
| 794 | 
> | 
                u = DOT(vec, uv[0]); | 
| 795 | 
> | 
                v = DOT(vec, uv[1]); | 
| 796 | 
> | 
                if ((r0*r0*u*u + r1*r1*v*v) * ap->d*ap->d <= u*u + v*v) | 
| 797 | 
> | 
                        continue;       /* occluder outside ellipse */ | 
| 798 | 
> | 
                ang = atan2a(v, u);     /* else set direction flags */ | 
| 799 | 
> | 
                for (a1 = ang-ang_res; a1 <= ang+ang_res; a1 += ang_step) | 
| 800 | 
> | 
                        flgs |= 1L<<(int)(16/PI*(a1 + 2.*PI*(a1 < 0))); | 
| 801 | 
> | 
            } | 
| 802 | 
> | 
        return(flgs); | 
| 803 | 
> | 
} | 
| 804 | 
> | 
 | 
| 805 | 
> | 
 | 
| 806 | 
> | 
int | 
| 807 | 
> | 
doambient(                              /* compute ambient component */ | 
| 808 | 
> | 
        SCOLOR  rcol,                   /* input/output color */ | 
| 809 | 
> | 
        RAY     *r, | 
| 810 | 
> | 
        double  wt,                     /* negative for back side */ | 
| 811 | 
> | 
        FVECT   uv[2],                  /* returned (optional) */ | 
| 812 | 
> | 
        float   ra[2],                  /* returned (optional) */ | 
| 813 | 
> | 
        float   pg[2],                  /* returned (optional) */ | 
| 814 | 
> | 
        float   dg[2],                  /* returned (optional) */ | 
| 815 | 
> | 
        uint32  *crlp                   /* returned (optional) */ | 
| 816 | 
> | 
) | 
| 817 | 
> | 
{ | 
| 818 | 
> | 
        AMBHEMI *hp = samp_hemi(rcol, r, wt); | 
| 819 | 
> | 
        FVECT   my_uv[2]; | 
| 820 | 
> | 
        double  d, K; | 
| 821 | 
> | 
        AMBSAMP *ap; | 
| 822 | 
> | 
        int     i; | 
| 823 | 
> | 
                                        /* clear return values */ | 
| 824 | 
> | 
        if (uv != NULL) | 
| 825 | 
> | 
                memset(uv, 0, sizeof(FVECT)*2); | 
| 826 | 
> | 
        if (ra != NULL) | 
| 827 | 
> | 
                ra[0] = ra[1] = 0.0; | 
| 828 | 
> | 
        if (pg != NULL) | 
| 829 | 
> | 
                pg[0] = pg[1] = 0.0; | 
| 830 | 
> | 
        if (dg != NULL) | 
| 831 | 
> | 
                dg[0] = dg[1] = 0.0; | 
| 832 | 
> | 
        if (crlp != NULL) | 
| 833 | 
> | 
                *crlp = 0; | 
| 834 | 
> | 
        if (hp == NULL)                 /* sampling falure? */ | 
| 835 | 
> | 
                return(0); | 
| 836 | 
> | 
 | 
| 837 | 
> | 
        if ((ra == NULL) & (pg == NULL) & (dg == NULL) || | 
| 838 | 
> | 
                        (hp->sampOK < 0) | (hp->ns < MINADIV)) { | 
| 839 | 
> | 
                free(hp);               /* Hessian not requested/possible */ | 
| 840 | 
> | 
                return(-1);             /* value-only return value */ | 
| 841 | 
> | 
        } | 
| 842 | 
> | 
        if ((d = scolor_mean(rcol)) > FTINY) { | 
| 843 | 
> | 
                d = 0.99*(hp->ns*hp->ns)/d;     /* normalize avg. values */ | 
| 844 | 
> | 
                K = 0.01; | 
| 845 | 
> | 
        } else {                        /* or fall back on geometric Hessian */ | 
| 846 | 
> | 
                K = 1.0; | 
| 847 | 
> | 
                pg = NULL; | 
| 848 | 
> | 
                dg = NULL; | 
| 849 | 
> | 
                crlp = NULL; | 
| 850 | 
> | 
        } | 
| 851 | 
> | 
        ap = hp->sa;                    /* single channel from here on... */ | 
| 852 | 
> | 
        for (i = hp->ns*hp->ns; i--; ap++) | 
| 853 | 
> | 
                ap->v[0] = scolor_mean(ap->v)*d + K; | 
| 854 | 
> | 
 | 
| 855 | 
> | 
        if (uv == NULL)                 /* make sure we have axis pointers */ | 
| 856 | 
> | 
                uv = my_uv; | 
| 857 | 
> | 
                                        /* compute radii & pos. gradient */ | 
| 858 | 
> | 
        ambHessian(hp, uv, ra, pg); | 
| 859 | 
> | 
 | 
| 860 | 
> | 
        if (dg != NULL)                 /* compute direction gradient */ | 
| 861 | 
> | 
                ambdirgrad(hp, uv, dg); | 
| 862 | 
> | 
 | 
| 863 | 
> | 
        if (ra != NULL) {               /* scale/clamp radii */ | 
| 864 | 
> | 
                if (pg != NULL) { | 
| 865 | 
> | 
                        if (ra[0]*(d = fabs(pg[0])) > 1.0) | 
| 866 | 
> | 
                                ra[0] = 1.0/d; | 
| 867 | 
> | 
                        if (ra[1]*(d = fabs(pg[1])) > 1.0) | 
| 868 | 
> | 
                                ra[1] = 1.0/d; | 
| 869 | 
> | 
                        if (ra[0] > ra[1]) | 
| 870 | 
> | 
                                ra[0] = ra[1]; | 
| 871 | 
  | 
                } | 
| 872 | 
< | 
                phi = 2.0*PI * (j+.5)/hp->np + PI/2.0; | 
| 873 | 
< | 
                xd += mag * tcos(phi); | 
| 874 | 
< | 
                yd += mag * tsin(phi); | 
| 872 | 
> | 
                if (ra[0] < minarad) { | 
| 873 | 
> | 
                        ra[0] = minarad; | 
| 874 | 
> | 
                        if (ra[1] < minarad) | 
| 875 | 
> | 
                                ra[1] = minarad; | 
| 876 | 
> | 
                } | 
| 877 | 
> | 
                ra[0] *= d = 1.0/sqrt(fabs(wt)); | 
| 878 | 
> | 
                if ((ra[1] *= d) > 2.0*ra[0]) | 
| 879 | 
> | 
                        ra[1] = 2.0*ra[0]; | 
| 880 | 
> | 
                if (ra[1] > maxarad) { | 
| 881 | 
> | 
                        ra[1] = maxarad; | 
| 882 | 
> | 
                        if (ra[0] > maxarad) | 
| 883 | 
> | 
                                ra[0] = maxarad; | 
| 884 | 
> | 
                } | 
| 885 | 
> | 
                                        /* flag encroached directions */ | 
| 886 | 
> | 
                if (crlp != NULL)       /* XXX doesn't update with changes to ambacc */ | 
| 887 | 
> | 
                        *crlp = ambcorral(hp, uv, ra[0]*ambacc, ra[1]*ambacc); | 
| 888 | 
> | 
                if (pg != NULL) {       /* cap gradient if necessary */ | 
| 889 | 
> | 
                        d = pg[0]*pg[0]*ra[0]*ra[0] + pg[1]*pg[1]*ra[1]*ra[1]; | 
| 890 | 
> | 
                        if (d > 1.0) { | 
| 891 | 
> | 
                                d = 1.0/sqrt(d); | 
| 892 | 
> | 
                                pg[0] *= d; | 
| 893 | 
> | 
                                pg[1] *= d; | 
| 894 | 
> | 
                        } | 
| 895 | 
> | 
                } | 
| 896 | 
  | 
        } | 
| 897 | 
< | 
        for (i = 0; i < 3; i++) | 
| 898 | 
< | 
                gv[i] = (xd*hp->ux[i] + yd*hp->uy[i])/(hp->nt*hp->np); | 
| 897 | 
> | 
        free(hp);                       /* clean up and return */ | 
| 898 | 
> | 
        return(1); | 
| 899 | 
  | 
} |