Page MenuHomec4science

srcobstr.c
No OneTemporary

File Metadata

Created
Thu, Jan 30, 17:20

srcobstr.c

#ifndef lint
static const char RCSid[] = "$Id: srcobstr.c,v 2.19 2017/02/22 03:16:20 greg Exp $";
#endif
/*
* Source occlusion caching routines
*/
#include "ray.h"
#include "otypes.h"
#include "otspecial.h"
#include "rtotypes.h"
#include "source.h"
#if SHADCACHE /* preemptive shadow checking */
#ifndef MAX2SHADE
#define MAX2SHADE 200 /* limit # of sources to precheck */
#endif
#define ABS(x) ((x)>0 ? (x) : -(x))
OBJECT * antimodlist = NULL; /* set of clipped materials */
static int /* cast source ray to first blocker */
castshadow(int sn, FVECT rorg, FVECT rdir)
{
RAY rt;
VCOPY(rt.rorg, rorg);
VCOPY(rt.rdir, rdir);
rt.rmax = 0;
rayorigin(&rt, PRIMARY, NULL, NULL);
/* check for intersection */
while (localhit(&rt, &thescene)) {
RAY rt1 = rt; /* pretend we were aimed at source */
rt1.crtype |= rt1.rtype = SHADOW;
rt1.rdir[0] = -rt.rdir[0];
rt1.rdir[1] = -rt.rdir[1];
rt1.rdir[2] = -rt.rdir[2];
rt1.rod = -rt.rod;
VSUB(rt1.rorg, rt.rop, rt.rdir);
rt1.rot = 1.;
rt1.rsrc = sn;
/* record blocker */
if (srcblocker(&rt1))
return(1);
/* move past failed blocker */
VSUM(rt.rorg, rt.rop, rt.rdir, FTINY);
rayclear(&rt); /* & try again... */
}
return(0); /* found no blockers */
}
void /* initialize occlusion cache */
initobscache(int sn)
{
SRCREC *srcp = &source[sn];
int cachelen;
FVECT rorg, rdir;
RREAL d;
int i, j, k;
int ax=0, ax1=1, ax2=2;
if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
return; /* don't cache these */
if (srcp->sflags & SDISTANT)
cachelen = 4*SHADCACHE*SHADCACHE;
else if (srcp->sflags & SFLAT)
cachelen = SHADCACHE*SHADCACHE*3 + (SHADCACHE&1)*SHADCACHE*4;
else /* spherical distribution */
cachelen = SHADCACHE*SHADCACHE*6;
/* allocate cache */
srcp->obscache = (OBSCACHE *)malloc(sizeof(OBSCACHE) +
sizeof(OBJECT)*(cachelen-1));
if (srcp->obscache == NULL)
error(SYSTEM, "out of memory in initobscache()");
/* set parameters */
if (srcp->sflags & SDISTANT) {
RREAL amax = 0;
for (ax1 = 3; ax1--; )
if (ABS(srcp->sloc[ax1]) > amax) {
amax = ABS(srcp->sloc[ax1]);
ax = ax1;
}
srcp->obscache->p.d.ax = ax;
ax1 = (ax+1)%3;
ax2 = (ax+2)%3;
VCOPY(srcp->obscache->p.d.o, thescene.cuorg);
if (srcp->sloc[ax] > 0)
srcp->obscache->p.d.o[ax] += thescene.cusize;
if (srcp->sloc[ax1] < 0)
srcp->obscache->p.d.o[ax1] += thescene.cusize *
srcp->sloc[ax1] / amax;
if (srcp->sloc[ax2] < 0)
srcp->obscache->p.d.o[ax2] += thescene.cusize *
srcp->sloc[ax2] / amax;
srcp->obscache->p.d.e1 = 1. / (thescene.cusize*(1. +
fabs(srcp->sloc[ax1])/amax));
srcp->obscache->p.d.e2 = 1. / (thescene.cusize*(1. +
fabs(srcp->sloc[ax2])/amax));
} else if (srcp->sflags & SFLAT) {
VCOPY(srcp->obscache->p.f.u, srcp->ss[SU]);
normalize(srcp->obscache->p.f.u);
fcross(srcp->obscache->p.f.v,
srcp->snorm, srcp->obscache->p.f.u);
}
/* clear cache */
for (i = cachelen; i--; )
srcp->obscache->obs[i] = OVOID;
#if (MAX2SHADE >= 0)
if (sn >= MAX2SHADE) /* limit on prechecking */
return;
#endif
/* cast shadow rays */
if (srcp->sflags & SDISTANT) {
for (k = 3; k--; )
rdir[k] = -srcp->sloc[k];
for (i = 2*SHADCACHE; i--; )
for (j = 2*SHADCACHE; j--; ) {
VCOPY(rorg, srcp->obscache->p.d.o);
rorg[ax1] += (i+.5) /
(2*SHADCACHE*srcp->obscache->p.d.e1);
rorg[ax2] += (j+.5) /
(2*SHADCACHE*srcp->obscache->p.d.e2);
castshadow(sn, rorg, rdir);
}
} else if (srcp->sflags & SFLAT) {
d = 0.01*srcp->srad;
VSUM(rorg, srcp->sloc, srcp->snorm, d);
for (i = SHADCACHE; i--; )
for (j = SHADCACHE; j--; ) {
d = 2./SHADCACHE*(i+.5) - 1.;
VSUM(rdir, srcp->snorm,
srcp->obscache->p.f.u, d);
d = 2./SHADCACHE*(j+.5) - 1.;
VSUM(rdir, rdir, srcp->obscache->p.f.v, d);
normalize(rdir);
castshadow(sn, rorg, rdir);
}
for (k = 2; k--; )
for (i = SHADCACHE; i--; )
for (j = SHADCACHE>>1; j--; ) {
d = 2./SHADCACHE*(i+.5) - 1.;
if (k)
VSUM(rdir, srcp->obscache->p.f.u,
srcp->obscache->p.f.v, d);
else
VSUM(rdir, srcp->obscache->p.f.v,
srcp->obscache->p.f.u, d);
d = 1. - 2./SHADCACHE*(j+.5);
VSUM(rdir, rdir, srcp->snorm, d);
normalize(rdir);
castshadow(sn, rorg, rdir);
d = 2.*DOT(rdir, srcp->snorm);
rdir[0] = d*srcp->snorm[0] - rdir[0];
rdir[1] = d*srcp->snorm[1] - rdir[1];
rdir[2] = d*srcp->snorm[2] - rdir[2];
castshadow(sn, rorg, rdir);
}
} else /* spherical distribution */
for (k = 6; k--; ) {
ax = k%3;
ax1 = (k+1)%3;
ax2 = (k+2)%3;
for (i = SHADCACHE; i--; )
for (j = SHADCACHE; j--; ) {
rdir[0]=rdir[1]=rdir[2] = 0.;
rdir[ax] = k<3 ? 1. : -1.;
rdir[ax1] = 2./SHADCACHE*(i+.5) - 1.;
rdir[ax2] = 2./SHADCACHE*(j+.5) - 1.;
normalize(rdir);
d = 1.05*srcp->srad;
VSUM(rorg, srcp->sloc, rdir, d);
castshadow(sn, rorg, rdir);
}
}
}
static OBJECT * /* return occluder cache entry */
srcobstructp(RAY *r)
{
static RNUMBER lastrno = ~0;
static OBJECT noobs;
static OBJECT *lastobjp;
SRCREC *srcp;
int ondx;
noobs = OVOID;
if (r->rno == lastrno)
return lastobjp; /* just recall last pointer */
DCHECK(r->rsrc < 0, CONSISTENCY,
"srcobstructp() called with unaimed ray");
lastrno = r->rno;
lastobjp = &noobs;
srcp = &source[r->rsrc];
if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL))
return(&noobs); /* don't cache these */
if (srcp->obscache == NULL) /* initialize cache */
initobscache(r->rsrc);
/* compute cache index */
if (srcp->sflags & SDISTANT) {
int ax=0, ax1=1, ax2=2;
double t;
ax = srcp->obscache->p.d.ax;
if ((ax1 = ax+1) >= 3) ax1 -= 3;
if ((ax2 = ax+2) >= 3) ax2 -= 3;
t = (srcp->obscache->p.d.o[ax] - r->rorg[ax]) / srcp->sloc[ax];
if (t <= FTINY)
return(&noobs); /* could happen if ray is outside */
ondx = 2*SHADCACHE*(int)(2*SHADCACHE*srcp->obscache->p.d.e1 *
(r->rorg[ax1] + t*srcp->sloc[ax1] -
srcp->obscache->p.d.o[ax1]));
ondx += (int)(2*SHADCACHE*srcp->obscache->p.d.e2 *
(r->rorg[ax2] + t*srcp->sloc[ax2] -
srcp->obscache->p.d.o[ax2]));
if ((ondx < 0) | (ondx >= 4*SHADCACHE*SHADCACHE))
return(&noobs); /* could happen if ray is outside */
} else if (srcp->sflags & SFLAT) {
FVECT sd;
RREAL sd0m, sd1m;
sd[0] = -DOT(r->rdir, srcp->obscache->p.f.u);
sd[1] = -DOT(r->rdir, srcp->obscache->p.f.v);
sd[2] = -DOT(r->rdir, srcp->snorm);
if (sd[2] < 0)
return(&noobs); /* shouldn't happen */
sd0m = ABS(sd[0]);
sd1m = ABS(sd[1]);
if (sd[2] >= sd0m && sd[2] >= sd1m) {
ondx = SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
(1. + sd[0]/sd[2]));
ondx += (int)(SHADCACHE*(.5-FTINY) *
(1. + sd[1]/sd[2]));
} else if (sd0m >= sd1m) {
ondx = SHADCACHE*SHADCACHE;
if (sd[0] < 0)
ondx += ((SHADCACHE+1)>>1)*SHADCACHE;
ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
(1. - sd[2]/sd0m));
ondx += (int)(SHADCACHE*(.5-FTINY) *
(1. + sd[1]/sd0m));
} else /* sd1m > sd0m */ {
ondx = SHADCACHE*SHADCACHE +
((SHADCACHE+1)>>1)*SHADCACHE*2;
if (sd[1] < 0)
ondx += ((SHADCACHE+1)>>1)*SHADCACHE;
ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
(1. - sd[2]/sd1m));
ondx += (int)(SHADCACHE*(.5-FTINY) *
(1. + sd[0]/sd1m));
}
DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*3 +
(SHADCACHE&1)*SHADCACHE*4), CONSISTENCY,
"flat source cache index out of bounds");
} else /* spherical distribution */ {
int ax, ax1, ax2;
RREAL amax = 0;
for (ax1 = 3; ax1--; )
if (ABS(r->rdir[ax1]) > amax) {
amax = ABS(r->rdir[ax1]);
ax = ax1;
}
if ((ax1 = ax+1) >= 3) ax1 -= 3;
if ((ax2 = ax+2) >= 3) ax2 -= 3;
ondx = 2*SHADCACHE*SHADCACHE * ax;
if (r->rdir[ax] < 0)
ondx += SHADCACHE*SHADCACHE;
ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) *
(1. + r->rdir[ax1]/amax));
ondx += (int)(SHADCACHE*(.5-FTINY) *
(1. + r->rdir[ax2]/amax));
DCHECK((ondx < 0) | (ondx >= SHADCACHE*SHADCACHE*6), CONSISTENCY,
"radial source cache index out of bounds");
}
/* return cache pointer */
return(lastobjp = &srcp->obscache->obs[ondx]);
}
void /* free obstruction cache */
freeobscache(SRCREC *srcp)
{
if (srcp->obscache == NULL)
return;
free((void *)srcp->obscache);
srcp->obscache = NULL;
}
int /* record a source blocker */
srcblocker(RAY *r)
{
OBJREC *m;
if (r->robj == OVOID || objptr(r->robj) != r->ro ||
isvolume(r->ro->otype))
return(0); /* don't record complex blockers */
if (r->rsrc < 0 || source[r->rsrc].so == r->ro)
return(0); /* just a mistake, that's all */
if (antimodlist != NULL && inset(antimodlist, r->ro->omod))
return(0); /* could be clipped */
m = findmaterial(r->ro);
if (m == NULL)
return(0); /* no material?! */
if (!isopaque(m->otype))
return(0); /* material not a reliable blocker */
*srcobstructp(r) = r->robj; /* else record obstructor */
return(1);
}
int /* check ray against cached blocker */
srcblocked(RAY *r)
{
OBJECT obs = *srcobstructp(r);
OBJREC *op;
if (obs == OVOID)
return(0);
op = objptr(obs); /* check blocker intersection */
if (!(*ofun[op->otype].funp)(op, r))
return(0);
if (source[r->rsrc].sflags & SDISTANT)
return(1);
op = source[r->rsrc].so; /* check source intersection */
if (!(*ofun[op->otype].funp)(op, r))
return(1);
rayclear(r);
return(0); /* source in front */
}
void /* record potentially clipped materials */
markclip(OBJREC *m)
{
OBJECT *set2add, *oldset;
if (m == NULL) { /* starting over */
if (antimodlist != NULL)
free((void *)antimodlist);
antimodlist = NULL;
return;
}
m_clip(m, NULL); /* initialize modifier list */
if ((set2add = (OBJECT *)m->os) == NULL || !set2add[0])
return;
if (antimodlist == NULL) { /* start of list */
antimodlist = setsave(set2add);
return;
}
/* else add to previous list */
oldset = antimodlist;
antimodlist = (OBJECT *)malloc((oldset[0]+set2add[0]+1)*sizeof(OBJECT));
if (antimodlist == NULL)
error(SYSTEM, "out of memory in markclip");
setunion(antimodlist, oldset, set2add);
free((void *)oldset);
}
#else /* SHADCACHE */
void /* no-op also avoids linker warning */
markclip(OBJREC *m)
{
(void)m;
}
#endif /* SHADCACHE */

Event Timeline