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

Comparing ray/src/rt/pmapdata.c (file contents):
Revision 2.10 by rschregle, Wed Jul 29 18:54:20 2015 UTC vs.
Revision 2.22 by rschregle, Wed Apr 8 15:14:21 2020 UTC

# Line 1 | Line 1
1 + #ifndef lint
2 + static const char RCSid[] = "$Id$";
3 + #endif
4 +
5   /*
6 <   ==================================================================
7 <   Photon map data structures and kd-tree handling
6 >   =========================================================================
7 >   Photon map types and interface to nearest neighbour lookups in underlying
8 >   point cloud data structure.
9 >  
10 >   The default data structure is an in-core kd-tree (see pmapkdt.{h,c}).
11 >   This can be overriden with the PMAP_OOC compiletime switch, which enables
12 >   an out-of-core octree (see oococt.{h,c}).
13  
14     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
15     (c) Fraunhofer Institute for Solar Energy Systems,
16     (c) Lucerne University of Applied Sciences and Arts,
17 <   supported by the Swiss National Science Foundation (SNSF, #147053)
18 <   ==================================================================  
17 >       supported by the Swiss National Science Foundation (SNSF, #147053)
18 >   ==========================================================================
19    
20     $Id$
21   */
22  
23  
24  
25 < #include "pmap.h"
25 > #include "pmapdata.h"
26   #include "pmaprand.h"
27   #include "pmapmat.h"
28   #include "otypes.h"
# Line 29 | Line 38 | PhotonMap *photonMaps [NUM_PMAP_TYPES] = {
38  
39  
40  
41 + /* Include routines to handle underlying point cloud data structure */
42 + #ifdef PMAP_OOC
43 +   #include "pmapooc.c"
44 + #else
45 +   #include "pmapkdt.c"
46 + #endif
47 +
48 + /* Ambient include/exclude set (from ambient.c) */
49 + #ifndef  MAXASET
50 +   #define MAXASET  4095
51 + #endif
52 + extern OBJECT ambset [MAXASET+1];
53 +
54 + /* Callback to print photon attributes acc. to user defined format */
55 + int (*printPhoton)(RAY *r, Photon *p, PhotonMap *pm);
56 +
57 +
58 +
59   void initPhotonMap (PhotonMap *pmap, PhotonMapType t)
60   /* Init photon map 'n' stuff... */
61   {
62     if (!pmap)
63        return;
64        
65 <   pmap -> heapSize = pmap -> heapEnd = 0;
39 <   pmap -> heap = NULL;
40 <   pmap -> squeue = NULL;
65 >   pmap -> numPhotons = 0;
66     pmap -> biasCompHist = NULL;
67     pmap -> maxPos [0] = pmap -> maxPos [1] = pmap -> maxPos [2] = -FHUGE;
68     pmap -> minPos [0] = pmap -> minPos [1] = pmap -> minPos [2] = FHUGE;
# Line 47 | Line 72 | void initPhotonMap (PhotonMap *pmap, PhotonMapType t)
72     pmap -> numDensity = 0;
73     pmap -> distribRatio = 1;
74     pmap -> type = t;
75 +   pmap -> squeue.node = NULL;
76 +   pmap -> squeue.len = 0;  
77  
78     /* Init local RNG state */
79     pmap -> randState [0] = 10243;
80     pmap -> randState [1] = 39829;
81     pmap -> randState [2] = 9433;
55   /* pmapSeed(25999, pmap -> randState); */
82     pmapSeed(randSeed, pmap -> randState);
83    
84     /* Set up type-specific photon lookup callback */
85     pmap -> lookup = pmapLookup [t];
86  
87 <   pmap -> primary = NULL;
88 <   pmap -> primarySize = pmap -> primaryEnd = 0;
87 >   /* Mark primary photon ray as unused */
88 >   pmap -> lastPrimary.srcIdx = -1;
89 >   pmap -> numPrimary = 0;  
90 >   pmap -> primaries = NULL;
91 >  
92 >   /* Init storage */
93 >   pmap -> heap = NULL;
94 >   pmap -> heapBuf = NULL;
95 >   pmap -> heapBufLen = 0;
96 > #ifdef PMAP_OOC
97 >   OOC_Null(&pmap -> store);
98 > #else
99 >   kdT_Null(&pmap -> store);
100 > #endif
101   }
102  
103  
104  
105 < const PhotonPrimary* addPhotonPrimary (PhotonMap *pmap, const RAY *ray)
105 > void initPhotonHeap (PhotonMap *pmap)
106   {
107 <   PhotonPrimary *prim = NULL;
70 <   FVECT dvec;
107 >   int fdFlags;
108    
109 <   if (!pmap || !ray)
110 <      return NULL;
109 >   if (!pmap)
110 >      error(INTERNAL, "undefined photon map in initPhotonHeap");
111        
112 <   /* Check if last primary ray has spawned photons (srcIdx >= 0, see
113 <    * addPhoton()), in which case we keep it and allocate a new one;
114 <    * otherwise we overwrite the unused entry */
115 <   if (pmap -> primary && pmap -> primary [pmap -> primaryEnd].srcIdx >= 0)
116 <      pmap -> primaryEnd++;
117 <      
118 <   if (!pmap -> primarySize || pmap -> primaryEnd >= pmap -> primarySize) {
119 <      /* Allocate/enlarge array */
120 <      pmap -> primarySize += pmap -> heapSizeInc;
121 <      
85 <      /* Counter wraparound? */
86 <      if (pmap -> primarySize < pmap -> heapSizeInc)
87 <         error(INTERNAL, "photon primary overflow");
88 <        
89 <      pmap -> primary = (PhotonPrimary *)realloc(pmap -> primary,
90 <                                                 sizeof(PhotonPrimary) *
91 <                                                 pmap -> primarySize);
92 <      if (!pmap -> primary)
93 <         error(USER, "can't allocate photon primaries");
112 >   if (!pmap -> heap) {
113 >      /* Open heap file */
114 >      mktemp(strcpy(pmap -> heapFname, PMAP_TMPFNAME));
115 >      if (!(pmap -> heap = fopen(pmap -> heapFname, "w+b")))
116 >         error(SYSTEM, "failed opening heap file in initPhotonHeap");
117 >
118 > #ifdef F_SETFL  /* XXX is there an alternate needed for Windows? */
119 >      fdFlags = fcntl(fileno(pmap -> heap), F_GETFL);
120 >      fcntl(fileno(pmap -> heap), F_SETFL, fdFlags | O_APPEND);
121 > #endif/*      ftruncate(fileno(pmap -> heap), 0); */
122     }
123 + }
124 +
125 +
126 +
127 + void flushPhotonHeap (PhotonMap *pmap)
128 + {
129 +   int                  fd;
130 +   const unsigned long  len = pmap -> heapBufLen * sizeof(Photon);
131    
132 <   prim = pmap -> primary + pmap -> primaryEnd;
132 >   if (!pmap)
133 >      error(INTERNAL, "undefined photon map in flushPhotonHeap");
134 >
135 >   if (!pmap -> heap || !pmap -> heapBuf) {
136 >      /* Silently ignore undefined heap
137 >      error(INTERNAL, "undefined heap in flushPhotonHeap"); */
138 >      return;
139 >   }
140 >
141 >   /* Atomically seek and write block to heap */
142 >   /* !!! Unbuffered I/O via pwrite() avoids potential race conditions
143 >    * !!! and buffer corruption which can occur with lseek()/fseek()
144 >    * !!! followed by write()/fwrite(). */  
145 >   fd = fileno(pmap -> heap);
146    
147 <   /* Mark unused with negative source index until path spawns a photon (see
148 <    * addPhoton()) */
149 <   prim -> srcIdx = -1;
150 <      
151 <   /* Reverse incident direction to point to light source */
103 <   dvec [0] = -ray -> rdir [0];
104 <   dvec [1] = -ray -> rdir [1];
105 <   dvec [2] = -ray -> rdir [2];
106 <   prim -> dir = encodedir(dvec);
147 > #ifdef DEBUG_PMAP
148 >   sprintf(errmsg, "Proc %d: flushing %ld photons from pos %ld\n", getpid(),
149 >           pmap -> heapBufLen, lseek(fd, 0, SEEK_END) / sizeof(Photon));
150 >   eputs(errmsg);
151 > #endif
152  
153 <   VCOPY(prim -> pos, ray -> rop);
153 >   /*if (pwrite(fd, pmap -> heapBuf, len, lseek(fd, 0, SEEK_END)) != len) */
154 >   if (write(fd, pmap -> heapBuf, len) != len)
155 >      error(SYSTEM, "failed append to heap file in flushPhotonHeap");
156 >
157 > #if NIX
158 >   if (fsync(fd))
159 >      error(SYSTEM, "failed fsync in flushPhotonHeap");
160 > #endif
161 >
162 >   pmap -> heapBufLen = 0;
163 > }
164 >
165 >
166 >
167 > #ifdef DEBUG_PMAP
168 > static int checkPhotonHeap (FILE *file)
169 > /* Check heap for nonsensical or duplicate photons */
170 > {
171 >   Photon   p, lastp;
172 >   int      i, dup;
173    
174 <   return prim;
174 >   rewind(file);
175 >   memset(&lastp, 0, sizeof(lastp));
176 >  
177 >   while (fread(&p, sizeof(p), 1, file)) {
178 >      dup = 1;
179 >      
180 >      for (i = 0; i <= 2; i++) {
181 >         if (p.pos [i] < thescene.cuorg [i] ||
182 >             p.pos [i] > thescene.cuorg [i] + thescene.cusize) {
183 >            
184 >            sprintf(errmsg, "corrupt photon in heap at [%f, %f, %f]\n",
185 >                    p.pos [0], p.pos [1], p.pos [2]);
186 >            error(WARNING, errmsg);
187 >         }
188 >        
189 >         dup &= p.pos [i] == lastp.pos [i];
190 >      }
191 >      
192 >      if (dup) {
193 >         sprintf(errmsg,
194 >                 "consecutive duplicate photon in heap at [%f, %f, %f]\n",
195 >                 p.pos [0], p.pos [1], p.pos [2]);
196 >         error(WARNING, errmsg);
197 >      }
198 >   }
199 >
200 >   return 0;
201   }
202 + #endif
203  
204  
205  
206 < const Photon* addPhoton (PhotonMap* pmap, const RAY* ray)
206 > int newPhoton (PhotonMap* pmap, const RAY* ray)
207   {
208     unsigned i;
209 <   Photon* photon = NULL;
209 >   Photon photon;
210     COLOR photonFlux;
211    
212     /* Account for distribution ratio */
213     if (!pmap || pmapRandom(pmap -> randState) > pmap -> distribRatio)
214 <      return NULL;
214 >      return -1;
215        
216     /* Don't store on sources */
217     if (ray -> robj > -1 && islight(objptr(ray -> ro -> omod) -> otype))
218 <      return NULL;
218 >      return -1;
219  
220 < #if 0
221 <   if (inContribPmap(pmap)) {
222 <      /* Adding contribution photon */
223 <      if (ray -> parent && ray -> parent -> rtype & PRIMARY)
224 <         /* Add primary photon ray if parent is primary; by putting this
225 <          * here and checking the ray's immediate parent, we only add
226 <          * primaries that actually contribute photons, and we only add them
136 <          * once.  */
137 <         addPhotonPrimary(pmap, ray -> parent);
220 >   /* Ignore photon if modifier in/outside exclude/include set */
221 >   if (ambincl != -1 && ray -> ro &&
222 >       ambincl != inset(ambset, ray -> ro -> omod))
223 >      return -1;
224 >
225 >   if (pmapNumROI && pmapROI) {      
226 >      unsigned inROI = 0;
227        
228 <      /* Save index to primary ray (remains unchanged if primary already in
229 <       * array) */
230 <      primary = pmap -> primaryEnd;
228 >      /* Store photon if within a region of interest (for ze Ecksperts!) */
229 >      for (i = 0; !inROI && i < pmapNumROI; i++)
230 >         inROI = (ray -> rop [0] >= pmapROI [i].min [0] &&
231 >                  ray -> rop [0] <= pmapROI [i].max [0] &&
232 >                  ray -> rop [1] >= pmapROI [i].min [1] &&
233 >                  ray -> rop [1] <= pmapROI [i].max [1] &&
234 >                  ray -> rop [2] >= pmapROI [i].min [2] &&
235 >                  ray -> rop [2] <= pmapROI [i].max [2]);
236 >      if (!inROI)
237 >         return -1;
238     }
143 #endif
239    
240 < #ifdef PMAP_ROI
241 <   /* Store photon if within region of interest -- for egg-spurtz only! */
242 <   if (ray -> rop [0] >= pmapROI [0] && ray -> rop [0] <= pmapROI [1] &&
243 <       ray -> rop [1] >= pmapROI [2] && ray -> rop [1] <= pmapROI [3] &&
244 <       ray -> rop [2] >= pmapROI [4] && ray -> rop [2] <= pmapROI [5])
240 >   /* Adjust flux according to distribution ratio and ray weight */
241 >   copycolor(photonFlux, ray -> rcol);        
242 > #if 0
243 >   /* Factored out ray -> rweight as deprecated (?) for pmap, and infact
244 >      erroneously attenuates volume photon flux based on extinction,
245 >      which is already factored in by photonParticipate() */
246 >   scalecolor(photonFlux,
247 >              ray -> rweight / (pmap -> distribRatio ? pmap -> distribRatio
248 >                                                     : 1));
249 > #else
250 >   scalecolor(photonFlux,
251 >              1.0 / (pmap -> distribRatio ? pmap -> distribRatio : 1));
252   #endif
253 <   {      
152 <      if (pmap -> heapEnd >= pmap -> heapSize) {
153 <         /* Enlarge heap */
154 <         pmap -> heapSize += pmap -> heapSizeInc;
155 <        
156 <         /* Counter wraparound? */
157 <         if (pmap -> heapSize < pmap -> heapSizeInc)
158 <            error(INTERNAL, "photon heap overflow");
159 <        
160 <         pmap -> heap = (Photon *)realloc(pmap -> heap,
161 <                                          sizeof(Photon) * pmap -> heapSize);
162 <         if (!pmap -> heap)
163 <            error(USER, "can't allocate photon heap");
164 <      }
253 >   setPhotonFlux(&photon, photonFlux);
254  
255 <      photon = pmap -> heap + pmap -> heapEnd++;
255 >   /* Set photon position and flags */
256 >   VCOPY(photon.pos, ray -> rop);
257 >   photon.flags = 0;
258 >   photon.caustic = PMAP_CAUSTICRAY(ray);
259  
260 <      /* Adjust flux according to distribution ratio and ray weight */
261 <      copycolor(photonFlux, ray -> rcol);  
262 <      scalecolor(photonFlux,
263 <                 ray -> rweight / (pmap -> distribRatio ? pmap -> distribRatio
264 <                                                        : 1));
265 <      setPhotonFlux(photon, photonFlux);
266 <              
267 <      /* Set photon position and flags */
268 <      VCOPY(photon -> pos, ray -> rop);
269 <      photon -> flags = PMAP_CAUSTICRAY(ray) ? PMAP_CAUST_BIT : 0;
260 >   /* Set contrib photon's primary ray and subprocess index (the latter
261 >    * to linearise the primary ray indices after photon distribution is
262 >    * complete). Also set primary ray's source index, thereby marking it
263 >    * as used. */
264 >   if (isContribPmap(pmap)) {
265 >      photon.primary = pmap -> numPrimary;
266 >      photon.proc = PMAP_GETRAYPROC(ray);
267 >      pmap -> lastPrimary.srcIdx = ray -> rsrc;
268 >   }
269 >   else photon.primary = 0;
270 >  
271 >   /* Set normal */
272 >   for (i = 0; i <= 2; i++)
273 >      photon.norm [i] = 127.0 * (isVolumePmap(pmap) ? ray -> rdir [i]
274 >                                                    : ray -> ron [i]);
275  
276 <      /* Set primary ray index and mark as used for contrib photons */
277 <      if (isContribPmap(pmap)) {
278 <         photon -> primary = pmap -> primaryEnd;
279 <         pmap -> primary [pmap -> primaryEnd].srcIdx = ray -> rsrc;
280 <      }
281 <      else photon -> primary = 0;
282 <      
283 <      /* Update min and max positions & set normal */
284 <      for (i = 0; i <= 2; i++) {
285 <         if (photon -> pos [i] < pmap -> minPos [i])
286 <            pmap -> minPos [i] = photon -> pos [i];
287 <         if (photon -> pos [i] > pmap -> maxPos [i])
288 <            pmap -> maxPos [i] = photon -> pos [i];
289 <         photon -> norm [i] = 127.0 * (isVolumePmap(pmap) ? ray -> rdir [i]
290 <                                                          : ray -> ron [i]);
194 <      }
276 >   if (!pmap -> heapBuf) {
277 >      /* Lazily allocate heap buffa */
278 > #if NIX
279 >      /* Randomise buffa size to temporally decorellate flushes in
280 >       * multiprocessing mode */
281 >      srandom(randSeed + getpid());
282 >      pmap -> heapBufSize = PMAP_HEAPBUFSIZE * (0.5 + frandom());
283 > #else
284 >      /* Randomisation disabled for single processes on WIN; also useful
285 >       * for reproducability during debugging */        
286 >      pmap -> heapBufSize = PMAP_HEAPBUFSIZE;
287 > #endif        
288 >      if (!(pmap -> heapBuf = calloc(pmap -> heapBufSize, sizeof(Photon))))
289 >         error(SYSTEM, "failed heap buffer allocation in newPhoton");
290 >      pmap -> heapBufLen = 0;      
291     }
292 +
293 +   /* Photon initialised; now append to heap buffa */
294 +   memcpy(pmap -> heapBuf + pmap -> heapBufLen, &photon, sizeof(Photon));
295 +              
296 +   if (++pmap -> heapBufLen >= pmap -> heapBufSize)
297 +      /* Heap buffa full, flush to heap file */
298 +      flushPhotonHeap(pmap);
299 +
300 +   pmap -> numPhotons++;
301 +        
302 +   /* Print photon attributes */
303 +   if (printPhoton)
304 +      /* Non-const kludge */
305 +      printPhoton((RAY*)ray, &photon, pmap);
306              
307 <   return photon;
307 >   return 0;
308   }
309  
310  
311  
312 < static void nearestNeighbours (PhotonMap* pmap, const float pos [3],
313 <                               const float norm [3], unsigned long node)
204 < /* Recursive part of findPhotons(..).
205 <   Note that all heap and priority queue index handling is 1-based, but
206 <   accesses to the arrays are 0-based! */
312 > void buildPhotonMap (PhotonMap *pmap, double *photonFlux,
313 >                     PhotonPrimaryIdx *primaryOfs, unsigned nproc)
314   {
315 <   Photon* p = &pmap -> heap [node - 1];
316 <   unsigned i, j;
317 <   /* Signed distance to current photon's splitting plane */
318 <   float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
319 <         d2 = d * d;
320 <   PhotonSQNode* sq = pmap -> squeue;
321 <   const unsigned sqSize = pmap -> squeueSize;
322 <   float dv [3];
315 >   unsigned long  n, nCheck = 0;
316 >   unsigned       i;
317 >   Photon         *p;
318 >   COLOR          flux;
319 >   char           nuHeapFname [sizeof(PMAP_TMPFNAME)];
320 >   FILE           *nuHeap;
321 >   /* Need double here to reduce summation errors */
322 >   double         avgFlux [3] = {0, 0, 0}, CoG [3] = {0, 0, 0}, CoGdist = 0;
323 >   FVECT          d;
324    
325 <   /* Search subtree closer to pos first; exclude other subtree if the
326 <      distance to the splitting plane is greater than maxDist */
219 <   if (d < 0) {
220 <      if (node << 1 <= pmap -> heapSize)
221 <         nearestNeighbours(pmap, pos, norm, node << 1);
222 <      if (d2 < pmap -> maxDist && node << 1 < pmap -> heapSize)
223 <         nearestNeighbours(pmap, pos, norm, (node << 1) + 1);
224 <   }
225 <   else {
226 <      if (node << 1 < pmap -> heapSize)
227 <         nearestNeighbours(pmap, pos, norm, (node << 1) + 1);
228 <      if (d2 < pmap -> maxDist && node << 1 <= pmap -> heapSize)
229 <         nearestNeighbours(pmap, pos, norm, node << 1);
230 <   }
231 <
232 <   /* Reject photon if normal faces away (ignored for volume photons) */
233 <   if (norm && DOT(norm, p -> norm) <= 0.5 * frandom())
234 <      return;
325 >   if (!pmap)
326 >      error(INTERNAL, "undefined photon map in buildPhotonMap");
327        
328 <   if (isContribPmap(pmap) && pmap -> srcContrib) {
329 <      /* Lookup in contribution photon map */
330 <      OBJREC *srcMod;
331 <      const int srcIdx = photonSrcIdx(pmap, p);
332 <      
333 <      if (srcIdx < 0 || srcIdx >= nsources)
334 <         error(INTERNAL, "invalid light source index in photon map");
243 <      
244 <      srcMod = findmaterial(source [srcIdx].so);
328 >   /* Get number of photons from heapfile size */
329 >   if (fseek(pmap -> heap, 0, SEEK_END) < 0)
330 >      error(SYSTEM, "failed seek to end of photon heap in buildPhotonMap");
331 >   pmap -> numPhotons = ftell(pmap -> heap) / sizeof(Photon);
332 >  
333 >   if (!pmap -> numPhotons)
334 >      error(INTERNAL, "empty photon map in buildPhotonMap");  
335  
336 <      /* Reject photon if contributions from light source which emitted it
337 <       * are not sought */
248 <      if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
249 <         return;
336 >   if (!pmap -> heap)
337 >      error(INTERNAL, "no heap in buildPhotonMap");
338  
339 <      /* Reject non-caustic photon if lookup for caustic contribs */
340 <      if (pmap -> lookupFlags & PMAP_CAUST_BIT & ~p -> flags)
341 <         return;
339 > #ifdef DEBUG_PMAP
340 >   eputs("Checking photon heap consistency...\n");
341 >   checkPhotonHeap(pmap -> heap);
342 >  
343 >   sprintf(errmsg, "Heap contains %ld photons\n", pmap -> numPhotons);
344 >   eputs(errmsg);
345 > #endif
346 >
347 >   /* Allocate heap buffa */
348 >   if (!pmap -> heapBuf) {
349 >      pmap -> heapBufSize = PMAP_HEAPBUFSIZE;
350 >      pmap -> heapBuf = calloc(pmap -> heapBufSize, sizeof(Photon));
351 >      if (!pmap -> heapBuf)
352 >         error(SYSTEM, "failed to allocate postprocessed photon heap in"
353 >               "buildPhotonMap");
354     }
355 +
356 +   /* We REALLY don't need yet another @%&*! heap just to hold the scaled
357 +    * photons, but can't think of a quicker fix... */
358 +   mktemp(strcpy(nuHeapFname, PMAP_TMPFNAME));
359 +   if (!(nuHeap = fopen(nuHeapFname, "w+b")))
360 +      error(SYSTEM, "failed to open postprocessed photon heap in "
361 +            "buildPhotonMap");
362 +            
363 +   rewind(pmap -> heap);
364 +
365 + #ifdef DEBUG_PMAP
366 +   eputs("Postprocessing photons...\n");
367 + #endif
368    
369 <   /* Squared distance to current photon */
370 <   dv [0] = pos [0] - p -> pos [0];
371 <   dv [1] = pos [1] - p -> pos [1];
372 <   dv [2] = pos [2] - p -> pos [2];
373 <   d2 = DOT(dv, dv);
369 >   while (!feof(pmap -> heap)) {  
370 > #ifdef DEBUG_PMAP
371 >      printf("Reading %lu at %lu... ", pmap -> heapBufSize, ftell(pmap->heap));
372 > #endif      
373 >      pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon),
374 >                                 pmap -> heapBufSize, pmap -> heap);
375 > #ifdef DEBUG_PMAP                                
376 >      printf("Got %lu\n", pmap -> heapBufLen);
377 > #endif      
378  
379 <   /* Accept photon if closer than current max dist & add to priority queue */
380 <   if (d2 < pmap -> maxDist) {
381 <      if (pmap -> squeueEnd < sqSize) {
382 <         /* Priority queue not full; append photon and restore heap */
383 <         i = ++pmap -> squeueEnd;
379 >      if (ferror(pmap -> heap))
380 >         error(SYSTEM, "failed to read photon heap in buildPhotonMap");
381 >
382 >      for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) {
383 >         /* Update min and max pos and set photon flux */
384 >         for (i = 0; i <= 2; i++) {
385 >            if (p -> pos [i] < pmap -> minPos [i])
386 >               pmap -> minPos [i] = p -> pos [i];
387 >            else if (p -> pos [i] > pmap -> maxPos [i])
388 >               pmap -> maxPos [i] = p -> pos [i];  
389 >
390 >            /* Update centre of gravity with photon position */                
391 >            CoG [i] += p -> pos [i];                  
392 >         }  
393          
394 <         while (i > 1 && sq [(i >> 1) - 1].dist <= d2) {
395 <            sq [i - 1].photon = sq [(i >> 1) - 1].photon;
396 <            sq [i - 1].dist = sq [(i >> 1) - 1].dist;
397 <            i >>= 1;
272 <         }
394 >         if (primaryOfs)
395 >            /* Linearise photon primary index from subprocess index using the
396 >             * per-subprocess offsets in primaryOfs */
397 >            p -> primary += primaryOfs [p -> proc];
398          
399 <         sq [--i].photon = p;
400 <         sq [i].dist = d2;
401 <         /* Update maxDist if we've just filled the queue */
402 <         if (pmap -> squeueEnd >= pmap -> squeueSize)
403 <            pmap -> maxDist = sq [0].dist;
404 <      }
405 <      else {
406 <         /* Priority queue full; replace maximum, restore heap, and
407 <            update maxDist */
283 <         i = 1;
284 <        
285 <         while (i <= sqSize >> 1) {
286 <            j = i << 1;
287 <            if (j < sqSize && sq [j - 1].dist < sq [j].dist)
288 <               j++;
289 <            if (d2 >= sq [j - 1].dist)
290 <               break;
291 <            sq [i - 1].photon = sq [j - 1].photon;
292 <            sq [i - 1].dist = sq [j - 1].dist;
293 <            i = j;
399 >         /* Scale photon's flux (hitherto normalised to 1 over RGB); in
400 >          * case of a contrib photon map, this is done per light source,
401 >          * and photonFlux is assumed to be an array */
402 >         getPhotonFlux(p, flux);
403 >
404 >         if (photonFlux) {
405 >            scalecolor(flux, photonFlux [isContribPmap(pmap) ?
406 >                                            photonSrcIdx(pmap, p) : 0]);
407 >            setPhotonFlux(p, flux);
408           }
409 <        
410 <         sq [--i].photon = p;
411 <         sq [i].dist = d2;
298 <         pmap -> maxDist = sq [0].dist;
409 >
410 >         /* Update average photon flux; need a double here */
411 >         addcolor(avgFlux, flux);
412        }
413 +        
414 +      /* Write modified photons to new heap */
415 +      fwrite(pmap -> heapBuf, sizeof(Photon), pmap -> heapBufLen, nuHeap);
416 +                
417 +      if (ferror(nuHeap))
418 +         error(SYSTEM, "failed postprocessing photon flux in "
419 +               "buildPhotonMap");
420 +      
421 +      nCheck += pmap -> heapBufLen;
422     }
423 +
424 + #ifdef DEBUG_PMAP
425 +   if (nCheck < pmap -> numPhotons)
426 +      error(INTERNAL, "truncated photon heap in buildPhotonMap");
427 + #endif
428 +  
429 +   /* Finalise average photon flux */
430 +   scalecolor(avgFlux, 1.0 / pmap -> numPhotons);
431 +   copycolor(pmap -> photonFlux, avgFlux);
432 +
433 +   /* Average photon positions to get centre of gravity */
434 +   for (i = 0; i < 3; i++)
435 +      pmap -> CoG [i] = CoG [i] /= pmap -> numPhotons;
436 +      
437 +   rewind(pmap -> heap);
438 +  
439 +   /* Compute average photon distance to centre of gravity */
440 +   while (!feof(pmap -> heap)) {
441 +      pmap -> heapBufLen = fread(pmap -> heapBuf, sizeof(Photon),
442 +                                 pmap -> heapBufSize, pmap -> heap);
443 +      
444 +      for (n = pmap -> heapBufLen, p = pmap -> heapBuf; n; n--, p++) {
445 +         VSUB(d, p -> pos, CoG);
446 +         CoGdist += DOT(d, d);
447 +      }
448 +   }  
449 +
450 +   pmap -> CoGdist = CoGdist /= pmap -> numPhotons;
451 +
452 +   /* Swap heaps, discarding unscaled photons */
453 +   fclose(pmap -> heap);
454 +   unlink(pmap -> heapFname);
455 +   pmap -> heap = nuHeap;
456 +   strcpy(pmap -> heapFname, nuHeapFname);
457 +  
458 + #ifdef PMAP_OOC
459 +   OOC_BuildPhotonMap(pmap, nproc);
460 + #else
461 +   kdT_BuildPhotonMap(pmap);
462 + #endif
463 +
464 +   /* Trash heap and its buffa */
465 +   free(pmap -> heapBuf);
466 +   fclose(pmap -> heap);
467 +   unlink(pmap -> heapFname);
468 +   pmap -> heap = NULL;
469 +   pmap -> heapBuf = NULL;
470   }
471  
472  
# Line 315 | Line 484 | static void nearestNeighbours (PhotonMap* pmap, const
484   /* Coefficient for adaptive maximum search radius */
485   #define PMAP_MAXDIST_COEFF 100
486  
318
487   void findPhotons (PhotonMap* pmap, const RAY* ray)
488   {
321   float pos [3], norm [3];
489     int redo = 0;
490    
491 <   if (!pmap -> squeue) {
491 >   if (!pmap -> squeue.len) {
492        /* Lazy init priority queue */
493 <      pmap -> squeueSize = pmap -> maxGather + 1;
494 <      pmap -> squeue = (PhotonSQNode*)malloc(pmap -> squeueSize *
495 <                                             sizeof(PhotonSQNode));
496 <      if (!pmap -> squeue)
497 <         error(USER, "can't allocate photon priority queue");
331 <        
493 > #ifdef PMAP_OOC
494 >      OOC_InitFindPhotons(pmap);
495 > #else
496 >      kdT_InitFindPhotons(pmap);      
497 > #endif      
498        pmap -> minGathered = pmap -> maxGather;
499        pmap -> maxGathered = pmap -> minGather;
500        pmap -> totalGathered = 0;
# Line 339 | Line 505 | void findPhotons (PhotonMap* pmap, const RAY* ray)
505        pmap -> rmsError = 0;
506        /* SQUARED max search radius limit is based on avg photon distance to
507         * centre of gravity, unless fixed by user (maxDistFix > 0) */
508 <      pmap -> maxDist0 = pmap -> maxDistLimit =
508 >      pmap -> maxDist0 = pmap -> maxDist2Limit =
509           maxDistFix > 0 ? maxDistFix * maxDistFix
510 <                        : PMAP_MAXDIST_COEFF * pmap -> squeueSize *
511 <                          pmap -> CoGdist / pmap -> heapSize;
510 >                        : PMAP_MAXDIST_COEFF * pmap -> squeue.len *
511 >                          pmap -> CoGdist / pmap -> numPhotons;
512     }
513  
514     do {
515 <      pmap -> squeueEnd = 0;
516 <      pmap -> maxDist = pmap -> maxDist0;
515 >      pmap -> squeue.tail = 0;
516 >      pmap -> maxDist2 = pmap -> maxDist0;
517          
518        /* Search position is ray -> rorg for volume photons, since we have no
519           intersection point. Normals are ignored -- these are incident
520 <         directions). */  
520 >         directions). */
521 >      /* NOTE: status returned by XXX_FindPhotons() is currently ignored;
522 >         if no photons are found, an empty queue is returned under the
523 >         assumption all photons are too distant to contribute significant
524 >         flux. */
525        if (isVolumePmap(pmap)) {
526 <         VCOPY(pos, ray -> rorg);
527 <         nearestNeighbours(pmap, pos, NULL, 1);
526 > #ifdef PMAP_OOC
527 >         OOC_FindPhotons(pmap, ray -> rorg, NULL);
528 > #else
529 >         kdT_FindPhotons(pmap, ray -> rorg, NULL);
530 > #endif                  
531        }
532        else {
533 <         VCOPY(pos, ray -> rop);
534 <         VCOPY(norm, ray -> ron);
535 <         nearestNeighbours(pmap, pos, norm, 1);
533 > #ifdef PMAP_OOC
534 >         OOC_FindPhotons(pmap, ray -> rop, ray -> ron);        
535 > #else
536 >         kdT_FindPhotons(pmap, ray -> rop, ray -> ron);
537 > #endif
538        }
539  
540 <      if (pmap -> maxDist < FTINY) {
541 <         sprintf(errmsg, "itsy bitsy teeny weeny photon search radius %e",
542 <                 sqrt(pmap -> maxDist));
543 <         error(WARNING, errmsg);
544 <      }
545 <
546 <      if (pmap -> squeueEnd < pmap -> squeueSize * pmap -> gatherTolerance) {
540 > #ifdef PMAP_LOOKUP_INFO
541 >      fprintf(stderr, "%d/%d %s photons found within radius %.3f "
542 >              "at (%.2f,%.2f,%.2f) on %s\n", pmap -> squeue.tail,
543 >              pmap -> squeue.len, pmapName [pmap -> type], sqrt(pmap -> maxDist2),
544 >              ray -> rop [0], ray -> rop [1], ray -> rop [2],
545 >              ray -> ro ? ray -> ro -> oname : "<null>");
546 > #endif      
547 >            
548 >      if (pmap -> squeue.tail < pmap -> squeue.len * pmap -> gatherTolerance) {
549           /* Short lookup; too few photons found */
550 <         if (pmap -> squeueEnd > PMAP_SHORT_LOOKUP_THRESH) {
550 >         if (pmap -> squeue.tail > PMAP_SHORT_LOOKUP_THRESH) {
551              /* Ignore short lookups which return fewer than
552               * PMAP_SHORT_LOOKUP_THRESH photons under the assumption there
553               * really are no photons in the vicinity, and increasing the max
# Line 378 | Line 555 | void findPhotons (PhotonMap* pmap, const RAY* ray)
555   #ifdef PMAP_LOOKUP_WARN
556              sprintf(errmsg,
557                      "%d/%d %s photons found at (%.2f,%.2f,%.2f) on %s",
558 <                    pmap -> squeueEnd, pmap -> squeueSize,
559 <                    pmapName [pmap -> type], pos [0], pos [1], pos [2],
558 >                    pmap -> squeue.tail, pmap -> squeue.len,
559 >                    pmapName [pmap -> type],
560 >                    ray -> rop [0], ray -> rop [1], ray -> rop [2],
561                      ray -> ro ? ray -> ro -> oname : "<null>");
562              error(WARNING, errmsg);        
563   #endif            
# Line 388 | Line 566 | void findPhotons (PhotonMap* pmap, const RAY* ray)
566              if (maxDistFix > 0)
567                 return;
568              
569 <            if (pmap -> maxDist0 < pmap -> maxDistLimit) {
569 >            if (pmap -> maxDist0 < pmap -> maxDist2Limit) {
570                 /* Increase max search radius if below limit & redo search */
571                 pmap -> maxDist0 *= PMAP_MAXDIST_INC;
572   #ifdef PMAP_LOOKUP_REDO
# Line 398 | Line 576 | void findPhotons (PhotonMap* pmap, const RAY* ray)
576                 sprintf(errmsg,
577                         redo ? "restarting photon lookup with max radius %.1e"
578                              : "max photon lookup radius adjusted to %.1e",
579 <                       sqrt(pmap -> maxDist0));
579 >                       pmap -> maxDist0);
580                 error(WARNING, errmsg);
581   #endif
582              }
583   #ifdef PMAP_LOOKUP_REDO
584              else {
585                 sprintf(errmsg, "max photon lookup radius clamped to %.1e",
586 <                       sqrt(pmap -> maxDist0));
586 >                       pmap -> maxDist0);
587                 error(WARNING, errmsg);
588              }
589   #endif
# Line 433 | Line 611 | void findPhotons (PhotonMap* pmap, const RAY* ray)
611  
612  
613  
614 < static void nearest1Neighbour (PhotonMap *pmap, const float pos [3],
437 <                               const float norm [3], Photon **photon,
438 <                               unsigned long node)
439 < /* Recursive part of find1Photon(..).
440 <   Note that all heap index handling is 1-based, but accesses to the
441 <   arrays are 0-based! */
614 > Photon *find1Photon (PhotonMap *pmap, const RAY* ray, Photon *photon)
615   {
616 <   Photon *p = pmap -> heap + node - 1;
617 <   /* Signed distance to current photon's splitting plane */
618 <   float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
619 <         d2 = d * d;
620 <   float dv [3];
616 >   /* Init (squared) search radius to avg photon dist to centre of gravity */
617 >   float maxDist2_0 = pmap -> CoGdist;  
618 >   int found = 0;  
619 > #ifdef PMAP_LOOKUP_REDO
620 >   #define REDO 1
621 > #else
622 >   #define REDO 0
623 > #endif
624    
625 <   /* Search subtree closer to pos first; exclude other subtree if the
626 <      distance to the splitting plane is greater than maxDist */
627 <   if (d < 0) {
628 <      if (node << 1 <= pmap -> heapSize)
629 <         nearest1Neighbour(pmap, pos, norm, photon, node << 1);
630 <      if (d2 < pmap -> maxDist && node << 1 < pmap -> heapSize)
631 <         nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
632 <   }
633 <   else {
634 <      if (node << 1 < pmap -> heapSize)
635 <         nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
636 <      if (d2 < pmap -> maxDist && node << 1 <= pmap -> heapSize)
637 <         nearest1Neighbour(pmap, pos, norm, photon, node << 1);
638 <   }
639 <  
640 <   /* Squared distance to current photon */
641 <   dv [0] = pos [0] - p -> pos [0];
642 <   dv [1] = pos [1] - p -> pos [1];
643 <   dv [2] = pos [2] - p -> pos [2];
644 <   d2 = DOT(dv, dv);
469 <  
470 <   if (d2 < pmap -> maxDist && DOT(norm, p -> norm) > 0.5 * frandom()) {
471 <      /* Closest photon so far with similar normal */
472 <      pmap -> maxDist = d2;
473 <      *photon = p;
474 <   }
475 < }
625 >   do {
626 >      pmap -> maxDist2 = maxDist2_0;
627 > #ifdef PMAP_OOC
628 >      found = OOC_Find1Photon(pmap, ray -> rop, ray -> ron, photon);
629 > #else
630 >      found = kdT_Find1Photon(pmap, ray -> rop, ray -> ron, photon);
631 > #endif
632 >      if (found < 0) {
633 >         /* Expand search radius to retry */
634 >         maxDist2_0 *= 2;      
635 > #ifdef PMAP_LOOKUP_WARN
636 >         sprintf(errmsg, "failed 1-NN photon lookup"
637 > #ifdef PMAP_LOOKUP_REDO
638 >            ", retrying with search radius %.2f", maxDist2_0
639 > #endif
640 >         );
641 >         error(WARNING, errmsg);
642 > #endif
643 >      }
644 >   } while (REDO && found < 0);
645  
646 <
647 <
479 < Photon* find1Photon (PhotonMap *pmap, const RAY* ray)
480 < {
481 <   float fpos [3], norm [3];
482 <   Photon* photon = NULL;
483 <
484 <   VCOPY(fpos, ray -> rop);
485 <   VCOPY(norm, ray -> ron);
486 <   pmap -> maxDist = thescene.cusize;
487 <   nearest1Neighbour(pmap, fpos, norm, &photon, 1);
488 <  
489 <   return photon;
646 >   /* Return photon buffer containing valid photon, else NULL */
647 >   return found < 0 ? NULL : photon;
648   }
649  
650  
651  
652 < static unsigned long medianPartition (const Photon* heap,
495 <                                      unsigned long* heapIdx,
496 <                                      unsigned long* heapXdi,
497 <                                      unsigned long left,
498 <                                      unsigned long right, unsigned dim)
499 < /* Returns index to median in heap from indices left to right
500 <   (inclusive) in dimension dim. The heap is partitioned relative to
501 <   median using a quicksort algorithm. The heap indices in heapIdx are
502 <   sorted rather than the heap itself. */
652 > void getPhoton (PhotonMap *pmap, PhotonIdx idx, Photon *photon)
653   {
654 <   register const float* p;
655 <   const unsigned long n = right - left + 1;
656 <   register unsigned long l, r, lg2, n2, m;
657 <   register unsigned d;
658 <  
659 <   /* Round down n to nearest power of 2 */
510 <   for (lg2 = 0, n2 = n; n2 > 1; n2 >>= 1, ++lg2);
511 <   n2 = 1 << lg2;
512 <  
513 <   /* Determine median position; this takes into account the fact that
514 <      only the last level in the heap can be partially empty, and that
515 <      it fills from left to right */
516 <   m = left + ((n - n2) > (n2 >> 1) - 1 ? n2 - 1 : n - (n2 >> 1));
517 <  
518 <   while (right > left) {
519 <      /* Pivot node */
520 <      p = heap [heapIdx [right]].pos;
521 <      l = left;
522 <      r = right - 1;
523 <      
524 <      /* l & r converge, swapping elements out of order with respect to
525 <         pivot node. Identical keys are resolved by cycling through
526 <         dim. The convergence point is then the pivot's position. */
527 <      do {
528 <         while (l <= r) {
529 <            d = dim;
530 <            
531 <            while (heap [heapIdx [l]].pos [d] == p [d]) {
532 <               d = (d + 1) % 3;
533 <              
534 <               if (d == dim) {
535 <                  /* Ignore dupes? */
536 <                  error(WARNING, "duplicate keys in photon heap");
537 <                  l++;
538 <                  break;
539 <               }
540 <            }
541 <            
542 <            if (heap [heapIdx [l]].pos [d] < p [d])
543 <               l++;
544 <            else break;
545 <         }
546 <        
547 <         while (r > l) {
548 <            d = dim;
549 <            
550 <            while (heap [heapIdx [r]].pos [d] == p [d]) {
551 <               d = (d + 1) % 3;
552 <              
553 <               if (d == dim) {
554 <                  /* Ignore dupes? */
555 <                  error(WARNING, "duplicate keys in photon heap");
556 <                  r--;
557 <                  break;
558 <               }
559 <            }
560 <            
561 <            if (heap [heapIdx [r]].pos [d] > p [d])
562 <               r--;
563 <            else break;
564 <         }
565 <        
566 <         /* Swap indices (not the nodes they point to) */
567 <         n2 = heapIdx [l];
568 <         heapIdx [l] = heapIdx [r];
569 <         heapIdx [r] = n2;
570 <         /* Update reverse indices */
571 <         heapXdi [heapIdx [l]] = l;
572 <         heapXdi [n2] = r;
573 <      } while (l < r);
574 <      
575 <      /* Swap indices of convergence and pivot nodes */
576 <      heapIdx [r] = heapIdx [l];
577 <      heapIdx [l] = heapIdx [right];
578 <      heapIdx [right] = n2;
579 <      /* Update reverse indices */
580 <      heapXdi [heapIdx [r]] = r;
581 <      heapXdi [heapIdx [l]] = l;
582 <      heapXdi [n2] = right;
583 <      if (l >= m) right = l - 1;
584 <      if (l <= m) left = l + 1;
585 <   }
586 <  
587 <   /* Once left & right have converged at m, we have found the median */
588 <   return m;
654 > #ifdef PMAP_OOC
655 >   if (OOC_GetPhoton(pmap, idx, photon))      
656 > #else
657 >   if (kdT_GetPhoton(pmap, idx, photon))
658 > #endif
659 >      error(INTERNAL, "failed photon lookup");
660   }
661  
662  
663  
664 < void buildHeap (Photon* heap, unsigned long* heapIdx,
594 <                unsigned long* heapXdi, const float min [3],
595 <                const float max [3], unsigned long left,
596 <                unsigned long right, unsigned long root)
597 < /* Recursive part of balancePhotons(..). Builds heap from subarray
598 <   defined by indices left and right. min and max are the minimum resp.
599 <   maximum photon positions in the array. root is the index of the
600 <   current subtree's root, which corresponds to the median's 1-based
601 <   index in the heap. heapIdx are the balanced heap indices. The heap
602 <   is accessed indirectly through these. heapXdi are the reverse indices
603 <   from the heap to heapIdx so that heapXdi [heapIdx [i]] = i. */
664 > Photon *getNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
665   {
666 <   float maxLeft [3], minRight [3];
667 <   Photon rootNode;
668 <   unsigned d;
669 <  
670 <   /* Choose median for dimension with largest spread and partition
610 <      accordingly */
611 <   const float d0 = max [0] - min [0],
612 <               d1 = max [1] - min [1],
613 <               d2 = max [2] - min [2];
614 <   const unsigned char dim = d0 > d1 ? d0 > d2 ? 0 : 2
615 <                                     : d1 > d2 ? 1 : 2;
616 <   const unsigned long median =
617 <      left == right ? left
618 <                    : medianPartition(heap, heapIdx, heapXdi, left, right, dim);
619 <  
620 <   /* Place median at root of current subtree. This consists of swapping
621 <      the median and the root nodes and updating the heap indices */
622 <   memcpy(&rootNode, heap + heapIdx [median], sizeof(Photon));
623 <   memcpy(heap + heapIdx [median], heap + root - 1, sizeof(Photon));
624 <   setPhotonDiscr(rootNode, dim);
625 <   memcpy(heap + root - 1, &rootNode, sizeof(Photon));
626 <   heapIdx [heapXdi [root - 1]] = heapIdx [median];
627 <   heapXdi [heapIdx [median]] = heapXdi [root - 1];
628 <   heapIdx [median] = root - 1;
629 <   heapXdi [root - 1] = median;
630 <  
631 <   /* Update bounds for left and right subtrees and recurse on them */
632 <   for (d = 0; d <= 2; d++)
633 <      if (d == dim)
634 <         maxLeft [d] = minRight [d] = rootNode.pos [d];
635 <      else {
636 <         maxLeft [d] = max [d];
637 <         minRight [d] = min [d];
638 <      }
639 <      
640 <   if (left < median)
641 <      buildHeap(heap, heapIdx, heapXdi, min, maxLeft,
642 <                left, median - 1, root << 1);
643 <                
644 <   if (right > median)
645 <      buildHeap(heap, heapIdx, heapXdi, minRight, max,
646 <                median + 1, right, (root << 1) + 1);
666 > #ifdef PMAP_OOC
667 >   return OOC_GetNearestPhoton(squeue, idx);
668 > #else
669 >   return kdT_GetNearestPhoton(squeue, idx);
670 > #endif
671   }
672  
673  
674  
675 < void balancePhotons (PhotonMap* pmap, double *photonFlux)
675 > PhotonIdx firstPhoton (const PhotonMap *pmap)
676   {
677 <   Photon *heap = pmap -> heap;
678 <   unsigned long i;
679 <   unsigned long *heapIdx;        /* Photon index array */
680 <   unsigned long *heapXdi;        /* Reverse index to heapIdx */
681 <   unsigned j;
658 <   COLOR flux;
659 <   /* Need doubles here to reduce errors from increment */
660 <   double avgFlux [3] = {0, 0, 0}, CoG [3] = {0, 0, 0}, CoGdist = 0;
661 <   FVECT d;
662 <  
663 <   if (pmap -> heapEnd) {
664 <      pmap -> heapSize = pmap -> heapEnd;
665 <      heapIdx = (unsigned long*)malloc(pmap -> heapSize *
666 <                                       sizeof(unsigned long));
667 <      heapXdi = (unsigned long*)malloc(pmap -> heapSize *
668 <                                       sizeof(unsigned long));
669 <      if (!heapIdx || !heapXdi)
670 <         error(USER, "can't allocate heap index");
671 <        
672 <      for (i = 0; i < pmap -> heapSize; i++) {
673 <         /* Initialize index arrays */
674 <         heapXdi [i] = heapIdx [i] = i;
675 <         getPhotonFlux(heap + i, flux);
676 <
677 <         /* Scale photon's flux (hitherto normalised to 1 over RGB); in case
678 <          * of a contrib photon map, this is done per light source, and
679 <          * photonFlux is assumed to be an array */
680 <         if (photonFlux) {
681 <            scalecolor(flux, photonFlux [isContribPmap(pmap) ?
682 <                                         photonSrcIdx(pmap, heap + i) : 0]);
683 <            setPhotonFlux(heap + i, flux);
684 <         }
685 <
686 <         /* Need a double here */
687 <         addcolor(avgFlux, flux);
688 <        
689 <         /* Add photon position to centre of gravity */
690 <         for (j = 0; j < 3; j++)
691 <            CoG [j] += heap [i].pos [j];
692 <      }
693 <      
694 <      /* Average photon positions to get centre of gravity */
695 <      for (j = 0; j < 3; j++)
696 <         pmap -> CoG [j] = CoG [j] /= pmap -> heapSize;
697 <      
698 <      /* Compute average photon distance to CoG */
699 <      for (i = 0; i < pmap -> heapSize; i++) {
700 <         VSUB(d, heap [i].pos, CoG);
701 <         CoGdist += DOT(d, d);
702 <      }
703 <      
704 <      pmap -> CoGdist = CoGdist /= pmap -> heapSize;
705 <      
706 <      /* Average photon flux based on RGBE representation */
707 <      scalecolor(avgFlux, 1.0 / pmap -> heapSize);
708 <      copycolor(pmap -> photonFlux, avgFlux);
709 <      
710 <      /* Build kd-tree */
711 <      buildHeap(pmap -> heap, heapIdx, heapXdi, pmap -> minPos,
712 <                pmap -> maxPos, 0, pmap -> heapSize - 1, 1);
713 <                
714 <      free(heapIdx);
715 <      free(heapXdi);
716 <   }
677 > #ifdef PMAP_OOC
678 >   return OOC_FirstPhoton(pmap);
679 > #else
680 >   return kdT_FirstPhoton(pmap);
681 > #endif
682   }
683  
684  
685  
686   void deletePhotons (PhotonMap* pmap)
687   {
688 <   free(pmap -> heap);
689 <   free(pmap -> squeue);
688 > #ifdef PMAP_OOC
689 >   OOC_Delete(&pmap -> store);
690 > #else
691 >   kdT_Delete(&pmap -> store);
692 > #endif
693 >
694 >   free(pmap -> squeue.node);
695     free(pmap -> biasCompHist);
696    
697 <   pmap -> heapSize = 0;
698 <   pmap -> minGather = pmap -> maxGather =
729 <      pmap -> squeueSize = pmap -> squeueEnd = 0;
697 >   pmap -> numPhotons = pmap -> minGather = pmap -> maxGather =
698 >      pmap -> squeue.len = pmap -> squeue.tail = 0;
699   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines