ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapdata.c
Revision: 2.3
Committed: Fri May 8 13:20:23 2015 UTC (9 years ago) by rschregle
Content type: text/plain
Branch: MAIN
Changes since 2.2: +22 -13 lines
Log Message:
Double-counting bugfix for glow sources (thanks DGM!), revised copyright

File Contents

# User Rev Content
1 greg 2.1 /*
2     ==================================================================
3     Photon map data structures and kd-tree handling
4    
5     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
6     (c) Fraunhofer Institute for Solar Energy Systems,
7 rschregle 2.3 (c) Lucerne University of Applied Sciences and Arts,
8     supported by the Swiss National Science Foundation (SNSF, #147053)
9 greg 2.1 ==================================================================
10    
11 rschregle 2.3 $Id: pmapdata.c,v 4.32 2015/05/08 13:11:58 taschreg Exp taschreg $
12 greg 2.1 */
13    
14    
15    
16     #include "pmap.h"
17     #include "pmaprand.h"
18     #include "pmapmat.h"
19     #include "otypes.h"
20     #include "source.h"
21     #include "rcontrib.h"
22    
23    
24    
25     PhotonMap *photonMaps [NUM_PMAP_TYPES] = {
26     NULL, NULL, NULL, NULL, NULL, NULL
27     };
28    
29    
30    
31     void initPhotonMap (PhotonMap *pmap, PhotonMapType t)
32     /* Init photon map 'n' stuff... */
33     {
34     if (!pmap)
35     return;
36    
37     pmap -> heapSize = pmap -> heapEnd = 0;
38     pmap -> heap = NULL;
39     pmap -> squeue = NULL;
40     pmap -> biasCompHist = NULL;
41     pmap -> maxPos [0] = pmap -> maxPos [1] = pmap -> maxPos [2] = -FHUGE;
42     pmap -> minPos [0] = pmap -> minPos [1] = pmap -> minPos [2] = FHUGE;
43     pmap -> minGathered = pmap -> maxGathered = pmap -> totalGathered = 0;
44     pmap -> gatherTolerance = gatherTolerance;
45     pmap -> minError = pmap -> maxError = pmap -> rmsError = 0;
46     pmap -> numDensity = 0;
47     pmap -> distribRatio = 1;
48     pmap -> type = t;
49    
50     /* Init local RNG state */
51     pmap -> randState [0] = 10243;
52     pmap -> randState [1] = 39829;
53     pmap -> randState [2] = 9433;
54     /* pmapSeed(25999, pmap -> randState); */
55     pmapSeed(randSeed, pmap -> randState);
56    
57     /* Set up type-specific photon lookup callback */
58     pmap -> lookup = pmapLookup [t];
59    
60     pmap -> primary = NULL;
61     pmap -> primarySize = pmap -> primaryEnd = 0;
62     }
63    
64    
65    
66     const PhotonPrimary* addPhotonPrimary (PhotonMap *pmap, const RAY *ray)
67     {
68     PhotonPrimary *prim = NULL;
69    
70     if (!pmap || !ray)
71     return NULL;
72    
73     /* Check if last primary ray has spawned photons (srcIdx >= 0, see
74     * addPhoton()), in which case we keep it and allocate a new one;
75     * otherwise we overwrite the unused entry */
76     if (pmap -> primary && pmap -> primary [pmap -> primaryEnd].srcIdx >= 0)
77     pmap -> primaryEnd++;
78    
79     if (!pmap -> primarySize || pmap -> primaryEnd >= pmap -> primarySize) {
80     /* Allocate/enlarge array */
81     pmap -> primarySize += pmap -> heapSizeInc;
82    
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");
92     }
93    
94     prim = pmap -> primary + pmap -> primaryEnd;
95    
96     /* Mark unused with negative source index until path spawns a photon (see
97     * addPhoton()) */
98     prim -> srcIdx = -1;
99    
100     /* 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];
104    
105     VCOPY(prim -> org, ray -> rorg);
106    
107     return prim;
108     }
109    
110    
111    
112     const Photon* addPhoton (PhotonMap* pmap, const RAY* ray)
113     {
114     unsigned i;
115     Photon* photon = NULL;
116     COLOR photonFlux;
117    
118     /* Account for distribution ratio */
119     if (!pmap || pmapRandom(pmap -> randState) > pmap -> distribRatio)
120     return NULL;
121    
122     /* Don't store on sources */
123     if (ray -> robj > -1 && islight(objptr(ray -> ro -> omod) -> otype))
124     return NULL;
125    
126     #if 0
127     if (inContribPmap(pmap)) {
128     /* Adding contribution photon */
129     if (ray -> parent && ray -> parent -> rtype & PRIMARY)
130     /* Add primary photon ray if parent is primary; by putting this
131     * here and checking the ray's immediate parent, we only add
132     * primaries that actually contribute photons, and we only add them
133     * once. */
134     addPhotonPrimary(pmap, ray -> parent);
135    
136     /* Save index to primary ray (remains unchanged if primary already in
137     * array) */
138     primary = pmap -> primaryEnd;
139     }
140     #endif
141    
142     #ifdef PMAP_ROI
143     /* Store photon if within region of interest -- for egg-spurtz only! */
144     if (ray -> rop [0] >= pmapROI [0] && ray -> rop [0] <= pmapROI [1] &&
145     ray -> rop [1] >= pmapROI [2] && ray -> rop [1] <= pmapROI [3] &&
146     ray -> rop [2] >= pmapROI [4] && ray -> rop [2] <= pmapROI [5])
147     #endif
148     {
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     }
162    
163     photon = pmap -> heap + pmap -> heapEnd++;
164    
165     /* Adjust flux according to distribution ratio and ray weight */
166     copycolor(photonFlux, ray -> rcol);
167     scalecolor(photonFlux,
168     ray -> rweight / (pmap -> distribRatio ? pmap -> distribRatio
169     : 1));
170     setPhotonFlux(photon, photonFlux);
171    
172     /* Set photon position and flags */
173     VCOPY(photon -> pos, ray -> rop);
174     photon -> flags = PMAP_CAUSTICRAY(ray) ? PMAP_CAUST_BIT : 0;
175    
176     /* Set primary ray index and mark as used for contrib photons */
177     if (isContribPmap(pmap)) {
178     photon -> primary = pmap -> primaryEnd;
179     pmap -> primary [pmap -> primaryEnd].srcIdx = ray -> rsrc;
180     }
181     else photon -> primary = 0;
182    
183     /* Update min and max positions & set normal */
184     for (i = 0; i <= 2; i++) {
185     if (photon -> pos [i] < pmap -> minPos [i])
186     pmap -> minPos [i] = photon -> pos [i];
187     if (photon -> pos [i] > pmap -> maxPos [i])
188     pmap -> maxPos [i] = photon -> pos [i];
189     photon -> norm [i] = 127.0 * (isVolumePmap(pmap) ? ray -> rdir [i]
190     : ray -> ron [i]);
191     }
192     }
193    
194     return photon;
195     }
196    
197    
198    
199     static void nearestNeighbours (PhotonMap* pmap, const float pos [3],
200     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! */
204     {
205     Photon* p = &pmap -> heap [node - 1];
206     unsigned i, j;
207     /* Signed distance to current photon's splitting plane */
208     float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
209     d2 = d * d;
210     PhotonSQNode* sq = pmap -> squeue;
211     const unsigned sqSize = pmap -> squeueSize;
212     float dv [3];
213    
214     /* Search subtree closer to pos first; exclude other subtree if the
215     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;
232    
233     if (isContribPmap(pmap) && pmap -> srcContrib) {
234     /* Lookup in contribution photon map */
235     OBJREC *srcMod;
236     const int srcIdx = photonSrcIdx(pmap, p);
237    
238     if (srcIdx < 0 || srcIdx >= nsources)
239     error(INTERNAL, "invalid light source index in photon map");
240    
241     srcMod = objptr(source [srcIdx].so -> omod);
242    
243     /* Reject photon if contributions from light source which emitted it
244     * are not sought */
245     if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
246     return;
247    
248     /* Reject non-caustic photon if lookup for caustic contribs */
249     if (pmap -> lookupFlags & PMAP_CAUST_BIT & ~p -> flags)
250     return;
251     }
252    
253     /* Squared distance to current photon */
254     dv [0] = pos [0] - p -> pos [0];
255     dv [1] = pos [1] - p -> pos [1];
256     dv [2] = pos [2] - p -> pos [2];
257     d2 = DOT(dv, dv);
258    
259     /* Accept photon if closer than current max dist & add to priority queue */
260     if (d2 < pmap -> maxDist) {
261     if (pmap -> squeueEnd < sqSize) {
262     /* Priority queue not full; append photon and restore heap */
263     i = ++pmap -> squeueEnd;
264    
265     while (i > 1 && sq [(i >> 1) - 1].dist <= d2) {
266     sq [i - 1].photon = sq [(i >> 1) - 1].photon;
267     sq [i - 1].dist = sq [(i >> 1) - 1].dist;
268     i >>= 1;
269     }
270    
271     sq [--i].photon = p;
272     sq [i].dist = d2;
273     /* Update maxDist if we've just filled the queue */
274     if (pmap -> squeueEnd >= pmap -> squeueSize)
275     pmap -> maxDist = sq [0].dist;
276     }
277     else {
278     /* Priority queue full; replace maximum, restore heap, and
279     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;
291     }
292    
293     sq [--i].photon = p;
294     sq [i].dist = d2;
295     pmap -> maxDist = sq [0].dist;
296     }
297     }
298     }
299    
300    
301    
302     /* Dynamic max photon search radius increase and reduction factors */
303     #define PMAP_MAXDIST_INC 4
304     #define PMAP_MAXDIST_DEC 0.9
305    
306     /* Num successful lookups before reducing in max search radius */
307     #define PMAP_MAXDIST_CNT 1000
308    
309     /* Threshold below which we assume increasing max radius won't help */
310     #define PMAP_SHORT_LOOKUP_THRESH 1
311    
312     void findPhotons (PhotonMap* pmap, const RAY* ray)
313     {
314     float pos [3], norm [3];
315     int redo = 0;
316    
317     if (!pmap -> squeue) {
318     /* Lazy init priority queue */
319     pmap -> squeueSize = pmap -> maxGather + 1;
320     pmap -> squeue = (PhotonSQNode*)malloc(pmap -> squeueSize *
321     sizeof(PhotonSQNode));
322     if (!pmap -> squeue)
323     error(USER, "can't allocate photon priority queue");
324    
325     pmap -> minGathered = pmap -> maxGather;
326     pmap -> maxGathered = pmap -> minGather;
327     pmap -> totalGathered = 0;
328     pmap -> numLookups = pmap -> numShortLookups = 0;
329     pmap -> shortLookupPct = 0;
330     pmap -> minError = FHUGE;
331     pmap -> maxError = -FHUGE;
332     pmap -> rmsError = 0;
333 rschregle 2.3 #ifdef PMAP_MAXDIST_ABS
334     /* Treat maxDistCoeff as an *absolute* and *fixed* max search radius.
335     Primarily intended for debugging; FOR ZE ECKSPURTZ ONLY! */
336     pmap -> maxDist0 = pmap -> maxDistLimit = maxDistCoeff;
337     #else
338 greg 2.1 /* 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 rschregle 2.3 #endif
344 greg 2.1 }
345    
346     do {
347     pmap -> squeueEnd = 0;
348     pmap -> maxDist = pmap -> maxDist0;
349    
350     /* Search position is ray -> rorg for volume photons, since we have no
351     intersection point. Normals are ignored -- these are incident
352     directions). */
353     if (isVolumePmap(pmap)) {
354     VCOPY(pos, ray -> rorg);
355     nearestNeighbours(pmap, pos, NULL, 1);
356     }
357     else {
358     VCOPY(pos, ray -> rop);
359     VCOPY(norm, ray -> ron);
360     nearestNeighbours(pmap, pos, norm, 1);
361     }
362 rschregle 2.3
363     #ifndef PMAP_MAXDIST_ABS
364 greg 2.1 if (pmap -> squeueEnd < pmap -> squeueSize * pmap -> gatherTolerance) {
365     /* Short lookup; too few photons found */
366     if (pmap -> squeueEnd > PMAP_SHORT_LOOKUP_THRESH) {
367     /* Ignore short lookups which return fewer than
368     * PMAP_SHORT_LOOKUP_THRESH photons under the assumption there
369     * really are no photons in the vicinity, and increasing the max
370     * search radius therefore won't help */
371 rschregle 2.3 #ifdef PMAP_LOOKUP_WARN
372 greg 2.1 sprintf(errmsg,
373     "%d/%d %s photons found at (%.2f,%.2f,%.2f) on %s",
374     pmap -> squeueEnd, pmap -> squeueSize,
375     pmapName [pmap -> type], pos [0], pos [1], pos [2],
376     ray -> ro ? ray -> ro -> oname : "<null>");
377     error(WARNING, errmsg);
378 rschregle 2.3 #endif
379    
380 greg 2.1 if (pmap -> maxDist0 < pmap -> maxDistLimit) {
381     /* Increase max search radius if below limit & redo search */
382     pmap -> maxDist0 *= PMAP_MAXDIST_INC;
383 rschregle 2.3 #ifdef PMAP_LOOKUP_REDO
384 greg 2.1 redo = 1;
385 rschregle 2.3 #endif
386 greg 2.1
387 rschregle 2.3 #ifdef PMAP_LOOKUP_WARN
388 greg 2.1 sprintf(errmsg,
389     redo ? "restarting photon lookup with max radius %.1e"
390     : "max photon lookup radius adjusted to %.1e",
391     pmap -> maxDist0);
392     error(WARNING, errmsg);
393 rschregle 2.3 #endif
394 greg 2.1 }
395 rschregle 2.3 #ifdef PMAP_LOOKUP_REDO
396 greg 2.1 else {
397     sprintf(errmsg, "max photon lookup radius clamped to %.1e",
398     pmap -> maxDist0);
399     error(WARNING, errmsg);
400     }
401 rschregle 2.3 #endif
402 greg 2.1 }
403    
404     /* Reset successful lookup counter */
405     pmap -> numLookups = 0;
406 rschregle 2.3 }
407 greg 2.1 else {
408     /* Increment successful lookup counter and reduce max search radius if
409     * wraparound */
410     pmap -> numLookups = (pmap -> numLookups + 1) % PMAP_MAXDIST_CNT;
411     if (!pmap -> numLookups)
412     pmap -> maxDist0 *= PMAP_MAXDIST_DEC;
413    
414     redo = 0;
415     }
416 rschregle 2.3 #endif
417 greg 2.1 } while (redo);
418     }
419    
420    
421    
422     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! */
428     {
429     Photon *p = pmap -> heap + node - 1;
430     /* Signed distance to current photon's splitting plane */
431     float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
432     d2 = d * d;
433     float dv [3];
434    
435     /* Search subtree closer to pos first; exclude other subtree if the
436     distance to the splitting plane is greater than maxDist */
437     if (d < 0) {
438     if (node << 1 <= pmap -> heapSize)
439     nearest1Neighbour(pmap, pos, norm, photon, node << 1);
440     if (d2 < pmap -> maxDist && node << 1 < pmap -> heapSize)
441     nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
442     }
443     else {
444     if (node << 1 < pmap -> heapSize)
445     nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
446     if (d2 < pmap -> maxDist && node << 1 <= pmap -> heapSize)
447     nearest1Neighbour(pmap, pos, norm, photon, node << 1);
448     }
449    
450     /* Squared distance to current photon */
451     dv [0] = pos [0] - p -> pos [0];
452     dv [1] = pos [1] - p -> pos [1];
453     dv [2] = pos [2] - p -> pos [2];
454     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     }
462    
463    
464    
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;
476     }
477    
478    
479    
480     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. */
489     {
490     register const float* p;
491     const unsigned long n = right - left + 1;
492     register unsigned long l, r, lg2, n2, m;
493     register unsigned d;
494    
495     /* 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;
575     }
576    
577    
578    
579     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. */
590     {
591     float maxLeft [3], minRight [3];
592     Photon rootNode;
593     unsigned d;
594    
595     /* 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);
633     }
634    
635    
636    
637     void balancePhotons (PhotonMap* pmap, double *photonFlux)
638     {
639     Photon *heap = pmap -> heap;
640     unsigned long i;
641     unsigned long *heapIdx; /* Photon index array */
642     unsigned long *heapXdi; /* Reverse index to heapIdx */
643     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     }
703     }
704    
705    
706    
707     void deletePhotons (PhotonMap* pmap)
708     {
709     free(pmap -> heap);
710     free(pmap -> squeue);
711     free(pmap -> biasCompHist);
712    
713     pmap -> heapSize = 0;
714     pmap -> minGather = pmap -> maxGather =
715     pmap -> squeueSize = pmap -> squeueEnd = 0;
716     }