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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines