static void addface( /* add a face to a cube */ register CUBE *cu, OBJECT obj ) { if (o_face(objptr(obj), cu) == O_MISS) return; if (istree(cu->cutree)) { CUBE cukid; /* do children */ int i, j; cukid.cusize = cu->cusize * 0.5; for (i = 0; i < 8; i++) { cukid.cutree = octkid(cu->cutree, i); for (j = 0; j < 3; j++) { cukid.cuorg[j] = cu->cuorg[j]; if ((1<<j) & i) cukid.cuorg[j] += cukid.cusize; } addface(&cukid, obj); octkid(cu->cutree, i) = cukid.cutree; } return; } if (isempty(cu->cutree)) { OBJECT oset[2]; /* singular set */ oset[0] = 1; oset[1] = obj; cu->cutree = fullnode(oset); return; } /* add to full node */ add2full(cu, obj); }
static void addobject( /* add an object to a cube */ register CUBE *cu, OBJECT obj ) { int inc; inc = (*ofun[objptr(obj)->otype].funp)(objptr(obj), cu); if (inc == O_MISS) return; /* no intersection */ if (istree(cu->cutree)) { CUBE cukid; /* do children */ int i, j; cukid.cusize = cu->cusize * 0.5; for (i = 0; i < 8; i++) { cukid.cutree = octkid(cu->cutree, i); for (j = 0; j < 3; j++) { cukid.cuorg[j] = cu->cuorg[j]; if ((1<<j) & i) cukid.cuorg[j] += cukid.cusize; } addobject(&cukid, obj); octkid(cu->cutree, i) = cukid.cutree; } return; } if (isempty(cu->cutree)) { OBJECT oset[2]; /* singular set */ oset[0] = 1; oset[1] = obj; cu->cutree = fullnode(oset); return; } /* add to full node */ add2full(cu, obj, inc); }
static OCTREE cvmeshoct( /* convert triangles in subtree */ OCTREE ot ) { int i; if (isempty(ot)) return(EMPTY); if (isfull(ot)) { OBJECT oset1[MAXSET+1]; OBJECT oset2[MAXSET+1]; objset(oset1, ot); oset2[0] = 0; for (i = oset1[0]; i > 0; i--) insertelem(oset2, cvmeshtri(oset1[i])); return(fullnode(oset2)); } for (i = 8; i--; ) octkid(ot, i) = cvmeshoct(octkid(ot, i)); return(ot); }
static void puttree( /* write octree to stdout in pre-order form */ register OCTREE ot ) { register int i; if (istree(ot)) { putc(OT_TREE, stdout); /* indicate tree */ for (i = 0; i < 8; i++) /* write tree */ puttree(octkid(ot, i)); } else if (isfull(ot)) { putc(OT_FULL, stdout); /* indicate fullnode */ putfullnode(ot); /* write fullnode */ } else putc(OT_EMPTY, stdout); /* indicate empty */ }
static void add2full( /* add object to full node */ register CUBE *cu, OBJECT obj ) { OCTREE ot; OBJECT oset[MAXSET+1]; CUBE cukid; register int i, j; objset(oset, cu->cutree); cukid.cusize = cu->cusize * 0.5; if (oset[0] < objlim || cukid.cusize < (oset[0] < MAXSET ? mincusize : mincusize/256.0)) { /* add to set */ if (oset[0] >= MAXSET) { sprintf(errmsg, "set overflow in addobject (%s)", objptr(obj)->oname); error(INTERNAL, errmsg); } insertelem(oset, obj); cu->cutree = fullnode(oset); return; } /* subdivide cube */ if ((ot = octalloc()) == EMPTY) error(SYSTEM, "out of octree space"); /* assign subcubes */ for (i = 0; i < 8; i++) { cukid.cutree = EMPTY; for (j = 0; j < 3; j++) { cukid.cuorg[j] = cu->cuorg[j]; if ((1<<j) & i) cukid.cuorg[j] += cukid.cusize; } for (j = 1; j <= oset[0]; j++) addface(&cukid, oset[j]); addface(&cukid, obj); /* returned node */ octkid(ot, i) = cukid.cutree; } cu->cutree = ot; }
static int nonsurfintree(OCTREE ot) /* check tree for modifiers */ { OBJECT set[MAXSET+1]; register int i; if (isempty(ot)) return(0); if (istree(ot)) { for (i = 0; i < 8; i++) if (nonsurfintree(octkid(ot, i))) return(1); return(0); } objset(set, ot); for (i = set[0]; i > 0; i-- ) if (ismodifier(objptr(set[i])->otype)) return(1); return(0); }
static void puttree( /* write octree to fp in pre-order form */ register OCTREE ot, FILE *fp ) { if (istree(ot)) { register int i; putc(OT_TREE, fp); /* indicate tree */ for (i = 0; i < 8; i++) /* write tree */ puttree(octkid(ot, i), fp); return; } if (isfull(ot)) { putc(OT_FULL, fp); /* indicate fullnode */ putfullnode(ot, fp); /* write fullnode */ return; } putc(OT_EMPTY, fp); /* indicate empty */ }
static void tallyoctree( /* tally octree size */ OCTREE ot, int *ecp, int *lcp, int *ocp ) { int i; if (isempty(ot)) { (*ecp)++; return; } if (isfull(ot)) { OBJECT oset[MAXSET+1]; (*lcp)++; objset(oset, ot); *ocp += oset[0]; return; } for (i = 0; i < 8; i++) tallyoctree(octkid(ot, i), ecp, lcp, ocp); }
static OCTREE gettree() /* get a pre-ordered octree */ { register OCTREE ot; register int i; switch (getc(infp)) { case OT_EMPTY: return(EMPTY); case OT_FULL: return(getfullnode()); case OT_TREE: if ((ot = octalloc()) == EMPTY) octerror(SYSTEM, "out of tree space in gettree"); for (i = 0; i < 8; i++) octkid(ot, i) = gettree(); return(ot); case EOF: octerror(USER, "truncated octree"); default: octerror(USER, "damaged octree"); } return EMPTY; /* pro forma return */ }
static void add2full( /* add object to full node */ register CUBE *cu, OBJECT obj, int inc ) { OCTREE ot; OBJECT oset[MAXSET+1]; CUBE cukid; unsigned char inflg[(MAXSET+7)/8], volflg[(MAXSET+7)/8]; register int i, j; objset(oset, cu->cutree); cukid.cusize = cu->cusize * 0.5; if (inc==O_IN || oset[0] < objlim || cukid.cusize < (oset[0] < MAXSET ? mincusize : mincusize/256.0)) { /* add to set */ if (oset[0] >= MAXSET) { sprintf(errmsg, "set overflow in addobject (%s)", objptr(obj)->oname); error(INTERNAL, errmsg); } insertelem(oset, obj); cu->cutree = fullnode(oset); return; } /* subdivide cube */ if ((ot = octalloc()) == EMPTY) error(SYSTEM, "out of octree space"); /* mark volumes */ j = (oset[0]+7)>>3; while (j--) volflg[j] = inflg[j] = 0; for (j = 1; j <= oset[0]; j++) if (isvolume(objptr(oset[j])->otype)) { setbit(volflg,j-1); if ((*ofun[objptr(oset[j])->otype].funp) (objptr(oset[j]), cu) == O_IN) setbit(inflg,j-1); } /* assign subcubes */ for (i = 0; i < 8; i++) { cukid.cutree = EMPTY; for (j = 0; j < 3; j++) { cukid.cuorg[j] = cu->cuorg[j]; if ((1<<j) & i) cukid.cuorg[j] += cukid.cusize; } /* surfaces first */ for (j = 1; j <= oset[0]; j++) if (!tstbit(volflg,j-1)) addobject(&cukid, oset[j]); /* then this object */ addobject(&cukid, obj); /* then partial volumes */ for (j = 1; j <= oset[0]; j++) if (tstbit(volflg,j-1) && !tstbit(inflg,j-1)) addobject(&cukid, oset[j]); /* full volumes last */ for (j = 1; j <= oset[0]; j++) if (tstbit(inflg,j-1)) addobject(&cukid, oset[j]); /* returned node */ octkid(ot, i) = cukid.cutree; } cu->cutree = ot; }
static int raymove( /* 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 */ RAY *r, CUBE *cu ) { int ax; double dt, t; if (istree(cu->cutree)) { /* recurse on subcubes */ CUBE cukid; int br, sgn; cukid.cusize = cu->cusize * 0.5; /* find subcube */ VCOPY(cukid.cuorg, cu->cuorg); br = 0; if (pos[0] >= cukid.cuorg[0]+cukid.cusize) { cukid.cuorg[0] += cukid.cusize; br |= 1; } if (pos[1] >= cukid.cuorg[1]+cukid.cusize) { cukid.cuorg[1] += cukid.cusize; br |= 2; } if (pos[2] >= cukid.cuorg[2]+cukid.cusize) { cukid.cuorg[2] += cukid.cusize; br |= 4; } for ( ; ; ) { cukid.cutree = octkid(cu->cutree, br); if ((ax = raymove(pos,cxs,dirf,r,&cukid)) == RAYHIT) return(RAYHIT); sgn = 1 << ax; if (sgn & dirf) /* positive axis? */ if (sgn & br) return(ax); /* overflow */ else { cukid.cuorg[ax] += cukid.cusize; br |= sgn; } else if (sgn & br) { cukid.cuorg[ax] -= cukid.cusize; br &= ~sgn; } else return(ax); /* underflow */ } /*NOTREACHED*/ } if (isfull(cu->cutree)) { if (checkhit(r, cu, cxs)) return(RAYHIT); } else if (r->ro == &Aftplane && incube(cu, r->rop)) return(RAYHIT); /* advance to next cube */ if (dirf&0x11) { dt = dirf&1 ? cu->cuorg[0] + cu->cusize : cu->cuorg[0]; t = (dt - pos[0])/r->rdir[0]; ax = 0; } else t = FHUGE; if (dirf&0x22) { dt = dirf&2 ? cu->cuorg[1] + cu->cusize : cu->cuorg[1]; dt = (dt - pos[1])/r->rdir[1]; if (dt < t) { t = dt; ax = 1; } } if (dirf&0x44) { dt = dirf&4 ? cu->cuorg[2] + cu->cusize : cu->cuorg[2]; dt = (dt - pos[2])/r->rdir[2]; if (dt < t) { t = dt; ax = 2; } } VSUM(pos, pos, r->rdir, t); return(ax); }