--- ray/src/rt/raytrace.c 1991/10/23 13:43:45 1.23 +++ ray/src/rt/raytrace.c 1993/02/23 13:57:11 2.4 @@ -18,6 +18,8 @@ static char SCCSid[] = "$SunId$ LBL"; #include "otspecial.h" +#define MAXCSET ((MAXSET+1)*2-1) /* maximum check set size */ + extern CUBE thescene; /* our scene */ extern int maxdepth; /* maximum recursion depth */ extern double minweight; /* minimum ray weight */ @@ -29,7 +31,7 @@ long nrays = 0L; /* number of calls to localhit */ static FLOAT Lambfa[5] = {PI, PI, PI, 0.0, 0.0}; OBJREC Lamb = { OVOID, MAT_PLASTIC, "Lambertian", - {0, 5, NULL, Lambfa}, NULL, -1, + {0, 5, NULL, Lambfa}, NULL, }; /* a Lambertian surface */ #define MAXLOOP 128 /* modifier loop detection */ @@ -151,7 +153,6 @@ int mod; m = &Lamb; } (*ofun[m->otype].funp)(m, r); /* execute function */ - m->lastrno = r->rno; if (ismaterial(m->otype)) { /* materials call raytexture */ depth--; return; /* we're done */ @@ -178,7 +179,6 @@ int mod; error(USER, errmsg); } (*ofun[m->otype].funp)(m, r); - m->lastrno = r->rno; } depth--; /* end here */ } @@ -318,6 +318,7 @@ localhit(r, scene) /* check for hit in the octree */ register RAY *r; register CUBE *scene; { + OBJECT cxset[MAXCSET+1]; /* set of checked objects */ FVECT curpos; /* current cube position */ int sflags; /* sign flags */ double t, dt; @@ -358,13 +359,15 @@ register CUBE *scene; if (!incube(scene, curpos)) /* non-intersecting ray */ return(0); } - return(raymove(curpos, sflags, r, scene) == RAYHIT); + cxset[0] = 0; + return(raymove(curpos, cxset, sflags, r, scene) == RAYHIT); } static int -raymove(pos, dirf, r, cu) /* check for hit as we move */ -FVECT pos; /* modified */ +raymove(pos, cxs, dirf, r, cu) /* check for hit as we move */ +FVECT pos; /* current position, modified herein */ +OBJECT *cxs; /* checked objects, modified by checkhit */ int dirf; /* direction indicators to speed tests */ register RAY *r; register CUBE *cu; @@ -393,7 +396,7 @@ register CUBE *cu; } for ( ; ; ) { cukid.cutree = octkid(cu->cutree, br); - if ((ax = raymove(pos,dirf,r,&cukid)) == RAYHIT) + if ((ax = raymove(pos,cxs,dirf,r,&cukid)) == RAYHIT) return(RAYHIT); sgn = 1 << ax; if (sgn & dirf) /* positive axis? */ @@ -412,7 +415,7 @@ register CUBE *cu; } /*NOTREACHED*/ } - if (isfull(cu->cutree) && checkhit(r, cu)) + if (isfull(cu->cutree) && checkhit(r, cu, cxs)) return(RAYHIT); /* advance to next cube */ if (dirf&0x11) { @@ -445,24 +448,57 @@ register CUBE *cu; static -checkhit(r, cu) /* check for hit in full cube */ +checkhit(r, cu, cxs) /* check for hit in full cube */ register RAY *r; CUBE *cu; +OBJECT *cxs; { OBJECT oset[MAXSET+1]; register OBJREC *o; register int i; objset(oset, cu->cutree); + checkset(oset, cxs); /* eliminate double-checking */ for (i = oset[0]; i > 0; i--) { o = objptr(oset[i]); - if (o->lastrno == r->rno) /* checked already? */ - continue; + if (o->omod == OVOID && issurface(o->otype)) + continue; /* ignore void surfaces */ (*ofun[o->otype].funp)(o, r); - o->lastrno = r->rno; } if (r->ro == NULL) return(0); /* no scores yet */ return(incube(cu, r->rop)); /* hit OK if in current cube */ +} + + +static +checkset(os, cs) /* modify checked set and set to check */ +register OBJECT *os; /* os' = os - cs */ +register OBJECT *cs; /* cs' = cs + os */ +{ + OBJECT cset[MAXCSET+MAXSET+1]; + register int i, j; + int k; + /* copy os in place, cset <- cs */ + cset[0] = 0; + k = 0; + for (i = j = 1; i <= os[0]; i++) { + while (j <= cs[0] && cs[j] < os[i]) + cset[++cset[0]] = cs[j++]; + if (j > cs[0] || os[i] != cs[j]) { /* object to check */ + os[++k] = os[i]; + cset[++cset[0]] = os[i]; + } + } + if (!(os[0] = k)) /* new "to check" set size */ + return; /* special case */ + while (j <= cs[0]) /* get the rest of cs */ + cset[++cset[0]] = cs[j++]; + if (cset[0] > MAXCSET) /* truncate "checked" set if nec. */ + cset[0] = MAXCSET; + /* setcopy(cs, cset); */ /* copy cset back to cs */ + os = cset; + for (i = os[0]; i-- >= 0; ) + *cs++ = *os++; }