Back to index

radiance  4R0+20100331
Classes | Defines | Functions | Variables
source.c File Reference
#include "ray.h"
#include "otypes.h"
#include "rtotypes.h"
#include "source.h"
#include "random.h"

Go to the source code of this file.

Classes

struct  CONTRIB
struct  CNTPTR

Defines

#define MAXSSAMP   16 /* maximum samples per ray */
#define illumblock(m, r)
#define wrongsource(m, r)
#define distglow(m, r, d)
#define badcomponent(m, r)
#define passillum(m, r)
#define srcignore(m, r)

Functions

static int cntcmp (const void *p1, const void *p2)
OBJRECfindmaterial (register OBJREC *o)
void marksources (void)
void freesources (void)
int srcray (register RAY *sr, RAY *r, SRCINDEX *si)
void srcvalue (register RAY *r)
static int transillum (OBJECT obj)
int sourcehit (register RAY *r)
void direct (RAY *r, srcdirf_t *f, void *p)
void srcscatter (register RAY *r)
static int weaksrcmat (OBJECT obj)
int m_light (register OBJREC *m, register RAY *r)

Variables

static const char RCSid [] = "$Id: source.c,v 2.57 2008/07/17 18:26:01 greg Exp $"
double ssampdist
static CONTRIBsrccnt
static CNTPTRcntord
static int maxcntr = 0

Class Documentation

struct CONTRIB

Definition at line 26 of file source.c.

Class Members
COLOR coef
FVECT dir
int sno
COLOR val
struct CNTPTR

Definition at line 33 of file source.c.

Class Members
float brt
int sndx

Define Documentation

#define badcomponent (   m,
 
)
Value:
(r->crtype&(AMBIENT|SPECULAR) && \
                            !(r->crtype&SHADOW || r->rod < 0.0 || \
              /* not 100% correct */      distglow(m, r, r->rot)))

Definition at line 654 of file source.c.

#define distglow (   m,
  r,
  d 
)
Value:
(m->otype==MAT_GLOW && \
                            m->oargs.farg[3] >= -FTINY && \
                            d > m->oargs.farg[3])

Definition at line 641 of file source.c.

#define illumblock (   m,
 
)
Value:
(!(source[r->rsrc].sflags&SVIRTUAL) && \
                            r->rod > 0.0 && \
                            weaksrcmat(source[r->rsrc].so->omod))

Definition at line 620 of file source.c.

#define MAXSSAMP   16 /* maximum samples per ray */

Definition at line 19 of file source.c.

#define passillum (   m,
 
)
Value:
(m->otype==MAT_ILLUM && \
                            (r->rsrc<0 || source[r->rsrc].so!=r->ro || \
				source[r->rsrc].sflags&SVIRTUAL))

Definition at line 665 of file source.c.

#define srcignore (   m,
 
)
Value:
!(directvis || r->crtype&SHADOW || \
                            distglow(m, r, raydist(r,PRIMARY)))

Definition at line 674 of file source.c.

#define wrongsource (   m,
 
)
Value:
(r->rsrc>=0 && source[r->rsrc].so!=r->ro && \
                            (m->otype!=MAT_ILLUM || illumblock(m,r)))

Definition at line 631 of file source.c.


Function Documentation

static int cntcmp ( const void *  p1,
const void *  p2 
) [static]

Definition at line 345 of file source.c.

{
       register const CNTPTR  *sc1 = (const CNTPTR *)p1;
       register const CNTPTR  *sc2 = (const CNTPTR *)p2;

       if (sc1->brt > sc2->brt)
              return(-1);
       if (sc1->brt < sc2->brt)
              return(1);
       return(0);
}

Here is the caller graph for this function:

void direct ( RAY r,
srcdirf_t f,
void *  p 
)

Definition at line 362 of file source.c.

{
       register int  sn;
       register CONTRIB  *scp;
       SRCINDEX  si;
       int  nshadcheck, ncnts;
       int  nhits;
       double  prob, ourthresh, hwt;
       RAY  sr;
                     /* NOTE: srccnt and cntord global so no recursion */
       if (nsources <= 0)
              return;              /* no sources?! */
                                          /* potential contributions */
       initsrcindex(&si);
       for (sn = 0; srcray(&sr, r, &si); sn++) {
              if (sn >= maxcntr) {
                     maxcntr = sn + MAXSPART;
                     srccnt = (CONTRIB *)realloc((void *)srccnt,
                                   maxcntr*sizeof(CONTRIB));
                     cntord = (CNTPTR *)realloc((void *)cntord,
                                   maxcntr*sizeof(CNTPTR));
                     if ((srccnt == NULL) | (cntord == NULL))
                            error(SYSTEM, "out of memory in direct");
              }
              cntord[sn].sndx = sn;
              scp = srccnt + sn;
              scp->sno = sr.rsrc;
                                          /* compute coefficient */
              (*f)(scp->coef, p, sr.rdir, si.dom);
              cntord[sn].brt = intens(scp->coef);
              if (cntord[sn].brt <= 0.0)
                     continue;
#if SHADCACHE
                                          /* check shadow cache */
              if (si.np == 1 && srcblocked(&sr)) {
                     cntord[sn].brt = 0.0;
                     continue;
              }
#endif
              VCOPY(scp->dir, sr.rdir);
              copycolor(sr.rcoef, scp->coef);
                                          /* compute potential */
              sr.revf = srcvalue;
              rayvalue(&sr);
              multcolor(sr.rcol, sr.rcoef);
              copycolor(scp->val, sr.rcol);
              cntord[sn].brt = bright(sr.rcol);
       }
                                          /* sort contributions */
       qsort(cntord, sn, sizeof(CNTPTR), cntcmp);
       {                                  /* find last */
              register int  l, m;

              ncnts = l = sn;
              sn = 0;
              while ((m = (sn + ncnts) >> 1) != l) {
                     if (cntord[m].brt > 0.0)
                            sn = m;
                     else
                            ncnts = m;
                     l = m;
              }
       }
       if (ncnts == 0)
              return;              /* no contributions! */
                                                /* accumulate tail */
        for (sn = ncnts-1; sn > 0; sn--)
                cntord[sn-1].brt += cntord[sn].brt;
                                          /* compute number to check */
       nshadcheck = pow((double)ncnts, shadcert) + .5;
                                          /* modify threshold */
       ourthresh = shadthresh / r->rweight;
                                          /* test for shadows */
       for (nhits = 0, hwt = 0.0, sn = 0; sn < ncnts;
                     hwt += (double)source[scp->sno].nhits /
                            (double)source[scp->sno].ntests,
                     sn++) {
                                          /* check threshold */
              if ((sn+nshadcheck>=ncnts ? cntord[sn].brt :
                            cntord[sn].brt-cntord[sn+nshadcheck].brt)
                            < ourthresh*bright(r->rcol))
                     break;
              scp = srccnt + cntord[sn].sndx;
                                          /* test for hit */
              rayorigin(&sr, SHADOW, r, NULL);
              copycolor(sr.rcoef, scp->coef);
              VCOPY(sr.rdir, scp->dir);
              sr.rsrc = scp->sno;
                                          /* keep statistics */
              if (source[scp->sno].ntests++ > 0xfffffff0) {
                     source[scp->sno].ntests >>= 1;
                     source[scp->sno].nhits >>= 1;
              }
              if (localhit(&sr, &thescene) &&
                            ( sr.ro != source[scp->sno].so ||
                            source[scp->sno].sflags & SFOLLOW )) {
                                          /* follow entire path */
                     raycont(&sr);
                     if (trace != NULL)
                            (*trace)(&sr);       /* trace execution */
                     if (bright(sr.rcol) <= FTINY) {
#if SHADCACHE
                            if ((scp <= srccnt || scp[-1].sno != scp->sno)
                                          && (scp >= srccnt+ncnts-1 ||
                                              scp[1].sno != scp->sno))
                                   srcblocker(&sr);
#endif
                            continue;     /* missed! */
                     }
                     rayparticipate(&sr);
                     multcolor(sr.rcol, sr.rcoef);
                     copycolor(scp->val, sr.rcol);
              } else if (trace != NULL &&
                     (source[scp->sno].sflags & (SDISTANT|SVIRTUAL|SFOLLOW))
                                          == (SDISTANT|SFOLLOW) &&
                            sourcehit(&sr) && rayshade(&sr, sr.ro->omod)) {
                     (*trace)(&sr);              /* trace execution */
                     /* skip call to rayparticipate() & scp->val update */
              }
                                          /* add contribution if hit */
              addcolor(r->rcol, scp->val);
              nhits++;
              source[scp->sno].nhits++;
       }
                                   /* source hit rate */
       if (hwt > FTINY)
              hwt = (double)nhits / hwt;
       else
              hwt = 0.5;
#ifdef DEBUG
       sprintf(errmsg, "%d tested, %d untested, %f conditional hit rate\n",
                     sn, ncnts-sn, hwt);
       eputs(errmsg);
#endif
                                   /* add in untested sources */
       for ( ; sn < ncnts; sn++) {
              scp = srccnt + cntord[sn].sndx;
              prob = hwt * (double)source[scp->sno].nhits /
                            (double)source[scp->sno].ntests;
              if (prob < 1.0)
                     scalecolor(scp->val, prob);
              addcolor(r->rcol, scp->val);
       }
}

Here is the call graph for this function:

OBJREC* findmaterial ( register OBJREC o)

Definition at line 46 of file source.c.

{
       while (!ismaterial(o->otype)) {
              if (o->otype == MOD_ALIAS && o->oargs.nsargs) {
                     OBJECT  aobj;
                     OBJREC  *ao;
                     aobj = lastmod(objndx(o), o->oargs.sarg[0]);
                     if (aobj < 0)
                            objerror(o, USER, "bad reference");
                     ao = objptr(aobj);
                     if (ismaterial(ao->otype))
                            return(ao);
                     if (ao->otype == MOD_ALIAS) {
                            o = ao;
                            continue;
                     }
              }
              if (o->omod == OVOID)
                     return(NULL);
              o = objptr(o->omod);
       }
       return(o);           /* mixtures will return NULL */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void freesources ( void  )

Definition at line 159 of file source.c.

{
       if (nsources > 0) {
#if SHADCACHE
              while (nsources--)
                     freeobscache(&source[nsources]);
#endif
              free((void *)source);
              source = NULL;
              nsources = 0;
       }
       if (maxcntr <= 0)
              return;
       free((void *)srccnt);
       srccnt = NULL;
       free((void *)cntord);
       cntord = NULL;
       maxcntr = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int m_light ( register OBJREC m,
register RAY r 
)

Definition at line 679 of file source.c.

{
                                          /* check for over-counting */
       if (badcomponent(m, r)) {
              setcolor(r->rcoef, 0.0, 0.0, 0.0);
              return(1);
       }
       if (wrongsource(m, r)) {
              setcolor(r->rcoef, 0.0, 0.0, 0.0);
              return(1);
       }
                                          /* check for passed illum */
       if (passillum(m, r)) {
              if (m->oargs.nsargs && strcmp(m->oargs.sarg[0], VOIDID))
                     return(rayshade(r,lastmod(objndx(m),m->oargs.sarg[0])));
              raytrans(r);
              return(1);
       }
                                          /* check for invisibility */
       if (srcignore(m, r)) {
              setcolor(r->rcoef, 0.0, 0.0, 0.0);
              return(1);
       }
                                   /* otherwise treat as source */
                                          /* check for behind */
       if (r->rod < 0.0)
              return(1);
                                          /* check for outside spot */
       if (m->otype==MAT_SPOT && spotout(r, makespot(m)))
              return(1);
                                          /* get distribution pattern */
       raytexture(r, m->omod);
                                          /* get source color */
       setcolor(r->rcol, m->oargs.farg[0],
                       m->oargs.farg[1],
                       m->oargs.farg[2]);
                                          /* modify value */
       multcolor(r->rcol, r->pcol);
       return(1);
}

Here is the call graph for this function:

void marksources ( void  )

Definition at line 72 of file source.c.

{
       int  foundsource = 0;
       int  i;
       register OBJREC  *o, *m;
       register int  ns;
                                   /* initialize dispatch table */
       initstypes();
                                   /* find direct sources */
       for (i = 0; i < nsceneobjs; i++) {
       
              o = objptr(i);

              if (!issurface(o->otype) || o->omod == OVOID)
                     continue;
                                   /* find material */
              m = findmaterial(objptr(o->omod));
              if (m == NULL)
                     continue;
              if (m->otype == MAT_CLIP) {
                     markclip(m);  /* special case for antimatter */
                     continue;
              }
              if (!islight(m->otype))
                     continue;     /* not source modifier */
       
              if (m->oargs.nfargs != (m->otype == MAT_GLOW ? 4 :
                            m->otype == MAT_SPOT ? 7 : 3))
                     objerror(m, USER, "bad # arguments");

              if (m->otype == MAT_GLOW &&
                            o->otype != OBJ_SOURCE &&
                            m->oargs.farg[3] <= FTINY)
                     continue;                   /* don't bother */
              if (m->oargs.farg[0] <= FTINY && m->oargs.farg[1] <= FTINY &&
                            m->oargs.farg[2] <= FTINY)
                     continue;                   /* don't bother */

              if (sfun[o->otype].of == NULL ||
                            sfun[o->otype].of->setsrc == NULL)
                     objerror(o, USER, "illegal material");

              if ((ns = newsource()) < 0)
                     goto memerr;

              setsource(&source[ns], o);

              if (m->otype == MAT_GLOW) {
                     source[ns].sflags |= SPROX;
                     source[ns].sl.prox = m->oargs.farg[3];
                     if (source[ns].sflags & SDISTANT)
                            source[ns].sflags |= SSKIP;
              } else if (m->otype == MAT_SPOT) {
                     source[ns].sflags |= SSPOT;
                     if ((source[ns].sl.s = makespot(m)) == NULL)
                            goto memerr;
                     if (source[ns].sflags & SFLAT &&
                            !checkspot(source[ns].sl.s,source[ns].snorm)) {
                            objerror(o, WARNING,
                                   "invalid spotlight direction");
                            source[ns].sflags |= SSKIP;
                     }
              }
#if  SHADCACHE
              initobscache(ns);
#endif
              if (!(source[ns].sflags & SSKIP))
                     foundsource++;
       }
       if (!foundsource) {
              error(WARNING, "no light sources found");
              return;
       }
       markvirtuals();                    /* find and add virtual sources */
                            /* allocate our contribution arrays */
       maxcntr = nsources + MAXSPART;     /* start with this many */
       srccnt = (CONTRIB *)malloc(maxcntr*sizeof(CONTRIB));
       cntord = (CNTPTR *)malloc(maxcntr*sizeof(CNTPTR));
       if ((srccnt == NULL) | (cntord == NULL))
              goto memerr;
       return;
memerr:
       error(SYSTEM, "out of memory in marksources");
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sourcehit ( register RAY r)

Definition at line 277 of file source.c.

{
       int  glowsrc = -1;
       int  transrc = -1;
       int  first, last;
       register int  i;

       if (r->rsrc >= 0) {         /* check only one if aimed */
              first = last = r->rsrc;
       } else {                    /* otherwise check all */
              first = 0; last = nsources-1;
       }
       for (i = first; i <= last; i++) {
              if ((source[i].sflags & (SDISTANT|SVIRTUAL)) != SDISTANT)
                     continue;
              /*
               * Check to see if ray is within
               * solid angle of source.
               */
              if (2.*PI*(1. - DOT(source[i].sloc,r->rdir)) > source[i].ss2)
                     continue;
                                   /* is it the only possibility? */
              if (first == last) {
                     r->ro = source[i].so;
                     break;
              }
              /*
               * If it's a glow or transparent illum, just remember it.
               */
              if (source[i].sflags & SSKIP) {
                     glowsrc = i;
                     continue;
              }
              if (transillum(source[i].so->omod)) {
                     transrc = i;
                     continue;
              }
              r->ro = source[i].so;       /* otherwise, use first hit */
              break;
       }
       /*
        * Do we need fallback?
        */
       if (r->ro == NULL) {
              if (transrc >= 0 && r->crtype & (AMBIENT|SPECULAR))
                     return(0);    /* avoid overcounting */
              if (glowsrc >= 0)
                     r->ro = source[glowsrc].so;
              else
                     return(0);    /* nothing usable */
       }
       /*
        * Make assignments.
        */
       r->robj = objndx(r->ro);
       for (i = 0; i < 3; i++)
              r->ron[i] = -r->rdir[i];
       r->rod = 1.0;
       r->pert[0] = r->pert[1] = r->pert[2] = 0.0;
       r->uv[0] = r->uv[1] = 0.0;
       r->rox = NULL;
       return(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int srcray ( register RAY sr,
RAY r,
SRCINDEX si 
)

Definition at line 181 of file source.c.

{
    double  d;                            /* distance to source */
    register SRCREC  *srcp;

    rayorigin(sr, SHADOW, r, NULL);              /* ignore limits */

    while ((d = nextssamp(sr, si)) != 0.0) {
       sr->rsrc = si->sn;                 /* remember source */
       srcp = source + si->sn;
       if (srcp->sflags & SDISTANT) {
              if (srcp->sflags & SSPOT && spotout(sr, srcp->sl.s))
                     continue;
              return(1);           /* sample OK */
       }
                            /* local source */
                                          /* check proximity */
       if (srcp->sflags & SPROX && d > srcp->sl.prox)
              continue;
                                          /* check angle */
       if (srcp->sflags & SSPOT) {
              if (spotout(sr, srcp->sl.s))
                     continue;
                                   /* adjust solid angle */
              si->dom *= d*d;
              d += srcp->sl.s->flen;
              si->dom /= d*d;
       }
       return(1);                  /* sample OK */
    }
    return(0);                     /* no more samples */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void srcscatter ( register RAY r)

Definition at line 513 of file source.c.

{
       int  oldsampndx;
       int  nsamps;
       RAY  sr;
       SRCINDEX  si;
       double  t, d;
       double  re, ge, be;
       COLOR  cvext;
       int  i, j;

       if (r->slights == NULL || r->slights[0] == 0
                     || r->gecc >= 1.-FTINY || r->rot >= FHUGE)
              return;
       if (ssampdist <= FTINY || (nsamps = r->rot/ssampdist + .5) < 1)
              nsamps = 1;
#if MAXSSAMP
       else if (nsamps > MAXSSAMP)
              nsamps = MAXSSAMP;
#endif
       oldsampndx = samplendx;
       samplendx = random()&0x7fff;              /* randomize */
       for (i = r->slights[0]; i > 0; i--) {     /* for each source */
              for (j = 0; j < nsamps; j++) {     /* for each sample position */
                     samplendx++;
                     t = r->rot * (j+frandom())/nsamps;
                                                 /* extinction */
                     re = t*colval(r->cext,RED);
                     ge = t*colval(r->cext,GRN);
                     be = t*colval(r->cext,BLU);
                     setcolor(cvext,      re > 92. ? 0. : exp(-re),
                                   ge > 92. ? 0. : exp(-ge),
                                   be > 92. ? 0. : exp(-be));
                     if (intens(cvext) <= FTINY)
                            break;               /* too far away */
                     sr.rorg[0] = r->rorg[0] + r->rdir[0]*t;
                     sr.rorg[1] = r->rorg[1] + r->rdir[1]*t;
                     sr.rorg[2] = r->rorg[2] + r->rdir[2]*t;
                     sr.rmax = 0.;
                     initsrcindex(&si);   /* sample ray to this source */
                     si.sn = r->slights[i];
                     nopart(&si, &sr);
                     if (!srcray(&sr, NULL, &si) ||
                                   sr.rsrc != r->slights[i])
                            continue;            /* no path */
#if SHADCACHE
                     if (srcblocked(&sr))        /* check shadow cache */
                            continue;
#endif
                     copycolor(sr.cext, r->cext);
                     copycolor(sr.albedo, r->albedo);
                     sr.gecc = r->gecc;
                     sr.slights = r->slights;
                     rayvalue(&sr);                     /* eval. source ray */
                     if (bright(sr.rcol) <= FTINY) {
#if SHADCACHE
                            srcblocker(&sr);     /* add blocker to cache */
#endif
                            continue;
                     }
                     if (r->gecc <= FTINY)              /* compute P(theta) */
                            d = 1.;
                     else {
                            d = DOT(r->rdir, sr.rdir);
                            d = 1. + r->gecc*r->gecc - 2.*r->gecc*d;
                            d = (1. - r->gecc*r->gecc) / (d*sqrt(d));
                     }
                                                 /* other factors */
                     d *= si.dom * r->rot / (4.*PI*nsamps);
                     multcolor(sr.rcol, r->cext);
                     multcolor(sr.rcol, r->albedo);
                     scalecolor(sr.rcol, d);
                     multcolor(sr.rcol, cvext);
                     addcolor(r->rcol, sr.rcol); /* add it in */
              }
       }
       samplendx = oldsampndx;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void srcvalue ( register RAY r)

Definition at line 220 of file source.c.

{
       register SRCREC  *sp;

       sp = &source[r->rsrc];
       if (sp->sflags & SVIRTUAL) {       /* virtual source */
                                   /* check intersection */
              if (!(*ofun[sp->so->otype].funp)(sp->so, r))
                     return;
              if (!rayshade(r, r->ro->omod))     /* compute contribution */
                     goto nomat;
              rayparticipate(r);
              return;
       }
                                   /* compute intersection */
       if (sp->sflags & SDISTANT ? sourcehit(r) :
                     (*ofun[sp->so->otype].funp)(sp->so, r)) {
              if (sp->sa.success >= 0)
                     sp->sa.success++;
              if (!rayshade(r, r->ro->omod))     /* compute contribution */
                     goto nomat;
              rayparticipate(r);
              return;
       }
                                   /* we missed our mark! */
       if (sp->sa.success < 0)
              return;                     /* bitched already */
       sp->sa.success -= AIMREQT;
       if (sp->sa.success >= 0)
              return;                     /* leniency */
       sprintf(errmsg, "aiming failure for light source \"%s\"",
                     sp->so->oname);
       error(WARNING, errmsg);            /* issue warning */
       return;
nomat:
       objerror(r->ro, USER, "material not found");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int transillum ( OBJECT  obj) [static]

Definition at line 262 of file source.c.

{
       OBJREC *m = findmaterial(objptr(obj));
       
       if (m == NULL)
              return(1);
       if (m->otype != MAT_ILLUM)
              return(0);
       return(!m->oargs.nsargs || !strcmp(m->oargs.sarg[0], VOIDID));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int weaksrcmat ( OBJECT  obj) [static]

Definition at line 612 of file source.c.

{
       OBJREC *m = findmaterial(objptr(obj));
       
       if (m == NULL) return(0);
       return((m->otype==MAT_ILLUM) | (m->otype==MAT_GLOW));
}

Here is the call graph for this function:


Variable Documentation

CNTPTR* cntord [static]

Definition at line 39 of file source.c.

int maxcntr = 0 [static]

Definition at line 40 of file source.c.

const char RCSid[] = "$Id: source.c,v 2.57 2008/07/17 18:26:01 greg Exp $" [static]

Definition at line 2 of file source.c.

CONTRIB* srccnt [static]

Definition at line 38 of file source.c.

double ssampdist

Definition at line 135 of file raycalls.c.