ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/oococt.c
(Generate patch)

Comparing ray/src/rt/oococt.c (file contents):
Revision 2.2 by greg, Wed Feb 25 17:19:52 2015 UTC vs.
Revision 2.3 by rschregle, Tue May 17 17:39:47 2016 UTC

# Line 1 | Line 1
1   /*
2 <   ==================================================================
2 >   ======================================================================
3     Out-of-core octree data structure
4    
5     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
6 <   (c) Fraunhofer Institute for Solar Energy Systems,
7 <       Lucerne University of Applied Sciences & Arts  
8 <   ==================================================================
6 >   (c) Lucerne University of Applied Sciences and Arts,
7 >       supported by the Swiss National Science Foundation (SNSF, #147053)
8 >   ======================================================================
9    
10     $Id$
11   */
12  
13  
14 < #include <stdlib.h>
14 >
15   #include "oococt.h"
16 < #include "oocsort.h"
16 > #include "rtio.h"
17 > #include <stdlib.h>
18 > #include <unistd.h>
19  
20  
21 < static OOC_Sort_Key zInterleave (OOC_Sort_Key k)
22 < /* Interleave lower 21 bits of k with 00, resulting in 63 bits.
23 <   This code taken from
22 <   http://www.forceflow.be/2013/10/07/
23 <      morton-encodingdecoding-through-bit-interleaving-implementations/ */
21 >
22 > void OOC_Null (OOC_Octree *oct)
23 > /* Init empty octree */
24   {
25 <   /* Mask out lower 21 bits, the rest is cryptic */
26 <   OOC_Sort_Key i = k & 0x1fffff;  
27 <  
28 <   i = (i | i << 32) & 0x001f00000000ffff;
29 <   i = (i | i << 16) & 0x001f0000ff0000ff;  
30 <   i = (i | i << 8)  & 0x100f00f00f00f00f;
31 <   i = (i | i << 4)  & 0x10c30c30c30c30c3;
32 <   i = (i | i << 2)  & 0x1249249249249249;
33 <  
34 <   return i;
25 >   oct -> maxNodes = oct -> numNodes = oct -> leafMax = oct -> maxDepth =
26 >      oct -> numData = oct -> size = oct -> recSize = oct -> mortonScale = 0;
27 >   oct -> org [0] = oct -> org [1] = oct -> org [2] =
28 >      oct -> bound [0] = oct -> bound [1] = oct -> bound [2] = 0;
29 >   oct -> key = NULL;
30 >   oct -> nodes = NULL;
31 >   oct -> leafFile = NULL;
32 >   oct -> cache = NULL;
33   }
34  
35  
36 < static OOC_Sort_Key Key2zOrder (OOC_Octree *oct, FVECT key)
37 < /* Compute 63-bit Morton (Z-order) index for 3D key */
36 >
37 > void OOC_Init (OOC_Octree *oct, unsigned recSize, FVECT org, RREAL size,
38 >               RREAL *(*key)(const void*), FILE *leafFile)
39   {
40 <   int i;
41 <   OOC_Sort_Key k [3];
42 <      
43 <   /* Normalise key and map to 21-bit int */
44 <   for (i = 0; i < 3; i++)
45 <      k [i] = (((OOC_Sort_Key)1 << 21) - 1) / oct -> size *
46 <              (key [i] - oct -> org [i]);
47 <  
48 <   /* Interleave each dim with zeros and merge */
49 <   return zInterleave(k [0]) | zInterleave(k [1]) << 1 |
50 <          zInterleave(k [2]) << 2;
40 >   oct -> maxNodes = oct -> numNodes = oct -> leafMax =
41 >      oct -> maxDepth = oct -> numData = 0;
42 >   VCOPY(oct -> org, org);
43 >   oct -> size = oct -> bound[0] = oct -> bound[1] = oct -> bound[2] = size;
44 >   VADD(oct -> bound, oct -> bound, org);
45 >   oct -> mortonScale = size > 0 ? OOC_MORTON_MAX / size : 0;
46 >   oct -> recSize = recSize;
47 >   oct -> key = key;
48 >   oct -> nodes = NULL;
49 >   oct -> leafFile = leafFile;
50 >   oct -> cache = NULL;    /* Cache currently initialised externally */
51   }
52  
53 <      
54 < static OOC_Node *NewNode (OOC_Octree *oct)
53 >
54 >
55 > OOC_Node *NewNode (OOC_Octree *oct)
56   /* Allocate new octree node, enlarge array if necessary.
57     Return pointer to new node or NULL if failed. */
58   {
59     OOC_Node *n = NULL;
60 <  
60 >
61 >   if (oct -> numNodes >= OOC_NODEIDX_MAX) {
62 >      /* Node index overflow */
63 >      fprintf(stderr, "OOC_NewNode: node index overflow (numNodes = %d)\n",
64 >              oct -> numNodes);
65 >      return NULL;
66 >   }
67 >      
68     if (++oct -> numNodes > oct -> maxNodes) {
69        /* Need to allocate root or enlarge array */
70        oct -> maxNodes += OOC_BLKSIZE / sizeof(OOC_Node);
71 <      realloc(oct -> root, oct -> maxNodes * sizeof(OOC_Node));
72 <      if (!oct -> root)
71 >      oct -> nodes = realloc(oct -> nodes,
72 >                             oct -> maxNodes * sizeof(OOC_Node));
73 >      if (!oct -> nodes) {
74 >         perror("OOC_NewNode: couldn't realloc() nodes");
75           return NULL;
76 +      }
77     }
78    
79 <   n = oct -> root + oct -> numNodes - 1;
80 <   n -> num = n -> kid = 0;
79 >   n = oct -> nodes + oct -> numNodes - 1;
80 >   n -> node.num = n -> node.kid = n -> node.branch = n -> node.type = 0;
81 >  
82 >   return n;
83   }
72      
84  
85 < int OOC_Init (OOC_Octree *oct, unsigned recSize, unsigned leafMax,
86 <              unsigned maxDepth)
85 >
86 >
87 > int OOC_GetData (OOC_Octree *oct, OOC_DataIdx idx, void *rec)
88 > /* Reads indexed data record from leaf file and copies it to rec, else
89 > * returns -1 on failure */
90   {
91 <   ooc -> org [0] = oct -> org [1] = oct -> org [2] = FHUGE;
92 <   ooc -> size = oct -> maxNodes = oct -> lastNode = 0;
93 <   ooc -> recSize = recSize;
94 <   ooc -> leafMax = leafMax;
95 <   ooc -> maxDepth = maxDepth;
96 <   ooc -> root = NULL;
91 >   if (!oct || !rec)
92 >      return -1;
93 >  
94 >   if (idx >= oct -> numData) {
95 >      fprintf(stderr, "OOC_GetData: invalid data record index %u\n", idx);
96 >      return -1;
97 >   }  
98  
99 <   return NewNode(oct) ? 0 : -1;
99 >   if (oct -> cache) {
100 >      /* Retrieve record from leaf file via I/O cache */
101 >      void  *cachedRec;
102 >
103 >      if (!(cachedRec = OOC_CacheData(oct -> cache, oct -> leafFile, idx)))
104 >         return -1;
105 >            
106 >      /* It's safer to copy the record to the caller's local buffer as a
107 >       * returned pointer may be invalidated by subsequent calls if the
108 >       * page it points to is swapped out */
109 >      memcpy(rec, cachedRec, oct -> recSize);
110 >   }
111 >   else {
112 >      /* No I/O caching; do (SLOW!) per-record I/O from leaf file */
113 >      const unsigned long  pos = (unsigned long)oct -> recSize * idx;
114 >
115 >      if (pread(fileno(oct -> leafFile), rec, oct -> recSize, pos) !=
116 >          oct -> recSize) {
117 >         perror("OOC_GetData: failed seek/read in leaf file");
118 >         return -1;
119 >      }
120 >   }
121 >
122 >   return 0;
123   }
124  
125  
126 < int OOC_Branch (FVECT key, FVECT org, RREAL *size);
127 < /* Return index of kid containing key, update origin and size accordingly */
126 >
127 > int OOC_InBBox (const OOC_Octree *oct, const FVECT org, RREAL size,
128 >                const FVECT key)
129 > /* Check whether key lies within bounding box defined by org and size.
130 > * Compares Morton codes rather than the coordinates directly to account
131 > * for dicretisation error introduced by the former. */
132   {
133 <   size *= 0.5;
134 <   int kidIdx = 0;
133 >   const OOC_MortonIdx  keyZ = OOC_KEY2MORTON(key, oct);
134 >   FVECT                bbox = {size, size, size};
135    
136 <   for (int i = 0; i < 3; i++) {
137 <      RREAL cent = org [i] + size;
138 <      if (key [i] > cent) {
139 <         kidIdx |= 1 << i;
140 <         org [i] = cent;
136 >   VADD(bbox, org, bbox);
137 >   return keyZ > OOC_KEY2MORTON(org, oct) &&
138 >          keyZ < OOC_KEY2MORTON(bbox, oct);
139 > }
140 >
141 >
142 >
143 > int OOC_Branch (const OOC_Octree *oct, const FVECT org, RREAL size,
144 >                const FVECT key, FVECT nuOrg)
145 > /* Return index of octant containing key and corresponding origin if nuOrg
146 > * != NULL, or -1 if key lies outside all octants.  Size is already assumed
147 > * to be halved, i.e.  corresponding to the length of an octant axis.
148 > * Compares Morton codes rather than the coordinates directly to account
149 > * for dicretisation error introduced by the former. */
150 > {
151 >   int   o;
152 >   FVECT octOrg;
153 >  
154 >   for (o = 0; o < 8; o++) {
155 >      VCOPY(octOrg, org);
156 >      OOC_OCTORIGIN(octOrg, o, size);
157 >      
158 >      if (OOC_InBBox(oct, octOrg, size, key)) {
159 >         if (nuOrg)
160 >            VCOPY(nuOrg, octOrg);
161 >            
162 >         return o;
163        }
164     }
165    
166 <   return kidIdx;
166 >   return -1;  
167   }
168  
169  
170 < OOC_Idx OOC_Find (OOC_Octree *oct, FVECT key)
171 < /* Iterative search for given key */
170 >
171 > int OOC_BranchZ (const OOC_Octree *oct, const FVECT org, RREAL size,
172 >                 OOC_MortonIdx keyZ, FVECT nuOrg)
173 > /* Optimised version of OOC_Branch() with precomputed key Morton code */
174   {
175 <   FVECT    org;
176 <   RREAL    size;
177 <   OOC_Idx  dataIdx = 0;
112 <   OOC_Node *node = NULL;
175 >   int         o;
176 >   const FVECT cent = {size, size, size};
177 >   FVECT       octOrg, bbox;
178    
179 <   if (!oct || !oct -> root)
180 <      return -1;
179 >   for (o = 0; o < 8; o++) {
180 >      VCOPY(octOrg, org);
181 >      OOC_OCTORIGIN(octOrg, o, size);
182 >      VADD(bbox, octOrg, cent);
183 >      
184 >      if (keyZ > OOC_KEY2MORTON(octOrg, oct) &&
185 >          keyZ < OOC_KEY2MORTON(bbox, oct)) {
186 >         if (nuOrg)
187 >            VCOPY(nuOrg, octOrg);
188 >            
189 >         return o;
190 >      }
191 >   }
192    
193 <   node = oct -> root;
194 <   VCOPY(org, oct -> org);
195 <   size = oct -> size;
193 >   return -1;  
194 > }
195 >
196 >
197 >
198 > OOC_DataIdx OOC_GetKid (const OOC_Octree *oct, OOC_Node **node, unsigned kid)
199 > /* For a given octree node, return the sum of the data counters for kids
200 > * [0..k-1].  On return, the node either points to the k'th kid, or
201 > * NULL if the kid is nonexistent or the node is a leaf */                        
202 > {
203 >   unsigned       k;
204 >   OOC_Node       *kidNode = OOC_KID1(oct, *node); /* NULL if leaf */
205 >   OOC_DataIdx    dataIdx = 0;
206    
207 <   /* Quit at terminal/empty node or internal leaf */
208 <   while (OOC_INTNODE(*node)) {
209 <      /* Determine kid to branch into and update data index with skipped
210 <       * kids' data counts */
211 <      int kidIdx = OOC_Branch(key, org, size);
212 <      node = oct -> root + OOC_KID(*node);
213 <      while (kidIdx--)
214 <         dataIdx += OOC_NUMDATA(node++);
207 >   for (k = 0; k < kid; k++) {
208 >      if (OOC_ISLEAF(*node))
209 >         /* Sum data counters of leaf octants */
210 >         dataIdx += (*node) -> leaf.num [k];
211 >      else
212 >         /* Sum data counter of inner node's nonempty kids and advance
213 >          * pointer to sibling */
214 >         if (OOC_ISBRANCH(*node, k)) {
215 >            dataIdx += OOC_DATACNT(kidNode);
216 >            kidNode++;
217 >         }
218     }
219    
220 <   /* Reached empty node -> not found */
221 <   if (OOC_EMPTYNODE(*node))
220 >   /* Update node pointer to selected kid (or NULL if nonexistent or node is
221 >    * a leaf) */
222 >   *node = OOC_ISBRANCH(*node, kid) ? kidNode : NULL;
223 >   return dataIdx;
224 > }
225 >
226 >
227 >
228 > #ifdef DEBUG_OOC
229 > int OOC_Check (OOC_Octree *oct, const OOC_Node *node,
230 >               FVECT org, RREAL size, OOC_DataIdx dataIdx)
231 > /* Traverse tree & check for valid nodes; oct -> leafFile must be open;
232 > * return 0 if ok, otherwise -1 */
233 > {
234 >   unsigned    k;
235 >   FVECT       kidOrg;
236 >   const RREAL kidSize = size * 0.5;
237 >
238 >   if (!oct || !node)
239        return -1;
240 +      
241 +   if (OOC_ISLEAF(node)) {
242 +      /* Node is a leaf; check records in each octant */
243 +      char        rec [oct -> recSize];   /* Violates C89! */
244 +      OOC_OctCnt  d;
245 +      RREAL       *key;
246 +      
247 +      for (k = 0; k < 8; k++) {
248 +         VCOPY(kidOrg, org);
249 +         OOC_OCTORIGIN(kidOrg, k, kidSize);
250 +        
251 +         for (d = node -> leaf.num [k]; d; d--, dataIdx++) {
252 + #ifdef DEBUG_OOC_CHECK
253 +            fprintf(stderr, "OOC_Check: checking record %lu\n",
254 +                    (unsigned long)dataIdx);
255 + #endif            
256 +            if (OOC_GetData(oct, dataIdx, rec)) {
257 +               fprintf(stderr, "OOC_Check: failed getting record at %lu\n",
258 +                       (unsigned long)dataIdx);
259 +               return -1;
260 +            }
261 +            
262 +            key = oct -> key(rec);
263 +            if (!OOC_InBBox(oct, kidOrg, kidSize, key)) {
264 +               fprintf(stderr, "OOC_Check: key [%f, %f, %f] (zIdx %020lu) "
265 +                       "outside bbox [[%f-%f], [%f-%f], [%f-%f]] "
266 +                       "in octant %d (should be %d)\n",
267 +                       key [0], key [1], key [2],
268 +                       OOC_KEY2MORTON(key, oct),
269 +                       kidOrg [0], kidOrg [0] + kidSize,
270 +                       kidOrg [1], kidOrg [1] + kidSize,
271 +                       kidOrg [2], kidOrg [2] + kidSize,
272 +                       k, OOC_Branch(oct, org, kidSize, key, NULL));
273 +               /* return -1; */              
274 +            }
275 +         }
276 +      }
277 +   }
278 +   else {
279 +      /* Internal node; recurse on all kids */
280 +      const OOC_Node *kid = OOC_KID1(oct, node);
281 +      OOC_DataIdx    numData = 0;
282 +      
283 +      if (node -> node.kid >= oct -> numNodes) {
284 +         fprintf(stderr, "OOC_Check: invalid node index %u\n",
285 +                 node -> node.kid);
286 +         return -1;
287 +      }
288 +        
289 +      if (!node -> node.num) {
290 +         fputs("OOC_Check: empty octree node\n", stderr);
291 +         return -1;
292 +      }
293 +      
294 +      for (k = 0; k < 8; k++)
295 +         if (OOC_ISBRANCH(node, k)) {
296 +            VCOPY(kidOrg, org);
297 +            OOC_OCTORIGIN(kidOrg, k, kidSize);
298 +            
299 +            if (OOC_Check(oct, kid, kidOrg, kidSize, dataIdx))
300 +               return -1;
301 +            
302 +            dataIdx += OOC_DATACNT(kid);
303 +            numData += OOC_DATACNT(kid);
304 +            kid++;
305 +         }
306 +      
307 +      if (node -> node.num != numData) {
308 +         fprintf(stderr,
309 +                 "Parent/kid data count mismatch; expected %u, found %u\n",
310 +                 node -> node.num, numData);
311 +         return -1;
312 +      }
313 +   }
314    
315 <   /* Reached terminal node -> find leaf to branch into and update data
316 <    * index with skipped leaves' data counts */
317 <   if (OOC_TERMNODE(*node)) {
318 <      OOC_Leaf *leaf = ooc -> leaves [OOC_KID(*node)];
319 <      int leafIdx = OOC_Branch(key, org, size);
320 <      while (leafIdx--)
321 <         dataIdx += *leaf++;
315 >   return 0;
316 > }
317 > #endif
318 >        
319 >
320 >
321 > int OOC_SaveOctree (const OOC_Octree *oct, FILE *out)
322 > /* Appends octree nodes to specified file along with metadata. Uses
323 > * RADIANCE's portable I/O routines.  Returns 0 on success, else -1.  Note
324 > * the internal representation of the nodes is platform specific as they
325 > * contain unions, therefore we use the portable I/O routines from the
326 > * RADIANCE library */
327 > {
328 >   int         i;
329 >   OOC_NodeIdx nc;
330 >   OOC_Node    *np = NULL;
331 >  
332 >   if (!oct || !oct->nodes || !oct->numData || !oct->numNodes || !out) {
333 >      fputs("OOC_SaveOctree: empty octree\n", stderr);
334 >      return -1;
335     }
336 +      
337 +   /* Write octree origin, size, data record size, number of records, and
338 +    * number of nodes */
339 +   for (i = 0; i < 3; i++)
340 +      putflt(oct -> org [i], out);
341 +      
342 +   putflt(oct -> size, out);
343  
344 <   /* (Reached internal leaf -> already have data index) */
345 <   return dataIdx;
344 > #if 0  
345 >   for (i = 0; i < 3; i++)
346 >      putflt(oct -> bound [i], out);
347 >      
348 >   putint(oct -> mortonScale, sizeof(oct -> mortonScale),   out);
349 > #endif  
350 >   putint(oct -> recSize,     sizeof(oct -> recSize),       out);
351 >   putint(oct -> numData,     sizeof(oct -> numData),       out);
352 >   putint(oct -> numNodes,    sizeof(oct -> numNodes),      out);
353 >  
354 >   /* Write nodes to file */
355 >   for (nc = oct -> numNodes, np = oct -> nodes; nc; nc--, np++) {
356 >      if (OOC_ISLEAF(np)) {
357 >         /* Write leaf marker */
358 >         putint(-1, 1, out);
359 >        
360 >         /* Write leaf octant counters */
361 >         for (i = 0; i < 8; i++)
362 >            putint(np -> leaf.num [i], sizeof(np -> leaf.num [i]), out);
363 >      }
364 >      else {
365 >         /* Write node marker */
366 >         putint(0, 1, out);
367 >        
368 >         /* Write node, rounding field size up to nearest number of bytes */
369 >         putint(np -> node.kid,     (OOC_NODEIDX_BITS + 7) >> 3, out);
370 >         putint(np -> node.num,     (OOC_DATAIDX_BITS + 7) >> 3, out);
371 >         putint(np -> node.branch,  1,                           out);
372 >      }
373 >        
374 >      if (ferror(out)) {
375 >         fputs("OOC_SaveOctree: failed writing to node file", stderr);
376 >         return -1;
377 >      }
378 >   }
379 >  
380 >   fflush(out);
381 >   return 0;
382   }
383  
384  
385 < #if 0
386 < OOC_Node *FindNode (OOC_Octree *oct, FVECT key, OOC_Idx *dataIdx, int flags)
387 < /* ITERATIVE node search for given key */
385 >
386 > int OOC_LoadOctree (OOC_Octree *oct, FILE *nodeFile,
387 >                    RREAL *(*key)(const void*), FILE *leafFile)
388 > /* Load octree nodes and metadata from nodeFile and associate with records
389 > * in leafFile.  Uses RADIANCE's portable I/O routines.  Returns 0 on
390 > * success, else -1.  */
391   {
392 <   FVECT    org;
393 <   double   size;
394 <   OOC_Idx  dataIdx = 0;
156 <   OOC_Node *node = NULL;
392 >   int         i;
393 >   OOC_NodeIdx nc;
394 >   OOC_Node    *np = NULL;
395    
396 <   if (!oct || !oct -> root)
397 <      return NULL;
396 >   if (!oct || !nodeFile)
397 >      return -1;
398 >
399 >   OOC_Null(oct);
400    
401 <   node = oct -> root;
402 <   VCOPY(org, oct -> org);
403 <   size = oct -> size;
401 >   /* Read octree origin, size, record size, #records and #nodes */
402 >   for (i = 0; i < 3; i++)
403 >      oct -> org [i] = getflt(nodeFile);
404 >
405 >   oct -> size = getflt(nodeFile);
406    
407 <   /* Quit at terminal or empty node */
408 <   while (!OOC_TERM(*node) && !OOC_EMPTY(*node)) {
409 <      size *= 0.5;
168 <      int kidIdx = 0;
407 > #if 0  
408 >   for (i = 0; i < 3; i++)
409 >      oct -> bound [i] = getflt(nodeFile);
410        
411 <      /* Determine kid to branch into and update origin accordingly */
412 <      for (int i = 0; i < 3; i++) {
413 <         RREAL cent = org [i] + size;
414 <         if (key [i] > cent) {
415 <            kidIdx |= 1 << i;
416 <            org [i] = cent;
417 <         }
411 >   oct -> mortonScale   = getint(sizeof(oct -> mortonScale),   nodeFile);
412 > #else
413 >   oct -> bound [0] = oct -> bound [1] = oct -> bound [2] = oct -> size;
414 >   VADD(oct -> bound, oct -> bound, oct -> org);  
415 >  
416 >   oct -> mortonScale   = OOC_MORTON_MAX / oct -> size;
417 > #endif
418 >  
419 > #if 0
420 >   fprintf(stderr, "OOC_LoadOctree: mortonScale = %lf\n", oct -> mortonScale);
421 > #endif      
422 >
423 >   oct -> recSize       = getint(sizeof(oct -> recSize),       nodeFile);
424 >   oct -> numData       = getint(sizeof(oct -> numData),       nodeFile);
425 >   oct -> numNodes      = getint(sizeof(oct -> numNodes),      nodeFile);
426 >   oct -> key           = key;
427 >   oct -> leafFile      = leafFile;
428 >  
429 >   if (feof(nodeFile) || !oct -> numData || !oct -> numNodes) {
430 >      fputs("OOC_LoadOctree: empty octree\n", stderr);
431 >      return -1;
432 >   }
433 >  
434 >   /* Allocate octree nodes */
435 >   if (!(oct -> nodes = calloc(oct -> numNodes, sizeof(OOC_Node)))) {
436 >      fputs("OOC_LoadOctree: failed octree allocation\n", stderr);
437 >      return -1;
438 >   }
439 >
440 >   /* Read nodes from file */  
441 >   for (nc = oct -> numNodes, np = oct -> nodes; nc; nc--, np++) {
442 >      OOC_CLEARNODE(np);
443 >      
444 >      /* Read node type marker */
445 >      if (getint(1, nodeFile)) {
446 >         /* Read leaf octant counters and set node type */
447 >         for (i = 0; i < 8; i++)
448 >            np -> leaf.num [i] = getint(sizeof(np -> leaf.num [i]),
449 >                                        nodeFile);
450 >        
451 >         OOC_SETLEAF(np);
452        }
453 <      
454 <      /* Increment node's data counter if inserting */
455 <      if (flags & OOC_INSERT)
456 <         node -> numData++;
457 <          
458 <      /* Update data index with skipped kids' data counts */
459 <      node = oct -> root + node -> kid;
460 <      while (kidIdx--)
461 <         dataIdx += node++ -> numData;
453 >      else {
454 >         /* Read node, rounding field size up to nearest number of bytes */
455 >         np -> node.kid    = getint((OOC_NODEIDX_BITS + 7) >> 3,  nodeFile);
456 >         np -> node.num    = getint((OOC_DATAIDX_BITS + 7) >> 3,  nodeFile);
457 >         np -> node.branch = getint(1,                            nodeFile);
458 >      }
459 >        
460 >      if (ferror(nodeFile)) {
461 >         fputs("OOC_LoadOctree: failed reading from node file\n", stderr);
462 >         return -1;
463 >      }
464     }
465    
466 <   return node;
467 < }
466 >   return 0;
467 > }  
468  
469 <
470 < OOC_Idx FindLeaf (OOC_Leaf *leaf, FVECT key, OOC_Idx *dataIdx);
471 < /* Return index into data block for leaf containing key */
469 >
470 >
471 > void OOC_Delete (OOC_Octree *oct)
472 > /* Self-destruct */
473   {
474 <   int kidIdx = 0;
475 <   OOC_Idx =
474 >   free(oct -> nodes);
475 >   fclose(oct -> leafFile);
476    
477 <   for (int i = 0; i < 3; i++) {
478 <      if (key [i]
479 < #endif
477 >   if (oct -> cache)
478 >      OOC_DeleteCache(oct -> cache);
479 > }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines