RAYTRACE.C

Go to the documentation of this file.
00001 #define MODULE_TRACE
00002 
00003 // This is the raytracing module - it uses an octree spatial
00004 // decomposition to speed things up - see the book!
00005 
00006 #include <setjmp.h>
00007 #include "render.h"
00008 
00009 #define UC unsigned short
00010 #define US unsigned long
00011 
00018 typedef struct traceNODE {
00019   long n,            
00020        mi[3],ma[3];  
00021   UC *vxi;           
00022   UC *oid;           
00023   US *fid;           
00024   struct traceNODE *octree[8]; 
00025   long id; struct traceNODE *last; long level; 
00026 } node;
00027 
00028 //#define THRESHOLDF 45     // nominal max number of faces per voxel
00029 //#define THRESHOLDR 6      // maximum number of recursive levels   
00030 #define THRESHOLDF 25     // nominal max number of faces per voxel - use when not subdividing 
00031 #define THRESHOLDR 8      // maximum number of recursive levels  
00032 
00033 extern short R_terminator(void);
00034 
00035 static jmp_buf x_buf;
00036 static long threshold_f,threshold_z,threshold_r,
00037             nfaces,kcount,maxfaces,minfaces,
00038             trace_depth_max=7, // number of reflections etc
00039             level_depth_max;
00040 static node *ROOT;
00041 static long *ObjectXlist=NULL;    // extra number of vertices required for this object due to voxel splitting
00042 static long voxel_xmin,voxel_ymin,voxel_zmin,
00043             voxel_xmax,voxel_ymax,voxel_zmax;
00044 
00045 static node *which_voxel(vector p, node *nc);
00046 static node *track_ray(node *nc, vector p, vector d);
00047 static void destroyBST(node *np);
00048 static void countBST(node *np);
00049 static void printBST(node *np);
00050 static int MakeVoxels(node *np, int level);
00051 static void eliminateDuplicatesInBST(node *n);
00052 static BOOL PartitionVoxel(node *, node *, node *, long, long index);
00053 static BOOL SplitVoxel(node *, node *, node *, long, long index);
00054 
00055 static double longest_ray;
00056 
00057 static void IntersectPlane(long p, long index, ivector vi1, ivector vi2, ivector vo){
00058  long id1[3]={1,2,0},id2[3]={2,0,1};
00059  double mu;
00060  mu=(double)(vi2[index]-vi1[index]);
00061  if(fabs(mu) < 1.0)mu=0.0;
00062  else mu=((double)p-vi1[index])/mu;
00063  vo[index]=p;
00064  vo[id1[index]]=vi1[id1[index]]+(long)(mu*((double)(vi2[id1[index]]-vi1[id1[index]])));
00065  vo[id2[index]]=vi1[id2[index]]+(long)(mu*((double)(vi2[id2[index]]-vi1[id2[index]])));
00066 }
00067 
00068 static double c_angle(ivector p1, ivector p2, ivector p3){ // angle at p2
00069  vector d1,d2;
00070  VECSUB(p1,p2,d1)
00071  VECSUB(p3,p2,d2)
00072  normalize(d1); normalize(d2);
00073  return DOT(d1,d2);
00074 }
00075 
00076 static void SplitFaceAtVoxelPlane(long o, long i, long c, // object face and type of intersection
00077                                   tvertex *v, tface *f,     // Base pointers 
00078                                   tvertex *v0, tvertex *v1, tvertex *v2, tface *fi,
00079                                   long p, long index,
00080                                   UC *oid1, US *fid1, UC *oid2, US *fid2,
00081                                   long *n1, long *n2){
00082  long vp,fp,fa,fb,i1,i2,i3,va,vb,i1i,i2i,i3i;
00083  tvertex *vl,*vr,*vrr;
00084  double uu,vv,ww,uu1,vv1,ww1,uui1,vvi1,wwi1,uui2,vvi2,wwi2,uui3,vvi3,wwi3;
00085  vector norm,normm,norm1,norm2,norm3;
00086  vp=Object[o].NoTraceVertices;
00087  fp=Object[o].NoTraceFaces;
00088  va=vp; vb=vp+1;
00089  fa=fp; fb=fp+1;
00090  //if(debug != NULL)fprintf(debug,"Splitting object %ld (v=%ld f=%ld) face %ld new vertices %ld %ld new faces %ld %ld\n",o,vp,fp,i,va,vb,fa,fb); 
00091  if(c == 3 || c == 4 || c == 5 || c == 13 || c == 14 || c == 15){  // add one vertex and one face
00092    if      (c ==  3 || c == 13){vl = v2; vr=v1; i1=0; i2=1; i3=2;}
00093    else if (c ==  4 || c == 14){vl = v0; vr=v2; i1=1; i2=2; i3=0;}
00094    else if (c ==  5 || c == 15){vl = v1; vr=v0; i1=2; i2=0; i3=1;}
00095    //if(debug != NULL)fprintf(debug,"Vertex in split plane !!\n");
00096    i1i=f[i].V[i1];  i2i=f[i].V[i2]; i3i=f[i].V[i3]; // actual vertex IDs
00097    IntersectPlane(p,index,vl->ip,vr->ip, v[va].ip);
00098    f[i].V[0]=i1i; f[i].V[1]=i2i; f[i].V[2]=va;
00099    f[fa].V[0]=i1i; f[fa].V[1]=va; f[fa].V[2]=i3i;
00100    f[fa].o=f[i].o; // new face points at same original face
00101    f[fa].f=f[i].f; // as the face that is being subdivided
00102    if(c == 3 || c == 4 || c == 5){
00103      oid1[*n1] = o; fid1[*n1] = fa; *n1 = (*n1) + 1;
00104      oid2[*n2] = o; fid2[*n2] =  i; *n2 = (*n2) + 1;
00105    }
00106    else{
00107      oid1[*n1] = o; fid1[*n1] =  i; *n1 = (*n1) + 1;
00108      oid2[*n2] = o; fid2[*n2] = fa; *n2 = (*n2) + 1;
00109    }
00110    vp += 1; fp += 1;
00111  }
00112  else {  // add two vertices and two faces 
00113    if     (c == 6 || c == 10){vl=v0; vr=v1; vrr=v2; i1=0; i2=1; i3=2;}
00114    else if(c == 7 || c == 11){vl=v1; vr=v2; vrr=v0; i1=1; i2=2; i3=0;}
00115    else if(c == 8 || c == 12){vl=v2; vr=v0; vrr=v1; i1=2; i2=0; i3=1;}
00116    i1i=f[i].V[i1];  i2i=f[i].V[i2]; i3i=f[i].V[i3]; // actual vertex IDs
00117    IntersectPlane(p,index,vl->ip,vr->ip, v[va].ip);
00118    IntersectPlane(p,index,vl->ip,vrr->ip, v[vb].ip);
00119    f[i].V[0]=i1i; f[i].V[1]=va; f[i].V[2]=vb;
00120    if(c_angle(v[i3i].ip,v[vb].ip,v[va].ip) >= c_angle(v[vb].ip,v[va].ip,v[i2i].ip)){
00121      f[fa].V[0]=i3i; f[fa].V[1]=vb; f[fa].V[2]=va;
00122      f[fb].V[0]=i2i; f[fb].V[1]=i3i; f[fb].V[2]=va;
00123    }
00124    else{
00125      f[fa].V[0]=i3i; f[fa].V[1]=vb; f[fa].V[2]=i2i;
00126      f[fb].V[0]=i2i; f[fb].V[1]=vb; f[fb].V[2]=va;
00127    }
00128    f[fa].o=f[i].o; // new face points at same original face
00129    f[fa].f=f[i].f; // as the face that is being subdivided
00130    f[fb].o=f[i].o; // new face points at same original face
00131    f[fb].f=f[i].f; // as the face that is being subdivided
00132    if(c == 6 || c == 7 || c == 8){
00133      oid1[*n1] = o; fid1[*n1] =  i; *n1 = (*n1) + 1;
00134      oid2[*n2] = o; fid2[*n2] = fa; *n2 = (*n2) + 1;
00135      oid2[*n2] = o; fid2[*n2] = fb; *n2 = (*n2) + 1;
00136    }
00137    else{
00138      oid1[*n1] = o; fid1[*n1] = fb; *n1 = (*n1) + 1;
00139      oid1[*n1] = o; fid1[*n1] = fa; *n1 = (*n1) + 1;
00140      oid2[*n2] = o; fid2[*n2] =  i; *n2 = (*n2) + 1;
00141    }
00142    //fprintf(debug,"X o=%ld i=%ld fa=%ld fb=%ld  n1=%ld n2=%ld\n",o,i,fa,fb,*n1,*n2);
00143    vp += 2; fp+=2;
00144  }
00145  Object[o].NoTraceVertices = vp;
00146  Object[o].NoTraceFaces = fp;
00147 }
00148 
00149 #define IN_PLANE(point,plane) (point == plane)
00150 #define IN_LESS_VOXEL(point,plane) (point < plane)
00151 #define IN_GREATER_VOXEL(point,plane) (point > plane)
00152 #define IN_LESS_EQUAL_VOXEL(point,plane) (point <= plane)
00153 #define IN_GREATER_EQUAL_VOXEL(point,plane) (point >= plane)
00154 
00155 static long FaceIntersectVoxelPlane(tvertex *v0, tvertex *v1, tvertex *v2, long p, long index, UC *vxi){
00156  long p0,p1,p2;
00157  // determine the type of split needed for this face and return number of extra vertices
00158  // and a code indicating how the split should be made.
00159  p0=(long)(v0->ip[index]);
00160  p1=(long)(v1->ip[index]);
00161  p2=(long)(v2->ip[index]);
00162  if(IN_LESS_EQUAL_VOXEL(p0,p) && IN_LESS_EQUAL_VOXEL(p1,p) && IN_LESS_EQUAL_VOXEL(p2,p)){
00163    *vxi = 1; // code for less voxel
00164    return 0; // no extra vertices required
00165  }
00166  else if(IN_GREATER_EQUAL_VOXEL(p0,p) && IN_GREATER_EQUAL_VOXEL(p1,p) && IN_GREATER_EQUAL_VOXEL(p2,p)){
00167    *vxi = 2; // code for greater voxel
00168    return 0; // no extra vertices required
00169  }
00170  else{ // face must cross the voxel boundary
00171    // these require 1 additional vertex and face
00172    if     (IN_PLANE(p0,p)){if(IN_LESS_VOXEL(p2,p))*vxi = 3; else *vxi = 13;  return 1;}
00173    else if(IN_PLANE(p1,p)){if(IN_LESS_VOXEL(p0,p))*vxi = 4; else *vxi = 14;  return 1;}
00174    else if(IN_PLANE(p2,p)){if(IN_LESS_VOXEL(p1,p))*vxi = 5; else *vxi = 15;  return 1;}
00175    // these require 2 additional vertices and faces
00176    else if(IN_LESS_VOXEL(p0,p)){
00177      if     (IN_LESS_VOXEL(p1,p)){*vxi = 12; return 2;} 
00178      else if(IN_LESS_VOXEL(p2,p)){*vxi = 11; return 2;} 
00179      else                        {*vxi = 6;  return 2;}  
00180    }
00181    else if(IN_LESS_VOXEL(p1,p)){
00182      if     (IN_LESS_VOXEL(p2,p)){*vxi = 10; return 2;} 
00183      else if(IN_LESS_VOXEL(p0,p)){*vxi = 12; return 2;} 
00184      else                        {*vxi = 7;  return 2;}  
00185    }
00186    else if(IN_LESS_VOXEL(p2,p)){
00187      if     (IN_LESS_VOXEL(p0,p)){*vxi = 11; return 2;} 
00188      else if(IN_LESS_VOXEL(p1,p)){*vxi = 10; return 2;} 
00189      else                        {*vxi = 8;  return 2;}  
00190    }
00191  }
00192  //if(debug != NULL)fprintf(debug,"Voxel Split - this point should not be reached\n");
00193  * vxi = 0; 
00194  return 0;
00195 }
00196 
00197 static BOOL SplitVoxel(node *np, node *na, node *nb, long p, long index){ // index = 2 for z coord 0 for x coord
00198   // split polygons in node "np" into the two sub nodes "na" and "nb" at plane "p" 
00199  long i,nnp,nx,n1,n2,o,f,c,sz,xvf,nl,nr,ns,ng;
00200  tface *F;
00201  tvertex *V,*v0,*v1,*v2;
00202  nnp=np->n;
00203  // assign max and min for the new voxels
00204  //if(debug != NULL)fprintf(debug,"Split voxel with %ld faces in plane %ld at %ld\n",nnp,index,p); 
00205  for(i=0;i<3;i++){
00206    na->mi[i]=nb->mi[i]=np->mi[i];
00207    na->ma[i]=nb->ma[i]=np->ma[i];
00208  }
00209  na->ma[index]=p;     //  "na" points at voxel with the lesser coord value  
00210  nb->mi[index]=p;     //  "nb" to one with greater coord value
00211  // calculate number of extra vertices and faces required  
00212  for(i=0;i<ObjectCount;i++)ObjectXlist[i]=0;
00213  for(i=0;i<nnp;i++){  
00214    o = (long)(*(np->oid+i));
00215    f = (long)(*(np->fid+i));
00216    F=(Object[o].Ftracebase+f);
00217    V=Object[o].Vtracebase;
00218    v0=(V + F->V[0]);
00219    v1=(V + F->V[1]);
00220    v2=(V + F->V[2]);
00221    // calculate the number of extra vertices created due to possible face split and where they should go
00222    ObjectXlist[o] += FaceIntersectVoxelPlane(v0,v1,v2,p,index,(np->vxi+i)); // increment extra face/vertex count for object "o"
00223    //if(debug != NULL)fprintf(debug,"Object %ld Face %ld  Icode=%ld - vertices %ld %ld %ld \n",o,i,(long)(*(np->vxi+i)),F->V[0],F->V[1],F->V[2]);
00224  }
00225  //if(debug != NULL)for(i=0;i<ObjectCount;i++)fprintf(debug,"Object %ld has %ld extra faces in voxel\n",i,ObjectXlist[i]); 
00226  // allocate space for extra faces and vertices - this is absolute
00227  for(i=0,nx=0;i<ObjectCount;i++)if((xvf=ObjectXlist[i]) > 0){
00228    sz=(Object[i].NoTraceVertices+xvf)*(long)sizeof(tvertex);
00229    if((V=(tvertex  *)X__Realloc(Object[i].Vtracebase,sz)) == NULL)goto FAILED;
00230    Object[i].Vtracebase=V;
00231    sz=(Object[i].NoTraceFaces+xvf)*(long)sizeof(tface);
00232    if((F=(tface  *)X__Realloc(Object[i].Ftracebase,sz)) == NULL)goto FAILED;
00233    Object[i].Ftracebase=F;
00234    nx += xvf;
00235  }
00236  // allocate space for list of vertices and in child nodes. This is relative to voxel.
00237  // this will be over estimate since some of the added faces will go in one voxel and
00238  // some in the other
00239  ng=nnp+nx;
00240  //fprintf(debug,"Guessed voxel count %ld\n",ng);
00241  if(ng > 0){
00242    if((na->oid=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
00243    if((na->fid=(US *)X__Malloc(sizeof(US)*ng)) == NULL)goto FAILED;
00244    if((na->vxi=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
00245    if((nb->oid=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
00246    if((nb->fid=(US *)X__Malloc(sizeof(US)*ng)) == NULL)goto FAILED;
00247    if((nb->vxi=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
00248 for(i=0;i<ng;i++){na->oid[i]=999,na->fid[i]=999,na->vxi[i]=999;nb->oid[i]=666,nb->fid[i]=666,nb->vxi[i]=666;} //remove when not debugging
00249  }
00250  // split vertices and faces - allocate them to the appropriate sub voxel - use VXI code
00251  nl=nr=ns=0;
00252  for(i=0,n1=0,n2=0;i<nnp;i++){  
00253    c = (long)(*(np->vxi+i));   
00254    o = (long)(*(np->oid+i));
00255    f = (long)(*(np->fid+i));
00256    if(c == 1){  // assigned to lower voxel
00257      *(na->fid+n1)=f; 
00258      *(na->oid+n1)=o; n1++;
00259      nl++;
00260    }
00261    else if(c == 2){
00262      *(nb->fid+n2)=f; 
00263      *(nb->oid+n2)=o; n2++;
00264      nr++;
00265    }
00266    else{ // split face
00267      F=(Object[o].Ftracebase+f);
00268      V=Object[o].Vtracebase;
00269      v0=(V + F->V[0]);
00270      v1=(V + F->V[1]);
00271      v2=(V + F->V[2]);
00272      SplitFaceAtVoxelPlane(o,f,c,V,Object[o].Ftracebase,v0,v1,v2,F,p,index,na->oid,na->fid,nb->oid,nb->fid,&n1,&n2);
00273      ns++;
00274    }
00275  }
00276  //fprintf(debug,"Assigned to lower %ld  to upper %ld  and split %ld\n",nl,nr,ns);
00277  // assign the correct sizes to voxel face list
00278  if(ng > 0 && n1 == 0){
00279    X__Free(na->oid); na->oid=NULL;
00280    X__Free(na->fid); na->fid=NULL;
00281    X__Free(na->vxi); na->vxi=NULL;
00282  }
00283  else if(n1 > 0){
00284    na->oid=(UC *)X__Realloc(na->oid,sizeof(UC)*n1);
00285    na->vxi=(UC *)X__Realloc(na->vxi,sizeof(UC)*n1);
00286    na->fid=(US *)X__Realloc(na->fid,sizeof(US)*n1);
00287  }
00288  if(ng > 0 && n2 == 0){
00289    X__Free(nb->oid); nb->oid=NULL;
00290    X__Free(nb->fid); nb->fid=NULL;
00291    X__Free(nb->vxi); nb->vxi=NULL;
00292  }
00293  if(n2 > 0){
00294    nb->oid=(UC *)X__Realloc(nb->oid,sizeof(UC)*n2);
00295    nb->vxi=(UC *)X__Realloc(nb->vxi,sizeof(UC)*n2);
00296    nb->fid=(US *)X__Realloc(nb->fid,sizeof(US)*n2);
00297  }
00298  // parent voxel now split so free face list
00299  if(np->oid != NULL)X__Free(np->oid); np->oid=NULL;
00300  if(np->fid != NULL)X__Free(np->fid); np->fid=NULL;
00301  if(np->vxi != NULL)X__Free(np->vxi); np->vxi=NULL;
00302  na->n=n1;
00303  nb->n=n2;
00304  //fprintf(debug,"%ld split into %ld  %ld\n",np->n, na->n,nb->n); fflush(debug); 
00305  np->n=0; 
00306  return OK;
00307  FAILED:
00308  return FAIL;
00309 }
00310 
00311 static int MakeVoxels(node *np, int level){  // main recursive function
00312  static long i,j,k,o,f,n;
00313  static double x,y,z,an;
00314  static tvertex *v,*v0,*v1,*v2;
00315  static tface   *F;
00316  static vector p;
00317  static node Nd[6]; // used for temporary datastructures
00318  RenderYield();
00319  if(R_terminator() == FAIL)longjmp(x_buf,-1);
00320  //if(debug != NULL)fprintf(debug,"Examining voxel %ld with %ld faces - depth=%ld\n",np->id,np->n,tree_depth); 
00321  if(level > threshold_r)return OK;
00322  if(np->n < threshold_f)return OK;   /* reached voxel minimun mumber of faces */
00323  if((np->ma[0]-np->mi[0]) < threshold_z ||
00324     (np->ma[1]-np->mi[1]) < threshold_z ||
00325     (np->ma[2]-np->mi[2]) < threshold_z)return OK;  // minimum size of voxels
00326  //if(debug != NULL){
00327  //fprintf(debug,"Splitting!  bounds [%ld %ld] [%ld %ld] [%ld %ld] size = %ld %ld %ld\n",
00328  //np->mi[0],np->ma[0],np->mi[1],np->ma[1],np->mi[2],np->ma[2],
00329  //np->ma[0]-np->mi[0],np->ma[1]-np->mi[1],np->ma[2]-np->mi[2]);
00330  //if(np->last != NULL)fprintf(debug,"Parent %ld\n",np->last->id); else fprintf(debug,"Spliting ROOT\n");
00331  //}
00332 #if 0
00333  x=(double)(np->mi[0]+np->ma[0])*0.5;
00334  y=(double)(np->mi[1]+np->ma[1])*0.5;
00335  z=(double)(np->mi[2]+np->ma[2])*0.5;
00336 #else
00337  {// This attempts to place the dividing plane through a vertex as close to the center as
00338   // possible. THis avoids subdividing some faces.
00339   // It assumes that every face lies in the voxel and all vertices are either
00340   // on the edge or inside. 
00341   long ds,ip,md[3],mxx[3]={BIGP,BIGP,BIGP};
00342   tvertex *vid[3]={NULL,NULL,NULL};
00343   md[0]=(np->mi[0]+np->ma[0])/2;
00344   md[1]=(np->mi[1]+np->ma[1])/2;
00345   md[2]=(np->mi[2]+np->ma[2])/2;
00346   for(i=0;i<np->n;i++){ // each face
00347     o = (long)(*(np->oid+i));   f = (long)(*(np->fid+i));
00348     F=(Object[o].Ftracebase+f); v=Object[o].Vtracebase;
00349     for(j=0;j<3;j++){ // each vertex
00350       v0=(v + F->V[j]);
00351       for(k=0;k<3;k++){//each coord 
00352         ip=v0->ip[k]; 
00353         if(ip > np->mi[k]+16 && ip < np->ma[k]-16 & (ds=abs(ip - md[k])) < mxx[k]){ // away from box wall
00354           mxx[k]=ds; vid[k]=v0; // a suitable vertex
00355         }
00356       }
00357     }  
00358   } // all faces
00359   for(k=0;k<3;k++){ // check to see if this vertex is suitable for split or just use the mid point 
00360     if(vid[k] != NULL){
00361      ip=vid[k]->ip[k];
00362      if(ip > np->mi[k]+128 && ip < np->ma[k]-128)mxx[k]=ip; else mxx[k]=md[k];
00363     } 
00364   }
00365   x=(double)mxx[0]; y=(double)mxx[1]; z=(double)mxx[2]; 
00366  }
00367 #endif
00368  // x,y,z are the coordinates of the voxel splitting plane 
00369 
00370  // Partition the faces in Voxel "np"  by spltting at the split plane
00371  // first allocating the 8 child nodes in this octree.
00372  if(level > level_depth_max)level_depth_max=level;
00373  // temporary octree structures
00374  for(i=0;i<6;i++){
00375    Nd[i].n=0;
00376    Nd[i].oid=NULL;
00377    Nd[i].fid=NULL;
00378    Nd[i].vxi=NULL;
00379  }
00380  //  Create the child nodes
00381  level += 1;
00382  for(i=0;i<8;i++){
00383    if((np->octree[i]=(node *)X__Malloc(sizeof(node))) == NULL)return FAIL;
00384    np->octree[i]->n=0;
00385    np->octree[i]->oid=NULL;
00386    np->octree[i]->fid=NULL;
00387    np->octree[i]->vxi=NULL;
00388    for(j=0;j<8;j++){
00389      np->octree[i]->octree[j]=NULL;
00390    }
00391    kcount++;
00392    np->octree[i]->id=kcount;   // used for testing // RSFd
00393    np->octree[i]->last=np;     // testing
00394    np->octree[i]->level=level; // testing
00395  }
00396  if(trace_partition == 0){
00397  // split along planes - adding new faces this will re-create the vertex & face lists
00398  if(!SplitVoxel(np, &Nd[0], &Nd[1],(long)z,2))return FAIL; // give up if split failed
00399  if(!SplitVoxel(&Nd[0],&Nd[2],&Nd[3],(long)x,0))return FAIL;
00400  if(!SplitVoxel(&Nd[1],&Nd[4],&Nd[5],(long)x,0))return FAIL;
00401  if(!SplitVoxel(&Nd[2],np->octree[0],np->octree[1],(long)y,1))return FAIL;
00402  if(!SplitVoxel(&Nd[3],np->octree[2],np->octree[3],(long)y,1))return FAIL;
00403  if(!SplitVoxel(&Nd[4],np->octree[4],np->octree[5],(long)y,1))return FAIL;
00404  if(!SplitVoxel(&Nd[5],np->octree[6],np->octree[7],(long)y,1))return FAIL;
00405  } else {
00406  if(!PartitionVoxel(np, &Nd[0], &Nd[1],(long)z,2))return FAIL; // give up if split failed
00407  if(!PartitionVoxel(&Nd[0],&Nd[2],&Nd[3],(long)x,0))return FAIL;
00408  if(!PartitionVoxel(&Nd[1],&Nd[4],&Nd[5],(long)x,0))return FAIL;
00409  if(!PartitionVoxel(&Nd[2],np->octree[0],np->octree[1],(long)y,1))return FAIL;
00410  if(!PartitionVoxel(&Nd[3],np->octree[2],np->octree[3],(long)y,1))return FAIL;
00411  if(!PartitionVoxel(&Nd[4],np->octree[4],np->octree[5],(long)y,1))return FAIL;
00412  if(!PartitionVoxel(&Nd[5],np->octree[6],np->octree[7],(long)y,1))return FAIL;
00413  }
00414  /* recurse on to next level */
00415  MakeVoxels(np->octree[0],level);
00416  MakeVoxels(np->octree[1],level);
00417  MakeVoxels(np->octree[2],level);
00418  MakeVoxels(np->octree[3],level);
00419  MakeVoxels(np->octree[4],level);
00420  MakeVoxels(np->octree[5],level);
00421  MakeVoxels(np->octree[6],level);
00422  MakeVoxels(np->octree[7],level);
00423  return OK;
00424 }
00425 
00426 int buildBST(void){
00427  char temp[256];
00428  long i,j,k,l,coord,nv=0;
00429  long divisions;
00430  tvertex *v;
00431  tface   *f;
00432  nfaces=0; kcount=0; level_depth_max=0;
00433  voxel_xmin=voxel_ymin=voxel_zmin=BIGP;
00434  voxel_xmax=voxel_ymax=voxel_zmax=BIGN;
00435  Render_Message(31,0,NULL);
00436  ROOT=NULL;
00437  if(ObjectCount > 0)for(i=0;i<ObjectCount;i++){
00438    if(!Object[i].in_use)continue;
00439    Object[i].NoTraceVertices=Object[i].NoVertices;
00440    Object[i].NoTraceFaces=Object[i].NoFaces;
00441    nfaces += Object[i].NoTraceFaces;
00442    nv += Object[i].NoTraceVertices;
00443    // copy vertex and face data to the geometry data structures for ray-tracing
00444    if((Object[i].Vtracebase=(tvertex *)X__Malloc(Object[i].NoTraceVertices*sizeof(tvertex))) == NULL)return FAIL;
00445    for(j=0;j<Object[i].NoTraceVertices;j++){
00446      VECCOPY(Object[i].Vbase[j].ip,Object[i].Vtracebase[j].ip)
00447    }
00448    if((Object[i].Ftracebase=(tface *)X__Malloc(Object[i].NoTraceFaces*sizeof(tface))) == NULL)return FAIL;
00449    for(j=0;j<Object[i].NoTraceFaces;j++){
00450      VECCOPY(Object[i].Fbase[j].V,Object[i].Ftracebase[j].V)
00451      Object[i].Ftracebase[j].o=i;
00452      Object[i].Ftracebase[j].f=j;
00453      { // calculate normal vector used in partition algorithm
00454      vector v1,v2,n;
00455      VECSUB(Object[i].Vtracebase[Object[i].Ftracebase[j].V[1]].ip,
00456             Object[i].Vtracebase[Object[i].Ftracebase[j].V[0]].ip,v1)
00457      VECSUB(Object[i].Vtracebase[Object[i].Ftracebase[j].V[2]].ip,
00458             Object[i].Vtracebase[Object[i].Ftracebase[j].V[0]].ip,v2)
00459      CROSS(v1,v2,n)
00460      normalize(n);
00461      VECCOPY(n,Object[i].Ftracebase[j].n)
00462      }
00463    }
00464  }
00465  if(nfaces == 0)return 0;
00466  if((ROOT=(node *)X__Malloc(sizeof(node))) == NULL)return FAIL;
00467  ROOT->n=0;
00468  if((ROOT->oid=(UC *)X__Malloc(sizeof(UC ) * nfaces)) == NULL){
00469    destroyBST(ROOT); return FAIL;
00470  }
00471  if((ROOT->fid=(US *)X__Malloc(sizeof(US ) * nfaces)) == NULL){
00472    destroyBST(ROOT); return FAIL;
00473  }
00474  if((ROOT->vxi=(UC *)X__Malloc(sizeof(UC ) * nfaces)) == NULL){
00475    destroyBST(ROOT); return FAIL;
00476  }
00477  ROOT->n=nfaces;  // all polygons in root node to start with
00478  if((ObjectXlist=(long *)X__Malloc(sizeof(long)*ObjectCount)) == NULL)return FAIL;
00479  for(i=0,k=0;i<ObjectCount;i++){
00480   if(!Object[i].in_use)continue;
00481   f=Object[i].Ftracebase;
00482    for(j=0;j<Object[i].NoTraceFaces;j++){
00483      *(ROOT->oid+k)=(UC)i;
00484      *(ROOT->fid+k)=(US)j;
00485      *(ROOT->vxi+k)=(UC)0;
00486      k++;
00487      f++;
00488    }
00489  }
00490  for(i=0;i<8;i++)ROOT->octree[i]=NULL;
00491  ROOT->mi[0]=ROOT->mi[1]=ROOT->mi[2]=BIGP;
00492  ROOT->ma[0]=ROOT->ma[1]=ROOT->ma[2]=BIGN;
00493  ROOT->id=kcount; ROOT->last=NULL;  // Used for testing //RSFd
00494  for(i=0,k=0;i<ObjectCount;i++){
00495    if(!Object[i].in_use)continue;
00496    v = Object[i].Vtracebase;
00497    for(j=0;j<Object[i].NoTraceVertices;j++){
00498      for(l=0;l<3;l++){  //p are the transformed coordinates after effects and clipping
00499        if((coord=(long)(v->ip[l])) < ROOT->mi[l])ROOT->mi[l]=coord;
00500        if( coord                   > ROOT->ma[l])ROOT->ma[l]=coord;
00501      }
00502      k++;
00503      v++;
00504    }
00505  }
00506  if(k == 0)return 0;
00507  for(i=0;i<3;i++){
00508    ROOT->mi[i] -= 2;  // to ensure voxel contains all vertices
00509    ROOT->ma[i] += 2;
00510  }
00511  longest_ray = max((ROOT->ma[1]-ROOT->mi[1]),(ROOT->ma[0]-ROOT->mi[0]));
00512  longest_ray = max(longest_ray,(ROOT->ma[2]-ROOT->mi[2]));
00513  threshold_r=trace_depth;             //THRESHOLDR;
00514  threshold_f=trace_face_count_target; //THRESHOLDF;
00515  divisions = (long)(pow(2.0,(double)threshold_r));  // max number of subdivisions along a side;
00516  threshold_z=(long)(longest_ray/divisions);
00517  longest_ray *= 1.4142; 
00518  //if(debug != NULL){ 
00519  //  fprintf(debug,"Dimensions x %ld  y %ld  z%ld\nLongest Ray %lf\n",ROOT->ma[0]-ROOT->mi[0],
00520  //        ROOT->ma[1]-ROOT->mi[1],ROOT->ma[2]-ROOT->mi[2],longest_ray);
00521  //  fprintf(debug,"Thr_r %d  Thr_f %d Thr_d  %d  (div %d)\n",threshold_r,threshold_f,threshold_z,divisions);
00522  //}
00523  /* make the voxels   --  at this time ALL the faces are in voxel ROOT */
00524  if(setjmp(x_buf) != 0 || MakeVoxels(ROOT,0) == FAIL){
00525    destroyBST(ROOT);
00526    X__Free(ObjectXlist);
00527    return FAIL;
00528  }
00529  X__Free(ObjectXlist);
00530  i=nfaces;
00531  nfaces=0;
00532  maxfaces=0;
00533  minfaces=65536*65536;
00534  eliminateDuplicatesInBST(ROOT);
00535  countBST(ROOT);
00536  //printBST(ROOT);  
00537  // SaveDivided(nvoxels,ROOT,0,"c:\\divided_model.mfx"); // RSFd
00538  sprintf(temp,
00539   "Scene: F=%ld V=%ld [Dp=%ld Th=%ld F/v=%ld] Size %ld(%ld) [Vox=%ld Fc=%ld]",
00540         i,nv,level_depth_max,threshold_f,maxfaces,
00541         max(min(voxel_xmax,voxel_ymax),voxel_zmax)/512,
00542         min(min(voxel_xmin,voxel_ymin),voxel_zmin)/512,
00543         kcount,nfaces);
00544  WindowedRenderInfo(temp);
00545  //if(debug != NULL){ 
00546  //  fprintf(debug,"Number of original faces %d  Number of original vertices %d\n",i,nv);
00547  //  fprintf(debug,"Number of faces in structured model %d\n",nfaces);
00548  //  fprintf(debug,"Number of Voxels %d\n",kcount);
00549  //  fprintf(debug,"Max number of faces in Voxel %d\n",maxfaces); 
00550  //}
00551  return 0;
00552 }
00553 
00554 void freeBST(void){
00555  int i;
00556  if(ROOT != NULL)destroyBST(ROOT);
00557  if(ObjectCount > 0)for(i=0;i<ObjectCount;i++){
00558    if(!Object[i].in_use)continue;
00559    if(Object[i].Vtracebase != NULL)X__Free(Object[i].Vtracebase); 
00560    Object[i].Vtracebase=NULL;  Object[i].NoTraceVertices=0;
00561    if(Object[i].Ftracebase != NULL)X__Free(Object[i].Ftracebase); 
00562    Object[i].Ftracebase=NULL; Object[i].NoTraceFaces=0;
00563  }
00564 }
00565 
00566 static void destroyBST(node *np){
00567  if(np->octree[0] != NULL){destroyBST(np->octree[0]); np->octree[0]=NULL;}
00568  if(np->octree[1] != NULL){destroyBST(np->octree[1]); np->octree[1]=NULL;}
00569  if(np->octree[2] != NULL){destroyBST(np->octree[2]); np->octree[2]=NULL;}
00570  if(np->octree[3] != NULL){destroyBST(np->octree[3]); np->octree[3]=NULL;}
00571  if(np->octree[4] != NULL){destroyBST(np->octree[4]); np->octree[4]=NULL;}
00572  if(np->octree[5] != NULL){destroyBST(np->octree[5]); np->octree[5]=NULL;}
00573  if(np->octree[6] != NULL){destroyBST(np->octree[6]); np->octree[6]=NULL;}
00574  if(np->octree[7] != NULL){destroyBST(np->octree[7]); np->octree[7]=NULL;}
00575  if(np->fid != NULL){X__Free(np->fid); np->fid=NULL;}
00576  if(np->oid != NULL){X__Free(np->oid); np->oid=NULL;}
00577  if(np->vxi != NULL){X__Free(np->vxi); np->vxi=NULL;}
00578  X__Free(np); np=NULL;
00579  return;
00580 }
00581 
00582 static void countBST(node *np){
00583  char temp[256];
00584  int i;
00585  if(np->ma[0]-np->mi[0] < voxel_xmin)voxel_xmin=np->ma[0]-np->mi[0];
00586  if(np->ma[1]-np->mi[1] < voxel_ymin)voxel_ymin=np->ma[1]-np->mi[1];
00587  if(np->ma[2]-np->mi[2] < voxel_zmin)voxel_zmin=np->ma[2]-np->mi[2];
00588  if(np->ma[0]-np->mi[0] > voxel_xmax)voxel_xmax=np->ma[0]-np->mi[0];
00589  if(np->ma[1]-np->mi[1] > voxel_ymax)voxel_ymax=np->ma[1]-np->mi[1];
00590  if(np->ma[2]-np->mi[2] > voxel_zmax)voxel_zmax=np->ma[2]-np->mi[2];
00591  if(np->octree[0] != NULL)countBST(np->octree[0]);
00592  if(np->octree[1] != NULL)countBST(np->octree[1]);
00593  if(np->octree[2] != NULL)countBST(np->octree[2]);
00594  if(np->octree[3] != NULL)countBST(np->octree[3]);
00595  if(np->octree[4] != NULL)countBST(np->octree[4]);
00596  if(np->octree[5] != NULL)countBST(np->octree[5]);
00597  if(np->octree[6] != NULL)countBST(np->octree[6]);
00598  if(np->octree[7] != NULL)countBST(np->octree[7]);
00599  if(np->fid != NULL){
00600    if(np->n > maxfaces)maxfaces=np->n;
00601    if(np->n < minfaces)minfaces=np->n;
00602    nfaces += np->n;
00603  }
00604  return;
00605 }
00606 
00607 static void eliminateDuplicatesInBST(node *n){ // this does not reduce the number of divided Trace faces 
00608  if(n->n > 0){                                 // it just ensures that the list of each trace face in a voxel does not 
00609    static long i,o,f,ft,pfid,poid,c;           // point at same model face more than once. Helps speed up the tracing.
00610    US *next;
00611    pfid=-1,poid=-1; c=0;
00612    if((next=(US *)X__Malloc(sizeof(US)*n->n)) == NULL)return;
00613    for(i=0;i<n->n;i++){
00614      o=n->oid[i];
00615      f=n->fid[i];
00616      ft=(Object[o].Ftracebase + f)->f;  // points at equivalent face in main data structures
00617      if(!(ft == pfid && o == poid))next[c++]=i;  // lists first of any runs !
00618      pfid=ft; poid=o;
00619    }
00620    if(c < n->n)for(i=0;i<c;i++){ // re-order the list remove duplicates and shorten
00621      n->oid[i]=n->oid[next[i]];  // next[i] is always >= i
00622      n->fid[i]=n->fid[next[i]];
00623    }
00624    n->n=c;
00625    X__Free(next); 
00626  }
00627  if(n->octree[0] != NULL)eliminateDuplicatesInBST(n->octree[0]);
00628  if(n->octree[1] != NULL)eliminateDuplicatesInBST(n->octree[1]);
00629  if(n->octree[2] != NULL)eliminateDuplicatesInBST(n->octree[2]);
00630  if(n->octree[3] != NULL)eliminateDuplicatesInBST(n->octree[3]);
00631  if(n->octree[4] != NULL)eliminateDuplicatesInBST(n->octree[4]);
00632  if(n->octree[5] != NULL)eliminateDuplicatesInBST(n->octree[5]);
00633  if(n->octree[6] != NULL)eliminateDuplicatesInBST(n->octree[6]);
00634  if(n->octree[7] != NULL)eliminateDuplicatesInBST(n->octree[7]);
00635  return;
00636 
00637 }
00638 
00639 #define TOL    0.00001     
00640 
00641 // This group of functions tracks a ray by working down the voxel tree recursively and finding which voxels
00642 // it intersects. When we find that the ray passes through a voxel with some faces we check them for intersection
00643 // with the whole ray. -  Seems to work with shadows 
00644 
00645 static BOOL RayIntersectVoxelSides(node *n, double ddn, vector p1, vector d, vector p2, long i, long j, long k){
00646  double ppn,u,v,mu;
00647  if((p1[i] <= n->mi[i] && p2[i] >= n->mi[i]) ||
00648     (p2[i] <= n->mi[i] && p1[i] >= n->mi[i])){
00649    ppn=n->mi[i]-p1[i]; mu=ppn/ddn;
00650    u=p1[j]+mu*d[j];
00651    v=p1[k]+mu*d[k];
00652    if(u >= n->mi[j] && u <= n->ma[j] && v >= n->mi[k] && v <= n->ma[k])return TRUE;
00653  }
00654  if((p1[i] <= n->ma[i] && p2[i] >= n->ma[i]) ||
00655     (p2[i] <= n->ma[i] && p1[i] >= n->ma[i])){
00656    ppn=n->ma[i]-p1[i]; mu=ppn/ddn;
00657    u=p1[j]+mu*d[j];
00658    v=p1[k]+mu*d[k];
00659    if(u >= n->mi[j] && u <= n->ma[j] && v >= n->mi[k] && v <= n->ma[k])return TRUE;
00660  }
00661  return FALSE;
00662 }
00663 
00664 static BOOL RayThroughVoxel(node *n, vector p1, vector d, vector p2){
00665  double ddn,ppn,u,v;
00666  if(p1[0] < n->mi[0] && p2[0] < n->mi[0])return FALSE;
00667  if(p1[1] < n->mi[1] && p2[1] < n->mi[1])return FALSE;
00668  if(p1[2] < n->mi[2] && p2[2] < n->mi[2])return FALSE;
00669  if(p1[0] > n->ma[0] && p2[0] > n->ma[0])return FALSE;
00670  if(p1[1] > n->ma[1] && p2[1] > n->ma[1])return FALSE;
00671  if(p1[2] > n->ma[2] && p2[2] > n->ma[2])return FALSE;
00672  if(p1[0] >= n->mi[0] && p1[0] <= n->ma[0] &&
00673     p1[1] >= n->mi[1] && p1[1] <= n->ma[1] &&
00674     p1[2] >= n->mi[2] && p1[2] <= n->ma[2])return TRUE;
00675  if(p2[0] >= n->mi[0] && p2[0] <= n->ma[0] &&
00676     p2[1] >= n->mi[1] && p2[1] <= n->ma[1] &&
00677     p2[2] >= n->mi[2] && p2[2] <= n->ma[2])return TRUE;
00678  ddn=d[0]; if(fabs(ddn) > TOL)if(RayIntersectVoxelSides(n,ddn,p1,d,p2,0,1,2))return TRUE;
00679  ddn=d[1]; if(fabs(ddn) > TOL)if(RayIntersectVoxelSides(n,ddn,p1,d,p2,1,2,0))return TRUE;
00680  ddn=d[2]; if(fabs(ddn) > TOL)if(RayIntersectVoxelSides(n,ddn,p1,d,p2,2,0,1))return TRUE;
00681  return FALSE;
00682 }
00683 
00684 static void FeelerHitsFace(node *np, vector p, vector d, vector pl, double ld, 
00685                            long obj, long *glassc, BOOL *hit, BOOL *abort){
00686  int i,j,o;
00687  face   *f;
00688  long  ft;
00689  vertex *v;
00690  matl   *mat;
00691  double depth;
00692  unsigned char  mattr;
00693  long glass = 0;
00694  node *nx;
00695  if(*abort)return;
00696  //if(np->last != NULL) fprintf(debug,"Testing voxel %ld parent %ld (%ld faces)\n",np->id,np->last->id,np->n);
00697  //else fprintf(debug,"Testing root voxel %ld \n",np->id);
00698  if(!RayThroughVoxel(np,p,d,pl))return;
00699  //fprintf(debug,"Ray passes through voxel With %ld faces\n",np->n);
00700  if(np->n > 0){ /* some faces */
00701    for(i=0;i<np->n;i++){
00702      o=(int)(*(np->oid + i)); // change to reflect the actual face (this should be same for both main and trace lists
00703      if(!Object[o].cast_shadow)continue;
00704      if(!Object[obj].self_shadow && obj == o)continue;
00705      ft=(Object[o].Ftracebase + (int)(*(np->fid + i)))->f;  // points at equivalent face in the original model
00706      f=Object[o].Fbase + (int)(ft);   // change to relect the actual face
00707      v=Object[o].Vbase;
00708      if(f->ffmat >= 0 && f->ffmat < Object[o].NoMats){
00709        if(Object[o].Tbase != NULL){
00710          mat=(Object[o].Tbase + f->ffmat);
00711          mattr=mat->transp;
00712        }
00713        else mattr=1;
00714      }
00715      else mattr=1;
00716      //fprintf(debug,"Testing face %ld object %ld face %ld\n",i,o,(int)(*(np->fid + i)));
00717      if(R_intersect_face(p,d,
00718               (v + f->V[0])->p,(v + f->V[1])->p,(v + f->V[2])->p,
00719                f->n,&depth,32.0) && (depth < ld)){ // need this so not on far side of light
00720        if(mattr > 1)glassc++;
00721        else{
00722          *abort=TRUE;
00723          *hit=TRUE;
00724          return;
00725        }           
00726      }
00727    }
00728  }
00729  if((nx=np->octree[0]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);  else return; // all the rest will be NULL if this one is
00730  if((nx=np->octree[1]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort); 
00731  if((nx=np->octree[2]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort); 
00732  if((nx=np->octree[3]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);
00733  if((nx=np->octree[4]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);
00734  if((nx=np->octree[5]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);
00735  if((nx=np->octree[6]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);
00736  if((nx=np->octree[7]) != NULL)FeelerHitsFace(nx,p,d,pl,ld,obj,glassc,hit,abort);
00737  return;
00738 }
00739 
00740 short check_for_shadow(long obj, vector p, vector natp){
00741 /* p is point for shadow   natp  is normal at point p */
00742  int i,j;
00743  vector d,pp;
00744  double ld,alpha;
00745  long glassc=0;
00746  BOOL abort,hit;
00747 
00748  for(j=0;j<Nlights;j++)if(Lights[j].type != NOSHADOW &&
00749                           Lights[j].type != DUMMYL){
00750    if(Lights[j].type == SPOTLIGHT && Lights[j].shadow_buffer != NULL)continue;
00751    VECSUB(Lights[j].p,p,d)
00752    if(DOT(p,natp)*DOT(d,natp) > 0)continue; /* not illuminated by light */
00753    ld=(double)((d[0]*d[0]) + (d[1]*d[1]) + (d[2]*d[2]));
00754    if(ld > 1.e-10){
00755      ld=sqrt(ld);
00756      VECSCALE((1.0/ld),d,d)
00757      if(Lights[j].type == SPOTLIGHT){
00758        if((alpha=DOT(d,Lights[j].d)) < Lights[j].dot2){
00759             continue; /* outside light cone */
00760        }
00761      }
00762      abort=FALSE;
00763      hit=FALSE;
00764      VECCOPY(p,pp)     
00765      //fprintf(debug,"Starting test from point (%lf %lf %lf) to light at (%lf %lf %lf)\n",p[0],p[1],p[2],Lights[j].p[0],Lights[j].p[1],Lights[j].p[2]);
00766      FeelerHitsFace(ROOT,pp,d,Lights[j].p,ld,obj,&glassc,&hit,&abort);
00767      if(hit)return -1;
00768    }
00769  }
00770  return glassc;
00771 }
00772 
00773 static void GetRayIntersectionFace(node *np, vector p, vector d, // start at p and in direction d
00774                            double *ld, // start off with longest distance to be sure outside object
00775                            long *closest_o, long *closest_f){
00776  // work with whole ray - work through whole of Octree structure - find any faces the ray intersects
00777  // only look for any faces that lie closer to the starting point when testing the next voxel level
00778  int i,j,o,fi;
00779  face   *f;
00780  long ft;
00781  vertex *v;
00782  double depth;
00783  node *nx;
00784  vector pl;
00785  VECSUM(p,(*ld)*d,pl)  // point on outside - end of ray 
00786  if(!RayThroughVoxel(np,p,d,pl))return;  // between p and pl
00787  if(np->n > 0){ /* some faces */
00788    for(i=0;i<np->n;i++){
00789      o=(int)(*(np->oid + i)); // change to reflect the actual face -- this should be the same - because no new objects are introduced by the face splitting
00790      ft=(Object[o].Ftracebase + (int)(*(np->fid + i)))->f;  // points at equivalent face in original model
00791      f=Object[o].Fbase + (fi=(int)(ft));   // change to relect the actual face
00792      v=Object[o].Vbase;
00793      if(R_intersect_face(p,d,
00794               (v + f->V[0])->p,(v + f->V[1])->p,(v + f->V[2])->p,
00795                f->n,&depth,32.0)){
00796        if(depth < *ld){
00797          *ld=depth;   // only check any subsequent voxels if they are nearer the origin
00798          *ld=depth - 10.0;    // only check any subsequent voxels if they are nearer the origin
00799          *closest_o = o;   // change to reflect  actual face ID
00800          *closest_f = fi;
00801        }           
00802      }
00803    }
00804  }
00805  if((nx=np->octree[0]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00806  if((nx=np->octree[1]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f); 
00807  if((nx=np->octree[2]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f); 
00808  if((nx=np->octree[3]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00809  if((nx=np->octree[4]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00810  if((nx=np->octree[5]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00811  if((nx=np->octree[6]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00812  if((nx=np->octree[7]) != NULL)GetRayIntersectionFace(nx,p,d,ld,closest_o,closest_f);
00813  return;
00814 }
00815 
00816 BOOL trace_starting_ray(vector d, vector p,
00817                         int *ob, int *fc, face **ff){
00818 /*  p is point of ray origin on entry point of hit on exit
00819     d is incident direction of ray (normalized)
00820 */
00821  int o,q;
00822  double depth;
00823  o=-1; 
00824  depth=(double)FARAWAY;
00825  GetRayIntersectionFace(ROOT,p,d,&depth,&o,&q);
00826  if(o < 0)return FALSE; // no hit with this ray  
00827  *ff=(Object[o].Fbase + q);
00828  *fc=q;
00829  *ob=o;
00830  VECSCALE(depth,d,p)
00831  return TRUE;
00832 }
00833 
00834 short trace_reflection_ray(vector p, vector d, /* d is normalized */
00835                            double depth_max, double *colour,
00836                            int at_o, face *at_f,
00837                            long trace_reflection_depth,
00838                            long trace_refraction_depth,
00839                            long refractive_flag){
00840  int o=-1,q;
00841  face *f;
00842  vertex *v;
00843  double depth=longest_ray;
00844 TRY_START_AGAIN:
00845  o=-1; 
00846  depth=longest_ray;
00847  VECSUM(p,128.0*d,p) // under test
00848  GetRayIntersectionFace(ROOT,p,d,&depth,&o,&q);
00849  if(o < 0)return 0; // no hit with this ray  
00850  f=(Object[o].Fbase + q);
00851  if(o == at_o && f == at_f){
00852    // hit the same face - increment the starting point along the ray and try again
00853    goto TRY_START_AGAIN; 
00854  }
00855  v=Object[o].Vbase;
00856  f=(Object[o].Fbase + q);
00857  depth_max=depth;
00858  if(trace_reflection_depth < trace_depth_max){
00859    //colour[0] = (double)0;  colour[1] = (double)255; colour[2] = (double)0; 
00860    trace_reflection_depth++;
00861    GetSurfaceValue(o,f,v,p,d,
00862    colour,(colour+1),(colour+2),
00863    trace_reflection_depth,
00864    trace_refraction_depth,
00865    refractive_flag);
00866  }
00867  return 1;
00868 }
00869 
00870 void trace_transmission_ray(vector p, vector d, vector n,
00871                           int at_o, face *at_f,
00872                           double depth_max, double *colour,
00873                           long trace_reflection_depth,
00874                           long trace_refraction_depth,
00875                           long refractive_flag){
00876 /*  p is point on glass face of ray hit
00877     d is incident direction of ray (normalized)
00878     n is normal of face on which ray is incident
00879     depth_max is maximum depth to trace to
00880 */
00881  int o,q;
00882  vector pc;
00883  face   *f;
00884  vertex *v;
00885  double depth;
00886  TRY_START_AGAIN:
00887  o=-1;
00888  depth=longest_ray;
00889  // go through the current face by 1000 units to make sure we dont hit the same face
00890  VECSUM(p,128.0*d,p) 
00891  GetRayIntersectionFace(ROOT,p,d,&depth,&o,&q);
00892  if(o < 0)return; // no hit with this ray  
00893  f=(Object[o].Fbase + q);
00894  if(o == at_o && f == at_f){
00895    // hit the same face - increment the starting point along the ray and try again
00896    goto TRY_START_AGAIN; 
00897  }
00898  v=Object[o].Vbase;
00899  if(trace_refraction_depth < trace_depth_max){
00900   trace_refraction_depth++;
00901    GetSurfaceValue(o,f,v,p,d,
00902                    colour,(colour+1),(colour+2),
00903                    trace_reflection_depth,
00904                    trace_refraction_depth,
00905                    refractive_flag);
00906  }
00907  return;
00908 }
00909 
00910 
00911 void trace_refraction_ray(vector p, vector d, vector n,
00912                           int at_o, face *at_f,
00913                           double depth_max, double *colour, int refx,
00914                           long trace_reflection_depth,
00915                           long trace_refraction_depth,
00916                           long refractive_flag){
00917 /*  p is point on glass face of ray hit
00918     d is incident direction of ray (normalized)
00919     n is normal of face on which ray is incident
00920     depth_max is maximum depth to trace to
00921 */
00922  int o,q;
00923  vector pc,temp,qq;
00924  face   *f;
00925  vertex *v;
00926  double depth,ddn;
00927  vector dp,gp;
00928  double pdotn,ddotn,mu,qnorm;
00929  unsigned char red,green,blue;
00930  // colour[0] = (double)255;  colour[1] = (double)0; colour[2] = (double)0;  return; 
00931  ddn=DOT(d,n);
00932  if(ddn > 0.0){
00933    ddn = -ddn; n[0] = -n[0]; n[1] = -n[1]; n[2] = -n[2];
00934  }
00935  VECSCALE(ddn,n,temp)
00936  VECSUB(d,temp,temp)
00937  if(refractive_flag == 0){
00938    VECSCALE(1000.0/(double)refx,temp,qq)
00939  }
00940  else{
00941    VECSCALE((double)refx/1000.0,temp,qq)
00942  }
00943  refractive_flag ^= 1;  /* each intersection is assumed air/glass */
00944  qnorm=qq[0]*qq[0]+qq[1]*qq[1]+qq[2]*qq[2];
00945  if(qnorm > 1.0){
00946    VECSCALE(sqrt(qnorm-1.0),n,temp)
00947    VECSUM(qq,temp,d)
00948    ddn=d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
00949    ddn=sqrt(ddn);
00950    VECSCALE((1.0/ddn),d,d)  /* d is normalised new ray direction */
00951  }
00952  else{
00953    VECSCALE(sqrt(1.0-qnorm),n,temp)
00954    VECSUB(qq,temp,d)
00955    ddn=d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
00956    ddn=sqrt(ddn);
00957    VECSCALE((1.0/ddn),d,d)  /* d is normalised new ray direction */
00958  }
00959  /* get the ground or sky value for this ray in case no other Xn's */
00960  if(R_Nground > 0 && fabs(ddotn=dot(Ground.n,d)) > 1.e-3){
00961    VECSUB(Ground.p,p,dp)
00962    pdotn=DOT(Ground.n,dp);
00963    mu=pdotn/ddotn;
00964    if(mu > 0.0){
00965      vecscale(mu,d,gp);
00966      vecsum(p,gp,gp);
00967      GetGroundLight(gp,&colour[0],&colour[1],&colour[2]);
00968      depth_max = mu;
00969    }
00970    else goto NEXTBLOCK;
00971  }
00972  else{
00973    NEXTBLOCK:
00974    colour[0] = (double)Sky.Zenith[0];
00975    colour[1] = (double)Sky.Zenith[1];
00976    colour[2] = (double)Sky.Zenith[2];
00977    // this is NOT correct for GRADED but is a small problem
00978    if(Sky.type == SKYMAPPED){
00979      ddotn=d[2];
00980      if(fabs(ddotn) > 1.e-2){
00981        vecsub(Sky.map.p,p,dp);
00982        pdotn=dp[2];
00983        mu=pdotn/ddotn;
00984        vecscale(fabs(mu),d,gp);
00985        vecsum(p,gp,gp);
00986        MapFromProjection(&Sky.map,TILE,EOPAQUE,gp,&colour[0],&colour[1],&colour[2]);
00987      }
00988    }
00989    else if(Sky.type == SKYCUBE){
00990      MapEnvironmentInDirection(d,&colour[0],&colour[1],&colour[2],&Sky.map);
00991    }
00992  }
00993  TRY_START_AGAIN:
00994  o=-1; 
00995  depth=longest_ray;
00996  // go through the current face by 1000 units to make sure we dont hit the same face
00997  VECSUM(p,128.0*d,p) 
00998  GetRayIntersectionFace(ROOT,p,d,&depth,&o,&q);
00999  if(o < 0)return; // no hit with this ray  
01000  f=(Object[o].Fbase + q);
01001  if(o == at_o && f == at_f){
01002    // hit the same face - increment the starting point along the ray and try again
01003    goto TRY_START_AGAIN; 
01004  }
01005  v=Object[o].Vbase;
01006  if(trace_refraction_depth < trace_depth_max){
01007    trace_refraction_depth++;
01008    GetSurfaceValue(o,f,v,p,d,
01009                    colour,(colour+1),(colour+2),
01010                    trace_reflection_depth,
01011                    trace_refraction_depth,
01012                    refractive_flag);
01013  }
01014  return;
01015 }
01016 
01018 
01019 #if 0
01020 
01021 static void printBST(node *n){
01022  if(debug == NULL)return;
01023  if(n->n > 0){  // only print voxels with faces
01024    static int i,o,f,ft;
01025    fprintf(debug,"Voxel id=%5ld (Has %5ld Faces) (At level %5ld) Edges[%8ld][%8ld][%8ld]",n->id,n->n, n->level, n->ma[0]-n->mi[0],n->ma[1]-n->mi[1],n->ma[2]-n->mi[2]);
01026    if(n->last != NULL)fprintf(debug," -> %ld\n",n->last->id);
01027    else               fprintf(debug," ROOT \n");
01028    for(i=0;i<n->n;i++){
01029      o=n->oid[i];
01030      f=n->fid[i];
01031      Object[o].Ftracebase[f].x = n->id;  // used for debugging idetifies which voxel this face belongs to
01032      ft=(Object[o].Ftracebase + f)->f;  // points at equivalent face in main data structures
01033      fprintf(debug, "V%5ld F%3ld  -  (F)%6ld (O=%d) Maps to face %6ld\n",n->id,i,f,o,ft);
01034    }
01035  }
01036 
01037  if(n->octree[0] != NULL)printBST(n->octree[0]);
01038  if(n->octree[1] != NULL)printBST(n->octree[1]);
01039  if(n->octree[2] != NULL)printBST(n->octree[2]);
01040  if(n->octree[3] != NULL)printBST(n->octree[3]);
01041  if(n->octree[4] != NULL)printBST(n->octree[4]);
01042  if(n->octree[5] != NULL)printBST(n->octree[5]);
01043  if(n->octree[6] != NULL)printBST(n->octree[6]);
01044  if(n->octree[7] != NULL)printBST(n->octree[7]);
01045  return;
01046 }
01047 
01048 #endif
01049 
01051 
01052 static BOOL  EdgeCrossBoxFaceX(ivector vi1, ivector vi2, long p, 
01053                               long ymin, long ymax,  long zmin, long zmax){
01054  long d1,d2,vo1,vo2,imu;
01055  double mu;
01056  if((imu=vi2[0]-vi1[0]) == 0)return FALSE;
01057  d1=vi1[0]-p; d2=vi2[0]-p;
01058  if((double)d1*(double)d2 >= 0.0)return FALSE; // edge does not cross the face
01059  mu=((double)(p-vi1[0]))/(double)imu;
01060  vo1=vi1[1]+(long)(mu*((double)(vi2[1]-vi1[1])));
01061  vo2=vi1[2]+(long)(mu*((double)(vi2[2]-vi1[2])));
01062  if(ymin <= vo1 && vo1 <= ymax && zmin <= vo2 && vo2 <= zmax)return TRUE; 
01063  return FALSE;
01064 }
01065 
01066 static BOOL  EdgeCrossBoxFaceY(ivector vi1, ivector vi2, long p, 
01067                               long zmin, long zmax,  long xmin, long xmax){
01068  long d1,d2,vo1,vo2,imu;
01069  double mu;
01070  if((imu=vi2[1]-vi1[1]) == 0)return FALSE;
01071  d1=vi1[1]-p; d2=vi2[1]-p;
01072  if((double)d1*(double)d2 >= 0.0)return FALSE; // edge does not cross the face
01073  mu=((double)(p-vi1[1]))/(double)imu;
01074  vo1=vi1[2]+(long)(mu*((double)(vi2[2]-vi1[2])));
01075  vo2=vi1[0]+(long)(mu*((double)(vi2[0]-vi1[0])));
01076  if(zmin <= vo1 && vo1 <= zmax && xmin <= vo2 && vo2 <= xmax)return TRUE; 
01077  return FALSE;
01078 }
01079 
01080 static BOOL  EdgeCrossBoxFaceZ(ivector vi1, ivector vi2, long p, 
01081                               long xmin, long xmax,  long ymin, long ymax){
01082  long d1,d2,vo1,vo2,imu;
01083  double mu;
01084  if((imu=vi2[2]-vi1[2]) == 0)return FALSE;
01085  d1=vi1[2]-p; d2=vi2[2]-p;
01086  if((double)d1*(double)d2 >= 0.0)return FALSE; // edge does not cross the face
01087  mu=((double)(p-vi1[2]))/(double)imu;
01088  vo1=vi1[0]+(long)(mu*((double)(vi2[0]-vi1[0])));
01089  vo2=vi1[1]+(long)(mu*((double)(vi2[1]-vi1[1])));
01090  if(xmin <= vo1 && vo1 <= xmax && ymin <= vo2 && vo2 <= ymax)return TRUE; 
01091  return FALSE;
01092 }
01093 
01094 static BOOL OnFaceEdge(node *n, long id, ivector ip){
01095  if      (id == 0 &&
01096   ip[1]==n->mi[1] && n->mi[0]<=ip[0] && ip[0]<=n->ma[0] && n->mi[2]<=ip[2] && ip[2]<=n->ma[2])return TRUE; 
01097  else if (id == 1 &&
01098   ip[1]==n->ma[1] && n->mi[0]<=ip[0] && ip[0]<=n->ma[0] && n->mi[2]<=ip[2] && ip[2]<=n->ma[2])return TRUE; 
01099  else if (id == 2 &&
01100   ip[0]==n->mi[0] && n->mi[1]<=ip[1] && ip[1]<=n->ma[1] && n->mi[2]<=ip[2] && ip[2]<=n->ma[2])return TRUE; 
01101  else if (id == 3 &&
01102   ip[0]==n->ma[0] && n->mi[1]<=ip[1] && ip[1]<=n->ma[1] && n->mi[2]<=ip[2] && ip[2]<=n->ma[2])return TRUE; 
01103  else if (id == 4 &&
01104   ip[2]==n->mi[2] && n->mi[0]<=ip[0] && ip[0]<=n->ma[0] && n->mi[1]<=ip[1] && ip[1]<=n->ma[1])return TRUE; 
01105  else if (id == 5 &&
01106   ip[2]==n->ma[2] && n->mi[0]<=ip[0] && ip[0]<=n->ma[0] && n->mi[1]<=ip[1] && ip[1]<=n->ma[1])return TRUE; 
01107  return FALSE;
01108 }
01109 
01110 static BOOL BoxEdgeCrossFace(ivector p1, ivector p2, long index, long len, vector n, 
01111                              ivector pf0, ivector pf1, ivector pf2){
01112  vector d,v1,pi,w,u,v;
01113  double mu,a,b,de,uu,vv,wu,wv,uv; 
01114  static vector dd[5]={{0.0,0.0,1.0},{0.0,1.0,0.0},{-1.0,0.0,0.0},{0.0,-1.0,0.0},{0.0,0.0,1.0}};
01115  VECCOPY(dd[index],d)  // direction 
01116  mu=DOT(d,n);
01117  if(fabs(mu) < 0.0001)return FALSE;   /* parallel to face */
01118  VECSUB(pf0,p1,v1)
01119  mu=DOT(n,v1)/mu;
01120  if(mu <= 0.0)return FALSE;          /* behind            */
01121  if(mu >= len)return FALSE;          /* beyond            */
01122  VECSCALE(mu,d,v1)
01123  VECSUM(p1,v1,pi)   // intersect point
01124  VECSUB(pi,pf0,w)
01125  VECSUB(pf1,pf0,u)
01126  VECSUB(pf2,pf0,v)
01127  uv=DOT(u,v);
01128  uu=DOT(u,u);
01129  vv=DOT(v,v);
01130  de=uu*vv-uv*uv;
01131  if(fabs(de) < 32)return FALSE;  // smallest cell
01132  wu=DOT(w,u);
01133  wv=DOT(w,v);
01134  a=(wu*vv-wv*uv)/de; 
01135  b=(wv*uu-wu*uv)/de;
01136  if( a <= 0.0 || a >= 1.0 || b <= 0.0|| b >= 1.0 || (a+b) >= 1.0)return FALSE;
01137  return TRUE; // strictly inside
01138 } 
01139 
01140 static BOOL TouchingFaceOutsideBox(node *n, ivector ip1, ivector ip2, ivector ip3){
01141  long ma,i;
01142  for(i=0;i<3;i++){ 
01143    if(ip1[i] == n->ma[i] && ip2[i] >= n->ma[i] && ip3[i] >= n->ma[i])return TRUE;
01144    if(ip1[i] == n->mi[i] && ip2[i] <= n->mi[i] && ip3[i] <= n->mi[i])return TRUE;
01145  }
01146  return FALSE;
01147 }
01148 
01149 static BOOL FaceInVoxel(node *n, tvertex *vBase, tface *f){
01150  // does face "f" lie inside node "n" 
01151  long i,j,c,c0,c1,c2,ma,mi;
01152  static long vxi1[12]={0,1,2,3,4,5,6,7,0,1,2,3}, // link from this voxel vertex 
01153              vxi2[12]={1,2,3,0,5,6,7,4,4,5,6,7}, // to this voxel vertex 
01154              vxdi[12]={0,1,2,3,0,1,2,3,4,4,4,4}, // in this directions (0=x 1=y= 2=z)
01155              len[12];
01156  tvertex *v;  
01157  ivector p1,p2,voxv[8];
01158  // it will return false if every vertex (3) is on the outside of each of the (6) faces
01159  // eg. if every vertex x coord is > max x coord
01160  for(i=0;i<3;i++){ // coords
01161    ma=n->ma[i]; mi=n->mi[i];
01162    c0=(vBase+f->V[0])->ip[i]; c1=(vBase+f->V[1])->ip[i]; c2=(vBase+f->V[2])->ip[i];
01163    if(c0 > ma && c1 > ma && c2 > ma)return FALSE;
01164    if(c0 < mi && c1 < mi && c2 < mi)return FALSE;
01165  }
01166  // it will return true if any vertex is strictly inside (3)
01167  for(j=0;j<3;j++){ 
01168    v=(vBase+f->V[j]);
01169    if(v->ip[0] > n->mi[0] && v->ip[0] < n->ma[0] &&
01170       v->ip[1] > n->mi[1] && v->ip[1] < n->ma[1] &&
01171       v->ip[2] > n->mi[2] && v->ip[2] < n->ma[2])return TRUE;
01172  } 
01173  // it will return true if every vertex (3)  is on a voxel face (6)
01174  for(i=0;i<6;i++){  
01175    if(OnFaceEdge(n,i,(vBase+f->V[0])->ip) && 
01176       OnFaceEdge(n,i,(vBase+f->V[1])->ip) && 
01177       OnFaceEdge(n,i,(vBase+f->V[2])->ip)) return TRUE;
01178  }
01179  // if will return false if one vertex is on a voxel face edge plane and the other two are
01180  // on the ourside of that face plane
01181  if(TouchingFaceOutsideBox(n,(vBase+f->V[0])->ip,(vBase+f->V[1])->ip,(vBase+f->V[2])->ip))return FALSE;
01182  if(TouchingFaceOutsideBox(n,(vBase+f->V[1])->ip,(vBase+f->V[2])->ip,(vBase+f->V[0])->ip))return FALSE;
01183  if(TouchingFaceOutsideBox(n,(vBase+f->V[2])->ip,(vBase+f->V[0])->ip,(vBase+f->V[1])->ip))return FALSE;
01184  // it will return true if any face edge (3) strictly crossed one of the (6) voxel faces
01185  for(i=0;i<3;i++){
01186    if     (i == 0){ VECCOPY((vBase+f->V[0])->ip,p1)  VECCOPY((vBase+f->V[1])->ip,p2) }
01187    else if(i == 1){ VECCOPY((vBase+f->V[1])->ip,p1)  VECCOPY((vBase+f->V[2])->ip,p2) }
01188    else           { VECCOPY((vBase+f->V[2])->ip,p1)  VECCOPY((vBase+f->V[0])->ip,p2) }
01189    if(EdgeCrossBoxFaceX(p1,p2,n->mi[0],  n->mi[1],n->ma[1],n->mi[2],n->ma[2]))return TRUE;
01190    if(EdgeCrossBoxFaceX(p1,p2,n->ma[0],  n->mi[1],n->ma[1],n->mi[2],n->ma[2]))return TRUE;
01191    if(EdgeCrossBoxFaceY(p1,p2,n->mi[1],  n->mi[2],n->ma[2],n->mi[0],n->ma[0]))return TRUE;
01192    if(EdgeCrossBoxFaceY(p1,p2,n->ma[1],  n->mi[2],n->ma[2],n->mi[0],n->ma[0]))return TRUE;
01193    if(EdgeCrossBoxFaceZ(p1,p2,n->mi[2],  n->mi[0],n->ma[0],n->mi[1],n->ma[1]))return TRUE;
01194    if(EdgeCrossBoxFaceZ(p1,p2,n->ma[2],  n->mi[0],n->ma[0],n->mi[1],n->ma[1]))return TRUE;
01195  }
01196  // it will return true if any voxel edge (12) passes through a face
01197  voxv[0][0]=n->mi[0]; voxv[0][1]=n->mi[1]; voxv[0][2]=n->mi[2];
01198  voxv[1][0]=n->ma[0]; voxv[1][1]=n->mi[1]; voxv[1][2]=n->mi[2];
01199  voxv[2][0]=n->ma[0]; voxv[2][1]=n->ma[1]; voxv[2][2]=n->mi[2];
01200  voxv[3][0]=n->mi[0]; voxv[3][1]=n->ma[1]; voxv[3][2]=n->mi[2];
01201  voxv[4][0]=n->mi[0]; voxv[4][1]=n->mi[1]; voxv[4][2]=n->ma[2];
01202  voxv[5][0]=n->ma[0]; voxv[5][1]=n->mi[1]; voxv[5][2]=n->ma[2];
01203  voxv[6][0]=n->ma[0]; voxv[6][1]=n->ma[1]; voxv[6][2]=n->ma[2];
01204  voxv[7][0]=n->mi[0]; voxv[7][1]=n->ma[1]; voxv[7][2]=n->ma[2];
01205  len[0]=len[2]=len[4]=len[6]=n->ma[0]-n->mi[0];
01206  len[1]=len[3]=len[5]=len[7]=n->ma[1]-n->mi[1];
01207  len[8]=len[9]=len[10]=len[11]=n->ma[2]-n->mi[2];
01208  for(i=0;i<12;i++){
01209    if(BoxEdgeCrossFace(voxv[vxi1[i]],voxv[vxi2[i]],vxdi[i],len[i],f->n,
01210       (vBase+f->V[0])->ip,(vBase+f->V[1])->ip,(vBase+f->V[2])->ip))return TRUE;
01211  }
01212  return FALSE;
01213 }
01214 
01215 static BOOL PartitionVoxel(node *np, node *na, node *nb, long p, long index){ // index = 2 for z coord 0 for x coord
01216   // split polygons in node "np" into the two sub nodes "na" and "nb" at plane "p" 
01217  long i,nnp,nx,n1,n2,o,f,c,sz,xvf,nl,nr,ns,ng;
01218  tface *F;
01219  tvertex *V,*v0,*v1,*v2;
01220  nnp=np->n;
01221  // assign max and min for the new voxels
01222  //if(debug != NULL)fprintf(debug,"Split voxel with %ld faces in plane %ld at %ld\n",nnp,index,p); 
01223  for(i=0;i<3;i++){
01224    na->mi[i]=nb->mi[i]=np->mi[i];
01225    na->ma[i]=nb->ma[i]=np->ma[i];
01226  }
01227  na->ma[index]=p;     //  "na" points at voxel with the lesser coord value  
01228  nb->mi[index]=p;     //  "nb" to one with greater coord value
01229  // calculate number of extra vertices and faces required  
01230  for(i=0;i<ObjectCount;i++)ObjectXlist[i]=0;
01231  for(i=0;i<nnp;i++){  
01232    *(np->vxi+i) = 0;
01233  }
01234  // allocate space for extra faces and vertices - this is absolute
01235  for(i=0,nx=0;i<ObjectCount;i++)if((xvf=ObjectXlist[i]) > 0){
01236    sz=(Object[i].NoTraceVertices+xvf)*(long)sizeof(tvertex);
01237    if((V=(tvertex  *)X__Realloc(Object[i].Vtracebase,sz)) == NULL)goto FAILED;
01238    Object[i].Vtracebase=V;
01239    sz=(Object[i].NoTraceFaces+xvf)*(long)sizeof(tface);
01240    if((F=(tface  *)X__Realloc(Object[i].Ftracebase,sz)) == NULL)goto FAILED;
01241    Object[i].Ftracebase=F;
01242    nx += xvf;
01243  }
01244  // allocate space for list of vertices and in child nodes. This is relative to voxel.
01245  // this will be over estimate since some of the added faces will go in one voxel and
01246  // some in the other
01247  ng=nnp+nx;
01248  //fprintf(debug,"Guessed voxel count %ld\n",ng);
01249  if(ng > 0){
01250    if((na->oid=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
01251    if((na->fid=(US *)X__Malloc(sizeof(US)*ng)) == NULL)goto FAILED;
01252    if((na->vxi=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
01253    if((nb->oid=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
01254    if((nb->fid=(US *)X__Malloc(sizeof(US)*ng)) == NULL)goto FAILED;
01255    if((nb->vxi=(UC *)X__Malloc(sizeof(UC)*ng)) == NULL)goto FAILED;
01256    for(i=0;i<ng;i++){na->oid[i]=999,na->fid[i]=999,na->vxi[i]=999;nb->oid[i]=666,nb->fid[i]=666,nb->vxi[i]=666;} // For testing
01257  }
01258  // split vertices and faces - allocate them to the appropriate sub voxel - use VXI code
01259  nl=nr=ns=0;
01260  for(i=0,n1=0,n2=0;i<nnp;i++){  
01261    c = (long)(*(np->vxi+i));   
01262    o = (long)(*(np->oid+i));
01263    f = (long)(*(np->fid+i));
01264 //index 0 = x plane
01265    F=(Object[o].Ftracebase+f);
01266    V=Object[o].Vtracebase;
01267    if(FaceInVoxel(na,V,F)){
01268      *(na->fid+n1)=f; 
01269      *(na->oid+n1)=o; n1++;
01270      nl++;
01271    }
01272    if(FaceInVoxel(nb,V,F)) {
01273      *(nb->fid+n2)=f; 
01274      *(nb->oid+n2)=o; n2++;
01275      nr++;
01276    }
01277  }
01278  //fprintf(debug,"Assigned to lower %ld  to upper %ld  and split %ld\n",nl,nr,ns);
01279  // assign the correct sizes to voxel face list
01280  if(ng > 0 && n1 == 0){
01281    X__Free(na->oid); na->oid=NULL;
01282    X__Free(na->fid); na->fid=NULL;
01283    X__Free(na->vxi); na->vxi=NULL;
01284  }
01285  else if(n1 > 0){
01286    na->oid=(UC *)X__Realloc(na->oid,sizeof(UC)*n1);
01287    na->vxi=(UC *)X__Realloc(na->vxi,sizeof(UC)*n1);
01288    na->fid=(US *)X__Realloc(na->fid,sizeof(US)*n1);
01289  }
01290  if(ng > 0 && n2 == 0){
01291    X__Free(nb->oid); nb->oid=NULL;
01292    X__Free(nb->fid); nb->fid=NULL;
01293    X__Free(nb->vxi); nb->vxi=NULL;
01294  }
01295  if(n2 > 0){
01296    nb->oid=(UC *)X__Realloc(nb->oid,sizeof(UC)*n2);
01297    nb->vxi=(UC *)X__Realloc(nb->vxi,sizeof(UC)*n2);
01298    nb->fid=(US *)X__Realloc(nb->fid,sizeof(US)*n2);
01299  }
01300  // parent voxel now split so free face list
01301  if(np->oid != NULL)X__Free(np->oid); np->oid=NULL;
01302  if(np->fid != NULL)X__Free(np->fid); np->fid=NULL;
01303  if(np->vxi != NULL)X__Free(np->vxi); np->vxi=NULL;
01304  na->n=n1;
01305  nb->n=n2;
01306  //fprintf(debug,"%ld split into %ld  %ld\n",np->n, na->n,nb->n); fflush(debug); 
01307  np->n=0; 
01308  return OK;
01309  FAILED:
01310  return FAIL;
01311 }

Generated on Sun Apr 27 14:20:13 2014 for OpenFX by  doxygen 1.5.6