/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 1990-1998 NeoGeo BV. * All rights reserved. * * Contributors: 2004/2005 Blender Foundation, full recode * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/render/intern/raytrace/rayobject_octree.cpp * \ingroup render */ /* IMPORTANT NOTE: this code must be independent of any other render code to use it outside the renderer! */ #include #include #include #include #include #include "MEM_guardedalloc.h" #include "DNA_material_types.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "rayintersection.h" #include "rayobject.h" /* ********** structs *************** */ #define BRANCH_ARRAY 1024 #define NODE_ARRAY 4096 typedef struct Branch { struct Branch *b[8]; } Branch; typedef struct OcVal { short ocx, ocy, ocz; } OcVal; typedef struct Node { struct RayFace *v[8]; struct OcVal ov[8]; struct Node *next; } Node; typedef struct Octree { RayObject rayobj; struct Branch **adrbranch; struct Node **adrnode; float ocsize; /* ocsize: mult factor, max size octree */ float ocfacx,ocfacy,ocfacz; float min[3], max[3]; int ocres; int branchcount, nodecount; /* during building only */ char *ocface; RayFace **ro_nodes; int ro_nodes_size, ro_nodes_used; } Octree; static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec); static void RE_rayobject_octree_add(RayObject *o, RayObject *ob); static void RE_rayobject_octree_done(RayObject *o); static void RE_rayobject_octree_free(RayObject *o); static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max); /* * This function is not expected to be called by current code state. */ static float RE_rayobject_octree_cost(RayObject *o) { return 1.0; } static void RE_rayobject_octree_hint_bb(RayObject *o, RayHint *hint, float *min, float *max) { return; } static RayObjectAPI octree_api = { RE_rayobject_octree_intersect, RE_rayobject_octree_add, RE_rayobject_octree_done, RE_rayobject_octree_free, RE_rayobject_octree_bb, RE_rayobject_octree_cost, RE_rayobject_octree_hint_bb }; /* **************** ocval method ******************* */ /* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */ #define OCVALRES 15 #define BROW16(min, max) (((max)>=OCVALRES? 0xFFFF: (1<<(max+1))-1) - ((min>0)? ((1<<(min))-1):0) ) static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov) { float min[3], max[3]; int ocmin, ocmax; copy_v3_v3(min, v1); copy_v3_v3(max, v1); DO_MINMAX(v2, min, max); DO_MINMAX(v3, min, max); if(v4) { DO_MINMAX(v4, min, max); } ocmin= OCVALRES*(min[0]-x); ocmax= OCVALRES*(max[0]-x); ov->ocx= BROW16(ocmin, ocmax); ocmin= OCVALRES*(min[1]-y); ocmax= OCVALRES*(max[1]-y); ov->ocy= BROW16(ocmin, ocmax); ocmin= OCVALRES*(min[2]-z); ocmax= OCVALRES*(max[2]-z); ov->ocz= BROW16(ocmin, ocmax); } static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2) { int ocmin, ocmax; if(vec1[0]ocx= BROW16(ocmin, ocmax); if(vec1[1]ocy= BROW16(ocmin, ocmax); if(vec1[2]ocz= BROW16(ocmin, ocmax); } /* ************* octree ************** */ static Branch *addbranch(Octree *oc, Branch *br, short ocb) { int index; if(br->b[ocb]) return br->b[ocb]; oc->branchcount++; index= oc->branchcount>>12; if(oc->adrbranch[index]==NULL) oc->adrbranch[index]= (Branch*)MEM_callocN(4096*sizeof(Branch), "new oc branch"); if(oc->branchcount>= BRANCH_ARRAY*4096) { printf("error; octree branches full\n"); oc->branchcount=0; } return br->b[ocb]= oc->adrbranch[index]+(oc->branchcount & 4095); } static Node *addnode(Octree *oc) { int index; oc->nodecount++; index= oc->nodecount>>12; if(oc->adrnode[index]==NULL) oc->adrnode[index]= (Node*)MEM_callocN(4096*sizeof(Node),"addnode"); if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) { printf("error; octree nodes full\n"); oc->nodecount=0; } return oc->adrnode[index]+(oc->nodecount & 4095); } static int face_in_node(RayFace *face, short x, short y, short z, float rtf[][3]) { static float nor[3], d; float fx, fy, fz; // init static vars if(face) { normal_tri_v3( nor,rtf[0], rtf[1], rtf[2]); d= -nor[0]*rtf[0][0] - nor[1]*rtf[0][1] - nor[2]*rtf[0][2]; return 0; } fx= x; fy= y; fz= z; if((fx)*nor[0] + (fy)*nor[1] + (fz)*nor[2] + d > 0.0f) { if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d < 0.0f) return 1; if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1; if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1; if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1; if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1; if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1; if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1; } else { if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d > 0.0f) return 1; if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1; if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1; if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1; if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1; if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1; if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1; } return 0; } static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[4][3]) { Branch *br; Node *no; short a, oc0, oc1, oc2, oc3, oc4, oc5; x<<=2; y<<=1; br= oc->adrbranch[0]; if(oc->ocres==512) { oc0= ((x & 1024)+(y & 512)+(z & 256))>>8; br= addbranch(oc, br, oc0); } if(oc->ocres>=256) { oc0= ((x & 512)+(y & 256)+(z & 128))>>7; br= addbranch(oc, br, oc0); } if(oc->ocres>=128) { oc0= ((x & 256)+(y & 128)+(z & 64))>>6; br= addbranch(oc, br, oc0); } oc0= ((x & 128)+(y & 64)+(z & 32))>>5; oc1= ((x & 64)+(y & 32)+(z & 16))>>4; oc2= ((x & 32)+(y & 16)+(z & 8))>>3; oc3= ((x & 16)+(y & 8)+(z & 4))>>2; oc4= ((x & 8)+(y & 4)+(z & 2))>>1; oc5= ((x & 4)+(y & 2)+(z & 1)); br= addbranch(oc, br,oc0); br= addbranch(oc, br,oc1); br= addbranch(oc, br,oc2); br= addbranch(oc, br,oc3); br= addbranch(oc, br,oc4); no= (Node *)br->b[oc5]; if(no==NULL) br->b[oc5]= (Branch *)(no= addnode(oc)); while(no->next) no= no->next; a= 0; if(no->v[7]) { /* node full */ no->next= addnode(oc); no= no->next; } else { while(no->v[a]!=NULL) a++; } no->v[a]= (RayFace*) RE_rayobject_align(face); if(quad) calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x>>2, y>>1, z, &no->ov[a]); else calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x>>2, y>>1, z, &no->ov[a]); } static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[][3], float rtf[][3]) { int ocx1,ocx2,ocy1,ocy2; int x,y,dx=0,dy=0; float ox1,ox2,oy1,oy2; float labda,labdao,labdax,labday,ldx,ldy; ocx1= rts[b1][c1]; ocy1= rts[b1][c2]; ocx2= rts[b2][c1]; ocy2= rts[b2][c2]; if(ocx1==ocx2 && ocy1==ocy2) { ocface[oc->ocres*ocx1+ocy1]= 1; return; } ox1= rtf[b1][c1]; oy1= rtf[b1][c2]; ox2= rtf[b2][c1]; oy2= rtf[b2][c2]; if(ox1!=ox2) { if(ox2-ox1>0.0f) { labdax= (ox1-ocx1-1.0f)/(ox1-ox2); ldx= -1.0f/(ox1-ox2); dx= 1; } else { labdax= (ox1-ocx1)/(ox1-ox2); ldx= 1.0f/(ox1-ox2); dx= -1; } } else { labdax=1.0f; ldx=0; } if(oy1!=oy2) { if(oy2-oy1>0.0f) { labday= (oy1-ocy1-1.0f)/(oy1-oy2); ldy= -1.0f/(oy1-oy2); dy= 1; } else { labday= (oy1-ocy1)/(oy1-oy2); ldy= 1.0f/(oy1-oy2); dy= -1; } } else { labday=1.0f; ldy=0; } x=ocx1; y=ocy1; labda= MIN2(labdax, labday); while(TRUE) { if(x<0 || y<0 || x>=oc->ocres || y>=oc->ocres); else ocface[oc->ocres*x+y]= 1; labdao=labda; if(labdax==labday) { labdax+=ldx; x+=dx; labday+=ldy; y+=dy; } else { if(labdax=1.0f) break; } ocface[oc->ocres*ocx2+ocy2]=1; } static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax) { int a, x, y, y1, y2; for(x=ocmin[c1];x<=ocmax[c1];x++) { a= oc->ocres*x; for(y=ocmin[c2];y<=ocmax[c2];y++) { if(ocface[a+y]) { y++; while(ocface[a+y] && y!=ocmax[c2]) y++; for(y1=ocmax[c2];y1>y;y1--) { if(ocface[a+y1]) { for(y2=y;y2<=y1;y2++) ocface[a+y2]=1; y1=0; } } y=ocmax[c2]; } } } } static void RE_rayobject_octree_free(RayObject *tree) { Octree *oc= (Octree*)tree; #if 0 printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount); printf("raycount %d \n", raycount); printf("ray coherent %d \n", coherent_ray); printf("accepted %d rejected %d\n", accepted, rejected); #endif if(oc->ocface) MEM_freeN(oc->ocface); if(oc->adrbranch) { int a= 0; while(oc->adrbranch[a]) { MEM_freeN(oc->adrbranch[a]); oc->adrbranch[a]= NULL; a++; } MEM_freeN(oc->adrbranch); oc->adrbranch= NULL; } oc->branchcount= 0; if(oc->adrnode) { int a= 0; while(oc->adrnode[a]) { MEM_freeN(oc->adrnode[a]); oc->adrnode[a]= NULL; a++; } MEM_freeN(oc->adrnode); oc->adrnode= NULL; } oc->nodecount= 0; MEM_freeN(oc); } RayObject *RE_rayobject_octree_create(int ocres, int size) { Octree *oc= (Octree*)MEM_callocN(sizeof(Octree), "Octree"); assert( RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */ oc->rayobj.api = &octree_api; oc->ocres = ocres; oc->ro_nodes = (RayFace**)MEM_callocN(sizeof(RayFace*)*size, "octree rayobject nodes"); oc->ro_nodes_size = size; oc->ro_nodes_used = 0; return RE_rayobject_unalignRayAPI((RayObject*) oc); } static void RE_rayobject_octree_add(RayObject *tree, RayObject *node) { Octree *oc = (Octree*)tree; assert( RE_rayobject_isRayFace(node) ); assert( oc->ro_nodes_used < oc->ro_nodes_size ); oc->ro_nodes[ oc->ro_nodes_used++ ] = (RayFace*)RE_rayobject_align(node); } static void octree_fill_rayface(Octree *oc, RayFace *face) { float ocfac[3], rtf[4][3]; float co1[3], co2[3], co3[3], co4[3]; short rts[4][3]; short ocmin[3], ocmax[3]; char *ocface= oc->ocface; // front, top, size view of face, to fill in int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2; ocfac[0]= oc->ocfacx; ocfac[1]= oc->ocfacy; ocfac[2]= oc->ocfacz; ocres2= oc->ocres*oc->ocres; copy_v3_v3(co1, face->v1); copy_v3_v3(co2, face->v2); copy_v3_v3(co3, face->v3); if(face->v4) copy_v3_v3(co4, face->v4); for(c=0;c<3;c++) { rtf[0][c]= (co1[c]-oc->min[c])*ocfac[c] ; rts[0][c]= (short)rtf[0][c]; rtf[1][c]= (co2[c]-oc->min[c])*ocfac[c] ; rts[1][c]= (short)rtf[1][c]; rtf[2][c]= (co3[c]-oc->min[c])*ocfac[c] ; rts[2][c]= (short)rtf[2][c]; if(RE_rayface_isQuad(face)) { rtf[3][c]= (co4[c]-oc->min[c])*ocfac[c] ; rts[3][c]= (short)rtf[3][c]; } } for(c=0;c<3;c++) { oc1= rts[0][c]; oc2= rts[1][c]; oc3= rts[2][c]; if(!RE_rayface_isQuad(face)) { ocmin[c]= MIN3(oc1,oc2,oc3); ocmax[c]= MAX3(oc1,oc2,oc3); } else { oc4= rts[3][c]; ocmin[c]= MIN4(oc1,oc2,oc3,oc4); ocmax[c]= MAX4(oc1,oc2,oc3,oc4); } if(ocmax[c]>oc->ocres-1) ocmax[c]=oc->ocres-1; if(ocmin[c]<0) ocmin[c]=0; } if(ocmin[0]==ocmax[0] && ocmin[1]==ocmax[1] && ocmin[2]==ocmax[2]) { ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf); } else { d2dda(oc, 0,1,0,1,ocface+ocres2,rts,rtf); d2dda(oc, 0,1,0,2,ocface,rts,rtf); d2dda(oc, 0,1,1,2,ocface+2*ocres2,rts,rtf); d2dda(oc, 1,2,0,1,ocface+ocres2,rts,rtf); d2dda(oc, 1,2,0,2,ocface,rts,rtf); d2dda(oc, 1,2,1,2,ocface+2*ocres2,rts,rtf); if(!RE_rayface_isQuad(face)) { d2dda(oc, 2,0,0,1,ocface+ocres2,rts,rtf); d2dda(oc, 2,0,0,2,ocface,rts,rtf); d2dda(oc, 2,0,1,2,ocface+2*ocres2,rts,rtf); } else { d2dda(oc, 2,3,0,1,ocface+ocres2,rts,rtf); d2dda(oc, 2,3,0,2,ocface,rts,rtf); d2dda(oc, 2,3,1,2,ocface+2*ocres2,rts,rtf); d2dda(oc, 3,0,0,1,ocface+ocres2,rts,rtf); d2dda(oc, 3,0,0,2,ocface,rts,rtf); d2dda(oc, 3,0,1,2,ocface+2*ocres2,rts,rtf); } /* nothing todo with triangle..., just fills :) */ filltriangle(oc, 0,1,ocface+ocres2,ocmin,ocmax); filltriangle(oc, 0,2,ocface,ocmin,ocmax); filltriangle(oc, 1,2,ocface+2*ocres2,ocmin,ocmax); /* init static vars here */ face_in_node(face, 0,0,0, rtf); for(x=ocmin[0];x<=ocmax[0];x++) { a= oc->ocres*x; for(y=ocmin[1];y<=ocmax[1];y++) { if(ocface[a+y+ocres2]) { b= oc->ocres*y+2*ocres2; for(z=ocmin[2];z<=ocmax[2];z++) { if(ocface[b+z] && ocface[a+z]) { if(face_in_node(NULL, x, y, z, rtf)) ocwrite(oc, face, RE_rayface_isQuad(face), x,y,z, rtf); } } } } } /* same loops to clear octree, doubt it can be done smarter */ for(x=ocmin[0];x<=ocmax[0];x++) { a= oc->ocres*x; for(y=ocmin[1];y<=ocmax[1];y++) { /* x-y */ ocface[a+y+ocres2]= 0; b= oc->ocres*y + 2*ocres2; for(z=ocmin[2];z<=ocmax[2];z++) { /* y-z */ ocface[b+z]= 0; /* x-z */ ocface[a+z]= 0; } } } } } static void RE_rayobject_octree_done(RayObject *tree) { Octree *oc = (Octree*)tree; int c; float t00, t01, t02; int ocres2 = oc->ocres*oc->ocres; INIT_MINMAX(oc->min, oc->max); /* Calculate Bounding Box */ for(c=0; cro_nodes_used; c++) RE_rayobject_merge_bb( RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max); /* Alloc memory */ oc->adrbranch= (Branch**)MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches"); oc->adrnode= (Node**)MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes"); oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree"); /* the lookup table, per face, for which nodes to fill in */ oc->ocface= (char*)MEM_callocN( 3*ocres2 + 8, "ocface"); memset(oc->ocface, 0, 3*ocres2); for(c=0;c<3;c++) { /* octree enlarge, still needed? */ oc->min[c]-= 0.01f; oc->max[c]+= 0.01f; } t00= oc->max[0]-oc->min[0]; t01= oc->max[1]-oc->min[1]; t02= oc->max[2]-oc->min[2]; /* this minus 0.1 is old safety... seems to be needed? */ oc->ocfacx= (oc->ocres-0.1)/t00; oc->ocfacy= (oc->ocres-0.1)/t01; oc->ocfacz= (oc->ocres-0.1)/t02; oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */ for(c=0; cro_nodes_used; c++) { octree_fill_rayface(oc, oc->ro_nodes[c]); } MEM_freeN(oc->ocface); oc->ocface = NULL; MEM_freeN(oc->ro_nodes); oc->ro_nodes = NULL; printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx ); printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy ); printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz ); } static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max) { Octree *oc = (Octree*)tree; DO_MINMAX(oc->min, min, max); DO_MINMAX(oc->max, min, max); } /* check all faces in this node */ static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval) { short nr=0; /* return on any first hit */ if(is->mode==RE_RAY_SHADOW) { for(; no; no = no->next) for(nr=0; nr<8; nr++) { RayFace *face = no->v[nr]; OcVal *ov = no->ov+nr; if(!face) break; if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) { if( RE_rayobject_intersect( RE_rayobject_unalignRayFace(face),is) ) return 1; } } } else { /* else mirror or glass or shadowtra, return closest face */ int found= 0; for(; no; no = no->next) for(nr=0; nr<8; nr++) { RayFace *face = no->v[nr]; OcVal *ov = no->ov+nr; if(!face) break; if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) { if( RE_rayobject_intersect( RE_rayobject_unalignRayFace(face),is) ) found= 1; } } return found; } return 0; } /* find the Node for the octree coord x y z */ static Node *ocread(Octree *oc, int x, int y, int z) { Branch *br; int oc1; x<<=2; y<<=1; br= oc->adrbranch[0]; if(oc->ocres==512) { oc1= ((x & 1024)+(y & 512)+(z & 256))>>8; br= br->b[oc1]; if(br==NULL) { return NULL; } } if(oc->ocres>=256) { oc1= ((x & 512)+(y & 256)+(z & 128))>>7; br= br->b[oc1]; if(br==NULL) { return NULL; } } if(oc->ocres>=128) { oc1= ((x & 256)+(y & 128)+(z & 64))>>6; br= br->b[oc1]; if(br==NULL) { return NULL; } } oc1= ((x & 128)+(y & 64)+(z & 32))>>5; br= br->b[oc1]; if(br) { oc1= ((x & 64)+(y & 32)+(z & 16))>>4; br= br->b[oc1]; if(br) { oc1= ((x & 32)+(y & 16)+(z & 8))>>3; br= br->b[oc1]; if(br) { oc1= ((x & 16)+(y & 8)+(z & 4))>>2; br= br->b[oc1]; if(br) { oc1= ((x & 8)+(y & 4)+(z & 2))>>1; br= br->b[oc1]; if(br) { oc1= ((x & 4)+(y & 2)+(z & 1)); return (Node *)br->b[oc1]; } } } } } return NULL; } static int cliptest(float p, float q, float *u1, float *u2) { float r; if(p<0.0f) { if(q*u2) return 0; else if(r>*u1) *u1=r; } } else { if(p>0.0f) { if(q<0.0f) return 0; else if(qorig.face */ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is) { Octree *oc= (Octree*)tree; Node *no; OcVal ocval; float vec1[3], vec2[3], start[3], end[3]; float u1,u2,ox1,ox2,oy1,oy2,oz1,oz2; float labdao,labdax,ldx,labday,ldy,labdaz,ldz, ddalabda; float olabda = 0; int dx,dy,dz; int xo,yo,zo,c1=0; int ocx1,ocx2,ocy1, ocy2,ocz1,ocz2; /* clip with octree */ if(oc->branchcount==0) return 0; /* do this before intersect calls */ #if 0 is->facecontr= NULL; /* to check shared edge */ is->obcontr= 0; is->faceisect= is->isect= 0; /* shared edge, quad half flag */ is->userdata= oc->userdata; #endif copy_v3_v3( start, is->start ); madd_v3_v3v3fl( end, is->start, is->dir, is->dist ); ldx= is->dir[0]*is->dist; olabda = is->dist; u1= 0.0f; u2= 1.0f; /* clip with octree cube */ if(cliptest(-ldx, start[0]-oc->min[0], &u1,&u2)) { if(cliptest(ldx, oc->max[0]-start[0], &u1,&u2)) { ldy= is->dir[1]*is->dist; if(cliptest(-ldy, start[1]-oc->min[1], &u1,&u2)) { if(cliptest(ldy, oc->max[1]-start[1], &u1,&u2)) { ldz = is->dir[2]*is->dist; if(cliptest(-ldz, start[2]-oc->min[2], &u1,&u2)) { if(cliptest(ldz, oc->max[2]-start[2], &u1,&u2)) { c1=1; if(u2<1.0f) { end[0] = start[0]+u2*ldx; end[1] = start[1]+u2*ldy; end[2] = start[2]+u2*ldz; } if(u1>0.0f) { start[0] += u1*ldx; start[1] += u1*ldy; start[2] += u1*ldz; } } } } } } } if(c1==0) return 0; /* reset static variables in ocread */ //ocread(oc, oc->ocres, 0, 0); /* setup 3dda to traverse octree */ ox1= (start[0]-oc->min[0])*oc->ocfacx; oy1= (start[1]-oc->min[1])*oc->ocfacy; oz1= (start[2]-oc->min[2])*oc->ocfacz; ox2= (end[0]-oc->min[0])*oc->ocfacx; oy2= (end[1]-oc->min[1])*oc->ocfacy; oz2= (end[2]-oc->min[2])*oc->ocfacz; ocx1= (int)ox1; ocy1= (int)oy1; ocz1= (int)oz1; ocx2= (int)ox2; ocy2= (int)oy2; ocz2= (int)oz2; if(ocx1==ocx2 && ocy1==ocy2 && ocz1==ocz2) { no= ocread(oc, ocx1, ocy1, ocz1); if(no) { /* exact intersection with node */ vec1[0]= ox1; vec1[1]= oy1; vec1[2]= oz1; vec2[0]= ox2; vec2[1]= oy2; vec2[2]= oz2; calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2); if( testnode(oc, is, no, ocval) ) return 1; } } else { int found = 0; //static int coh_ocx1,coh_ocx2,coh_ocy1, coh_ocy2,coh_ocz1,coh_ocz2; float dox, doy, doz; int eqval; /* calc labda en ld */ dox= ox1-ox2; doy= oy1-oy2; doz= oz1-oz2; if(dox<-FLT_EPSILON) { ldx= -1.0f/dox; labdax= (ocx1-ox1+1.0f)*ldx; dx= 1; } else if(dox>FLT_EPSILON) { ldx= 1.0f/dox; labdax= (ox1-ocx1)*ldx; dx= -1; } else { labdax=1.0f; ldx=0; dx= 0; } if(doy<-FLT_EPSILON) { ldy= -1.0f/doy; labday= (ocy1-oy1+1.0f)*ldy; dy= 1; } else if(doy>FLT_EPSILON) { ldy= 1.0f/doy; labday= (oy1-ocy1)*ldy; dy= -1; } else { labday=1.0f; ldy=0; dy= 0; } if(doz<-FLT_EPSILON) { ldz= -1.0f/doz; labdaz= (ocz1-oz1+1.0f)*ldz; dz= 1; } else if(doz>FLT_EPSILON) { ldz= 1.0f/doz; labdaz= (oz1-ocz1)*ldz; dz= -1; } else { labdaz=1.0f; ldz=0; dz= 0; } xo=ocx1; yo=ocy1; zo=ocz1; labdao= ddalabda= MIN3(labdax,labday,labdaz); vec2[0]= ox1; vec2[1]= oy1; vec2[2]= oz1; /* this loop has been constructed to make sure the first and last node of ray are always included, even when ddalabda==1.0f or larger */ while(TRUE) { no= ocread(oc, xo, yo, zo); if(no) { /* calculate ray intersection with octree node */ copy_v3_v3(vec1, vec2); // dox,y,z is negative vec2[0]= ox1-ddalabda*dox; vec2[1]= oy1-ddalabda*doy; vec2[2]= oz1-ddalabda*doz; calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2); //is->dist = (u1+ddalabda*(u2-u1))*olabda; if( testnode(oc, is, no, ocval) ) found = 1; if(is->dist < (u1+ddalabda*(u2-u1))*olabda) return found; } labdao= ddalabda; /* traversing ocree nodes need careful detection of smallest values, with proper exceptions for equal labdas */ eqval= (labdax==labday); if(labday==labdaz) eqval += 2; if(labdax==labdaz) eqval += 4; if(eqval) { // only 4 cases exist! if(eqval==7) { // x=y=z xo+=dx; labdax+=ldx; yo+=dy; labday+=ldy; zo+=dz; labdaz+=ldz; } else if(eqval==1) { // x=y if(labday < labdaz) { xo+=dx; labdax+=ldx; yo+=dy; labday+=ldy; } else { zo+=dz; labdaz+=ldz; } } else if(eqval==2) { // y=z if(labdax < labday) { xo+=dx; labdax+=ldx; } else { yo+=dy; labday+=ldy; zo+=dz; labdaz+=ldz; } } else { // x=z if(labday < labdax) { yo+=dy; labday+=ldy; } else { xo+=dx; labdax+=ldx; zo+=dz; labdaz+=ldz; } } } else { // all three different, just three cases exist eqval= (labdax=1.0f) break; } } /* reached end, no intersections found */ return 0; }