--- ray/src/rt/srcobstr.c 2004/01/01 19:31:46 2.2 +++ ray/src/rt/srcobstr.c 2011/02/14 20:13:38 2.16 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: srcobstr.c,v 2.2 2004/01/01 19:31:46 greg Exp $"; +static const char RCSid[] = "$Id: srcobstr.c,v 2.16 2011/02/14 20:13:38 greg Exp $"; #endif /* * Source occlusion caching routines @@ -11,6 +11,8 @@ static const char RCSid[] = "$Id: srcobstr.c,v 2.2 200 #include "otspecial.h" +#include "rtotypes.h" + #include "source.h" #define ABS(x) ((x)>0 ? (x) : -(x)) @@ -19,7 +21,10 @@ static const char RCSid[] = "$Id: srcobstr.c,v 2.2 200 #if SHADCACHE /* preemptive shadow checking */ -static void /* cast source ray to first blocker */ +OBJECT * antimodlist = NULL; /* set of clipped materials */ + + +static int /* cast source ray to first blocker */ castshadow(int sn, FVECT rorg, FVECT rdir) { RAY rt; @@ -27,24 +32,30 @@ castshadow(int sn, FVECT rorg, FVECT rdir) VCOPY(rt.rorg, rorg); VCOPY(rt.rdir, rdir); rt.rmax = 0; - rayorigin(&rt, NULL, PRIMARY, 1.0); - if (!localhit(&rt, &thescene)) - return; - /* pretend we were aimed at source */ - rt.crtype |= rt.rtype = SHADOW; - rt.rdir[0] = -rt.rdir[0]; - rt.rdir[1] = -rt.rdir[1]; - rt.rdir[2] = -rt.rdir[2]; - rt.rod = -rt.rod; - VSUB(rt.rorg, rt.rop, rt.rdir); - rt.rot = 1.; - rt.rsrc = sn; + 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 */ - srcblocker(&rt); + 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 */ } -static void /* initialize occlusion cache */ +void /* initialize occlusion cache */ initobscache(int sn) { register SRCREC *srcp = &source[sn]; @@ -54,6 +65,8 @@ initobscache(int sn) int i, j, k; int ax, ax1, ax2; + 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) @@ -61,8 +74,6 @@ initobscache(int sn) else /* spherical distribution */ cachelen = SHADCACHE*SHADCACHE*6; /* allocate cache */ - DCHECK(srcp->obscache != NULL, - CONSISTENCY, "initobscache() called twice"); srcp->obscache = (OBSCACHE *)malloc(sizeof(OBSCACHE) + sizeof(OBJECT)*(cachelen-1)); if (srcp->obscache == NULL) @@ -136,7 +147,7 @@ initobscache(int sn) else VSUM(rdir, srcp->obscache->p.f.v, srcp->obscache->p.f.u, d); - d = 2./SHADCACHE*(j+.5); + d = 1. - 2./SHADCACHE*(j+.5); VSUM(rdir, rdir, srcp->snorm, d); normalize(rdir); castshadow(sn, rorg, rdir); @@ -169,13 +180,19 @@ initobscache(int sn) static OBJECT * /* return occluder cache entry */ srcobstructp(register 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"); - noobs = OVOID; + lastrno = r->rno; + lastobjp = &noobs; srcp = &source[r->rsrc]; if (srcp->sflags & (SSKIP|SPROX|SSPOT|SVIRTUAL)) return(&noobs); /* don't cache these */ @@ -197,7 +214,7 @@ srcobstructp(register RAY *r) 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) + if ((ondx < 0) | (ondx >= 4*SHADCACHE*SHADCACHE)) return(&noobs); /* could happen if ray is outside */ } else if (srcp->sflags & SFLAT) { FVECT sd; @@ -219,7 +236,7 @@ srcobstructp(register RAY *r) if (sd[0] < 0) ondx += ((SHADCACHE+1)>>1)*SHADCACHE; ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) * - sd[2]/sd0m); + (1. - sd[2]/sd0m)); ondx += (int)(SHADCACHE*(.5-FTINY) * (1. + sd[1]/sd0m)); } else /* sd1m > sd0m */ { @@ -228,10 +245,13 @@ srcobstructp(register RAY *r) if (sd[1] < 0) ondx += ((SHADCACHE+1)>>1)*SHADCACHE; ondx += SHADCACHE*(int)(SHADCACHE*(.5-FTINY) * - sd[2]/sd1m); + (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; @@ -249,9 +269,11 @@ srcobstructp(register RAY *r) (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(&srcp->obscache->obs[ondx]); + return(lastobjp = &srcp->obscache->obs[ondx]); } @@ -265,20 +287,25 @@ freeobscache(SRCREC *srcp) } -void /* record a source blocker */ +int /* record a source blocker */ srcblocker(register RAY *r) { OBJREC *m; if (r->robj == OVOID || objptr(r->robj) != r->ro || isvolume(r->ro->otype)) - return; /* don't record complex blockers */ + 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; /* no material?! */ - if (!(ofun[m->otype].flags & T_OPAQUE)) - return; /* material not a reliable blocker */ + return(0); /* no material?! */ + if (!isopaque(m->otype)) + return(0); /* material not a reliable blocker */ *srcobstructp(r) = r->robj; /* else record obstructor */ + return(1); } @@ -290,8 +317,55 @@ srcblocked(RAY *r) if (obs == OVOID) return(0); - op = objptr(obs); /* check for intersection */ - return((*ofun[op->otype].funp)(op, r)); + 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; }