ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapdata.c
Revision: 2.12
Committed: Tue Sep 1 16:27:52 2015 UTC (8 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +1 -2 lines
Log Message:
Removed redundant $Id: in file

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmapdata.c,v 2.11 2015/08/18 18:45:55 greg Exp $";
3 #endif
4 /*
5 ==================================================================
6 Photon map data structures and kd-tree handling
7
8 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
9 (c) Fraunhofer Institute for Solar Energy Systems,
10 (c) Lucerne University of Applied Sciences and Arts,
11 supported by the Swiss National Science Foundation (SNSF, #147053)
12 ==================================================================
13
14 */
15
16
17
18 #include "pmap.h"
19 #include "pmaprand.h"
20 #include "pmapmat.h"
21 #include "otypes.h"
22 #include "source.h"
23 #include "rcontrib.h"
24 #include "random.h"
25
26
27
28 PhotonMap *photonMaps [NUM_PMAP_TYPES] = {
29 NULL, NULL, NULL, NULL, NULL, NULL
30 };
31
32
33
34 void initPhotonMap (PhotonMap *pmap, PhotonMapType t)
35 /* Init photon map 'n' stuff... */
36 {
37 if (!pmap)
38 return;
39
40 pmap -> heapSize = pmap -> heapEnd = 0;
41 pmap -> heap = NULL;
42 pmap -> squeue = NULL;
43 pmap -> biasCompHist = NULL;
44 pmap -> maxPos [0] = pmap -> maxPos [1] = pmap -> maxPos [2] = -FHUGE;
45 pmap -> minPos [0] = pmap -> minPos [1] = pmap -> minPos [2] = FHUGE;
46 pmap -> minGathered = pmap -> maxGathered = pmap -> totalGathered = 0;
47 pmap -> gatherTolerance = gatherTolerance;
48 pmap -> minError = pmap -> maxError = pmap -> rmsError = 0;
49 pmap -> numDensity = 0;
50 pmap -> distribRatio = 1;
51 pmap -> type = t;
52
53 /* Init local RNG state */
54 pmap -> randState [0] = 10243;
55 pmap -> randState [1] = 39829;
56 pmap -> randState [2] = 9433;
57 /* pmapSeed(25999, pmap -> randState); */
58 pmapSeed(randSeed, pmap -> randState);
59
60 /* Set up type-specific photon lookup callback */
61 pmap -> lookup = pmapLookup [t];
62
63 pmap -> primary = NULL;
64 pmap -> primarySize = pmap -> primaryEnd = 0;
65 }
66
67
68
69 const PhotonPrimary* addPhotonPrimary (PhotonMap *pmap, const RAY *ray)
70 {
71 PhotonPrimary *prim = NULL;
72 FVECT dvec;
73
74 if (!pmap || !ray)
75 return NULL;
76
77 /* Check if last primary ray has spawned photons (srcIdx >= 0, see
78 * addPhoton()), in which case we keep it and allocate a new one;
79 * otherwise we overwrite the unused entry */
80 if (pmap -> primary && pmap -> primary [pmap -> primaryEnd].srcIdx >= 0)
81 pmap -> primaryEnd++;
82
83 if (!pmap -> primarySize || pmap -> primaryEnd >= pmap -> primarySize) {
84 /* Allocate/enlarge array */
85 pmap -> primarySize += pmap -> heapSizeInc;
86
87 /* Counter wraparound? */
88 if (pmap -> primarySize < pmap -> heapSizeInc)
89 error(INTERNAL, "photon primary overflow");
90
91 pmap -> primary = (PhotonPrimary *)realloc(pmap -> primary,
92 sizeof(PhotonPrimary) *
93 pmap -> primarySize);
94 if (!pmap -> primary)
95 error(USER, "can't allocate photon primaries");
96 }
97
98 prim = pmap -> primary + pmap -> primaryEnd;
99
100 /* Mark unused with negative source index until path spawns a photon (see
101 * addPhoton()) */
102 prim -> srcIdx = -1;
103
104 /* Reverse incident direction to point to light source */
105 dvec [0] = -ray -> rdir [0];
106 dvec [1] = -ray -> rdir [1];
107 dvec [2] = -ray -> rdir [2];
108 prim -> dir = encodedir(dvec);
109
110 VCOPY(prim -> pos, ray -> rop);
111
112 return prim;
113 }
114
115
116
117 const Photon* addPhoton (PhotonMap* pmap, const RAY* ray)
118 {
119 unsigned i;
120 Photon* photon = NULL;
121 COLOR photonFlux;
122
123 /* Account for distribution ratio */
124 if (!pmap || pmapRandom(pmap -> randState) > pmap -> distribRatio)
125 return NULL;
126
127 /* Don't store on sources */
128 if (ray -> robj > -1 && islight(objptr(ray -> ro -> omod) -> otype))
129 return NULL;
130
131 #if 0
132 if (inContribPmap(pmap)) {
133 /* Adding contribution photon */
134 if (ray -> parent && ray -> parent -> rtype & PRIMARY)
135 /* Add primary photon ray if parent is primary; by putting this
136 * here and checking the ray's immediate parent, we only add
137 * primaries that actually contribute photons, and we only add them
138 * once. */
139 addPhotonPrimary(pmap, ray -> parent);
140
141 /* Save index to primary ray (remains unchanged if primary already in
142 * array) */
143 primary = pmap -> primaryEnd;
144 }
145 #endif
146
147 #ifdef PMAP_ROI
148 /* Store photon if within region of interest -- for egg-spurtz only! */
149 if (ray -> rop [0] >= pmapROI [0] && ray -> rop [0] <= pmapROI [1] &&
150 ray -> rop [1] >= pmapROI [2] && ray -> rop [1] <= pmapROI [3] &&
151 ray -> rop [2] >= pmapROI [4] && ray -> rop [2] <= pmapROI [5])
152 #endif
153 {
154 if (pmap -> heapEnd >= pmap -> heapSize) {
155 /* Enlarge heap */
156 pmap -> heapSize += pmap -> heapSizeInc;
157
158 /* Counter wraparound? */
159 if (pmap -> heapSize < pmap -> heapSizeInc)
160 error(INTERNAL, "photon heap overflow");
161
162 pmap -> heap = (Photon *)realloc(pmap -> heap,
163 sizeof(Photon) * pmap -> heapSize);
164 if (!pmap -> heap)
165 error(USER, "can't allocate photon heap");
166 }
167
168 photon = pmap -> heap + pmap -> heapEnd++;
169
170 /* Adjust flux according to distribution ratio and ray weight */
171 copycolor(photonFlux, ray -> rcol);
172 scalecolor(photonFlux,
173 ray -> rweight / (pmap -> distribRatio ? pmap -> distribRatio
174 : 1));
175 setPhotonFlux(photon, photonFlux);
176
177 /* Set photon position and flags */
178 VCOPY(photon -> pos, ray -> rop);
179 photon -> flags = PMAP_CAUSTICRAY(ray) ? PMAP_CAUST_BIT : 0;
180
181 /* Set primary ray index and mark as used for contrib photons */
182 if (isContribPmap(pmap)) {
183 photon -> primary = pmap -> primaryEnd;
184 pmap -> primary [pmap -> primaryEnd].srcIdx = ray -> rsrc;
185 }
186 else photon -> primary = 0;
187
188 /* Update min and max positions & set normal */
189 for (i = 0; i <= 2; i++) {
190 if (photon -> pos [i] < pmap -> minPos [i])
191 pmap -> minPos [i] = photon -> pos [i];
192 if (photon -> pos [i] > pmap -> maxPos [i])
193 pmap -> maxPos [i] = photon -> pos [i];
194 photon -> norm [i] = 127.0 * (isVolumePmap(pmap) ? ray -> rdir [i]
195 : ray -> ron [i]);
196 }
197 }
198
199 return photon;
200 }
201
202
203
204 static void nearestNeighbours (PhotonMap* pmap, const float pos [3],
205 const float norm [3], unsigned long node)
206 /* Recursive part of findPhotons(..).
207 Note that all heap and priority queue index handling is 1-based, but
208 accesses to the arrays are 0-based! */
209 {
210 Photon* p = &pmap -> heap [node - 1];
211 unsigned i, j;
212 /* Signed distance to current photon's splitting plane */
213 float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
214 d2 = d * d;
215 PhotonSQNode* sq = pmap -> squeue;
216 const unsigned sqSize = pmap -> squeueSize;
217 float dv [3];
218
219 /* Search subtree closer to pos first; exclude other subtree if the
220 distance to the splitting plane is greater than maxDist */
221 if (d < 0) {
222 if (node << 1 <= pmap -> heapSize)
223 nearestNeighbours(pmap, pos, norm, node << 1);
224 if (d2 < pmap -> maxDist && node << 1 < pmap -> heapSize)
225 nearestNeighbours(pmap, pos, norm, (node << 1) + 1);
226 }
227 else {
228 if (node << 1 < pmap -> heapSize)
229 nearestNeighbours(pmap, pos, norm, (node << 1) + 1);
230 if (d2 < pmap -> maxDist && node << 1 <= pmap -> heapSize)
231 nearestNeighbours(pmap, pos, norm, node << 1);
232 }
233
234 /* Reject photon if normal faces away (ignored for volume photons) */
235 if (norm && DOT(norm, p -> norm) <= 0.5 * frandom())
236 return;
237
238 if (isContribPmap(pmap) && pmap -> srcContrib) {
239 /* Lookup in contribution photon map */
240 OBJREC *srcMod;
241 const int srcIdx = photonSrcIdx(pmap, p);
242
243 if (srcIdx < 0 || srcIdx >= nsources)
244 error(INTERNAL, "invalid light source index in photon map");
245
246 srcMod = findmaterial(source [srcIdx].so);
247
248 /* Reject photon if contributions from light source which emitted it
249 * are not sought */
250 if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data)
251 return;
252
253 /* Reject non-caustic photon if lookup for caustic contribs */
254 if (pmap -> lookupFlags & PMAP_CAUST_BIT & ~p -> flags)
255 return;
256 }
257
258 /* Squared distance to current photon */
259 dv [0] = pos [0] - p -> pos [0];
260 dv [1] = pos [1] - p -> pos [1];
261 dv [2] = pos [2] - p -> pos [2];
262 d2 = DOT(dv, dv);
263
264 /* Accept photon if closer than current max dist & add to priority queue */
265 if (d2 < pmap -> maxDist) {
266 if (pmap -> squeueEnd < sqSize) {
267 /* Priority queue not full; append photon and restore heap */
268 i = ++pmap -> squeueEnd;
269
270 while (i > 1 && sq [(i >> 1) - 1].dist <= d2) {
271 sq [i - 1].photon = sq [(i >> 1) - 1].photon;
272 sq [i - 1].dist = sq [(i >> 1) - 1].dist;
273 i >>= 1;
274 }
275
276 sq [--i].photon = p;
277 sq [i].dist = d2;
278 /* Update maxDist if we've just filled the queue */
279 if (pmap -> squeueEnd >= pmap -> squeueSize)
280 pmap -> maxDist = sq [0].dist;
281 }
282 else {
283 /* Priority queue full; replace maximum, restore heap, and
284 update maxDist */
285 i = 1;
286
287 while (i <= sqSize >> 1) {
288 j = i << 1;
289 if (j < sqSize && sq [j - 1].dist < sq [j].dist)
290 j++;
291 if (d2 >= sq [j - 1].dist)
292 break;
293 sq [i - 1].photon = sq [j - 1].photon;
294 sq [i - 1].dist = sq [j - 1].dist;
295 i = j;
296 }
297
298 sq [--i].photon = p;
299 sq [i].dist = d2;
300 pmap -> maxDist = sq [0].dist;
301 }
302 }
303 }
304
305
306
307 /* Dynamic max photon search radius increase and reduction factors */
308 #define PMAP_MAXDIST_INC 4
309 #define PMAP_MAXDIST_DEC 0.9
310
311 /* Num successful lookups before reducing in max search radius */
312 #define PMAP_MAXDIST_CNT 1000
313
314 /* Threshold below which we assume increasing max radius won't help */
315 #define PMAP_SHORT_LOOKUP_THRESH 1
316
317 /* Coefficient for adaptive maximum search radius */
318 #define PMAP_MAXDIST_COEFF 100
319
320
321 void findPhotons (PhotonMap* pmap, const RAY* ray)
322 {
323 float pos [3], norm [3];
324 int redo = 0;
325
326 if (!pmap -> squeue) {
327 /* Lazy init priority queue */
328 pmap -> squeueSize = pmap -> maxGather + 1;
329 pmap -> squeue = (PhotonSQNode*)malloc(pmap -> squeueSize *
330 sizeof(PhotonSQNode));
331 if (!pmap -> squeue)
332 error(USER, "can't allocate photon priority queue");
333
334 pmap -> minGathered = pmap -> maxGather;
335 pmap -> maxGathered = pmap -> minGather;
336 pmap -> totalGathered = 0;
337 pmap -> numLookups = pmap -> numShortLookups = 0;
338 pmap -> shortLookupPct = 0;
339 pmap -> minError = FHUGE;
340 pmap -> maxError = -FHUGE;
341 pmap -> rmsError = 0;
342 /* SQUARED max search radius limit is based on avg photon distance to
343 * centre of gravity, unless fixed by user (maxDistFix > 0) */
344 pmap -> maxDist0 = pmap -> maxDistLimit =
345 maxDistFix > 0 ? maxDistFix * maxDistFix
346 : PMAP_MAXDIST_COEFF * pmap -> squeueSize *
347 pmap -> CoGdist / pmap -> heapSize;
348 }
349
350 do {
351 pmap -> squeueEnd = 0;
352 pmap -> maxDist = pmap -> maxDist0;
353
354 /* Search position is ray -> rorg for volume photons, since we have no
355 intersection point. Normals are ignored -- these are incident
356 directions). */
357 if (isVolumePmap(pmap)) {
358 VCOPY(pos, ray -> rorg);
359 nearestNeighbours(pmap, pos, NULL, 1);
360 }
361 else {
362 VCOPY(pos, ray -> rop);
363 VCOPY(norm, ray -> ron);
364 nearestNeighbours(pmap, pos, norm, 1);
365 }
366
367 if (pmap -> maxDist < FTINY) {
368 sprintf(errmsg, "itsy bitsy teeny weeny photon search radius %e",
369 sqrt(pmap -> maxDist));
370 error(WARNING, errmsg);
371 }
372
373 if (pmap -> squeueEnd < pmap -> squeueSize * pmap -> gatherTolerance) {
374 /* Short lookup; too few photons found */
375 if (pmap -> squeueEnd > PMAP_SHORT_LOOKUP_THRESH) {
376 /* Ignore short lookups which return fewer than
377 * PMAP_SHORT_LOOKUP_THRESH photons under the assumption there
378 * really are no photons in the vicinity, and increasing the max
379 * search radius therefore won't help */
380 #ifdef PMAP_LOOKUP_WARN
381 sprintf(errmsg,
382 "%d/%d %s photons found at (%.2f,%.2f,%.2f) on %s",
383 pmap -> squeueEnd, pmap -> squeueSize,
384 pmapName [pmap -> type], pos [0], pos [1], pos [2],
385 ray -> ro ? ray -> ro -> oname : "<null>");
386 error(WARNING, errmsg);
387 #endif
388
389 /* Bail out after warning if maxDist is fixed */
390 if (maxDistFix > 0)
391 return;
392
393 if (pmap -> maxDist0 < pmap -> maxDistLimit) {
394 /* Increase max search radius if below limit & redo search */
395 pmap -> maxDist0 *= PMAP_MAXDIST_INC;
396 #ifdef PMAP_LOOKUP_REDO
397 redo = 1;
398 #endif
399 #ifdef PMAP_LOOKUP_WARN
400 sprintf(errmsg,
401 redo ? "restarting photon lookup with max radius %.1e"
402 : "max photon lookup radius adjusted to %.1e",
403 sqrt(pmap -> maxDist0));
404 error(WARNING, errmsg);
405 #endif
406 }
407 #ifdef PMAP_LOOKUP_REDO
408 else {
409 sprintf(errmsg, "max photon lookup radius clamped to %.1e",
410 sqrt(pmap -> maxDist0));
411 error(WARNING, errmsg);
412 }
413 #endif
414 }
415
416 /* Reset successful lookup counter */
417 pmap -> numLookups = 0;
418 }
419 else {
420 /* Bail out after warning if maxDist is fixed */
421 if (maxDistFix > 0)
422 return;
423
424 /* Increment successful lookup counter and reduce max search radius if
425 * wraparound */
426 pmap -> numLookups = (pmap -> numLookups + 1) % PMAP_MAXDIST_CNT;
427 if (!pmap -> numLookups)
428 pmap -> maxDist0 *= PMAP_MAXDIST_DEC;
429
430 redo = 0;
431 }
432
433 } while (redo);
434 }
435
436
437
438 static void nearest1Neighbour (PhotonMap *pmap, const float pos [3],
439 const float norm [3], Photon **photon,
440 unsigned long node)
441 /* Recursive part of find1Photon(..).
442 Note that all heap index handling is 1-based, but accesses to the
443 arrays are 0-based! */
444 {
445 Photon *p = pmap -> heap + node - 1;
446 /* Signed distance to current photon's splitting plane */
447 float d = pos [photonDiscr(*p)] - p -> pos [photonDiscr(*p)],
448 d2 = d * d;
449 float dv [3];
450
451 /* Search subtree closer to pos first; exclude other subtree if the
452 distance to the splitting plane is greater than maxDist */
453 if (d < 0) {
454 if (node << 1 <= pmap -> heapSize)
455 nearest1Neighbour(pmap, pos, norm, photon, node << 1);
456 if (d2 < pmap -> maxDist && node << 1 < pmap -> heapSize)
457 nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
458 }
459 else {
460 if (node << 1 < pmap -> heapSize)
461 nearest1Neighbour(pmap, pos, norm, photon, (node << 1) + 1);
462 if (d2 < pmap -> maxDist && node << 1 <= pmap -> heapSize)
463 nearest1Neighbour(pmap, pos, norm, photon, node << 1);
464 }
465
466 /* Squared distance to current photon */
467 dv [0] = pos [0] - p -> pos [0];
468 dv [1] = pos [1] - p -> pos [1];
469 dv [2] = pos [2] - p -> pos [2];
470 d2 = DOT(dv, dv);
471
472 if (d2 < pmap -> maxDist && DOT(norm, p -> norm) > 0.5 * frandom()) {
473 /* Closest photon so far with similar normal */
474 pmap -> maxDist = d2;
475 *photon = p;
476 }
477 }
478
479
480
481 Photon* find1Photon (PhotonMap *pmap, const RAY* ray)
482 {
483 float fpos [3], norm [3];
484 Photon* photon = NULL;
485
486 VCOPY(fpos, ray -> rop);
487 VCOPY(norm, ray -> ron);
488 pmap -> maxDist = thescene.cusize;
489 nearest1Neighbour(pmap, fpos, norm, &photon, 1);
490
491 return photon;
492 }
493
494
495
496 static unsigned long medianPartition (const Photon* heap,
497 unsigned long* heapIdx,
498 unsigned long* heapXdi,
499 unsigned long left,
500 unsigned long right, unsigned dim)
501 /* Returns index to median in heap from indices left to right
502 (inclusive) in dimension dim. The heap is partitioned relative to
503 median using a quicksort algorithm. The heap indices in heapIdx are
504 sorted rather than the heap itself. */
505 {
506 register const float* p;
507 const unsigned long n = right - left + 1;
508 register unsigned long l, r, lg2, n2, m;
509 register unsigned d;
510
511 /* Round down n to nearest power of 2 */
512 for (lg2 = 0, n2 = n; n2 > 1; n2 >>= 1, ++lg2);
513 n2 = 1 << lg2;
514
515 /* Determine median position; this takes into account the fact that
516 only the last level in the heap can be partially empty, and that
517 it fills from left to right */
518 m = left + ((n - n2) > (n2 >> 1) - 1 ? n2 - 1 : n - (n2 >> 1));
519
520 while (right > left) {
521 /* Pivot node */
522 p = heap [heapIdx [right]].pos;
523 l = left;
524 r = right - 1;
525
526 /* l & r converge, swapping elements out of order with respect to
527 pivot node. Identical keys are resolved by cycling through
528 dim. The convergence point is then the pivot's position. */
529 do {
530 while (l <= r) {
531 d = dim;
532
533 while (heap [heapIdx [l]].pos [d] == p [d]) {
534 d = (d + 1) % 3;
535
536 if (d == dim) {
537 /* Ignore dupes? */
538 error(WARNING, "duplicate keys in photon heap");
539 l++;
540 break;
541 }
542 }
543
544 if (heap [heapIdx [l]].pos [d] < p [d])
545 l++;
546 else break;
547 }
548
549 while (r > l) {
550 d = dim;
551
552 while (heap [heapIdx [r]].pos [d] == p [d]) {
553 d = (d + 1) % 3;
554
555 if (d == dim) {
556 /* Ignore dupes? */
557 error(WARNING, "duplicate keys in photon heap");
558 r--;
559 break;
560 }
561 }
562
563 if (heap [heapIdx [r]].pos [d] > p [d])
564 r--;
565 else break;
566 }
567
568 /* Swap indices (not the nodes they point to) */
569 n2 = heapIdx [l];
570 heapIdx [l] = heapIdx [r];
571 heapIdx [r] = n2;
572 /* Update reverse indices */
573 heapXdi [heapIdx [l]] = l;
574 heapXdi [n2] = r;
575 } while (l < r);
576
577 /* Swap indices of convergence and pivot nodes */
578 heapIdx [r] = heapIdx [l];
579 heapIdx [l] = heapIdx [right];
580 heapIdx [right] = n2;
581 /* Update reverse indices */
582 heapXdi [heapIdx [r]] = r;
583 heapXdi [heapIdx [l]] = l;
584 heapXdi [n2] = right;
585 if (l >= m) right = l - 1;
586 if (l <= m) left = l + 1;
587 }
588
589 /* Once left & right have converged at m, we have found the median */
590 return m;
591 }
592
593
594
595 void buildHeap (Photon* heap, unsigned long* heapIdx,
596 unsigned long* heapXdi, const float min [3],
597 const float max [3], unsigned long left,
598 unsigned long right, unsigned long root)
599 /* Recursive part of balancePhotons(..). Builds heap from subarray
600 defined by indices left and right. min and max are the minimum resp.
601 maximum photon positions in the array. root is the index of the
602 current subtree's root, which corresponds to the median's 1-based
603 index in the heap. heapIdx are the balanced heap indices. The heap
604 is accessed indirectly through these. heapXdi are the reverse indices
605 from the heap to heapIdx so that heapXdi [heapIdx [i]] = i. */
606 {
607 float maxLeft [3], minRight [3];
608 Photon rootNode;
609 unsigned d;
610
611 /* Choose median for dimension with largest spread and partition
612 accordingly */
613 const float d0 = max [0] - min [0],
614 d1 = max [1] - min [1],
615 d2 = max [2] - min [2];
616 const unsigned char dim = d0 > d1 ? d0 > d2 ? 0 : 2
617 : d1 > d2 ? 1 : 2;
618 const unsigned long median =
619 left == right ? left
620 : medianPartition(heap, heapIdx, heapXdi, left, right, dim);
621
622 /* Place median at root of current subtree. This consists of swapping
623 the median and the root nodes and updating the heap indices */
624 memcpy(&rootNode, heap + heapIdx [median], sizeof(Photon));
625 memcpy(heap + heapIdx [median], heap + root - 1, sizeof(Photon));
626 setPhotonDiscr(rootNode, dim);
627 memcpy(heap + root - 1, &rootNode, sizeof(Photon));
628 heapIdx [heapXdi [root - 1]] = heapIdx [median];
629 heapXdi [heapIdx [median]] = heapXdi [root - 1];
630 heapIdx [median] = root - 1;
631 heapXdi [root - 1] = median;
632
633 /* Update bounds for left and right subtrees and recurse on them */
634 for (d = 0; d <= 2; d++)
635 if (d == dim)
636 maxLeft [d] = minRight [d] = rootNode.pos [d];
637 else {
638 maxLeft [d] = max [d];
639 minRight [d] = min [d];
640 }
641
642 if (left < median)
643 buildHeap(heap, heapIdx, heapXdi, min, maxLeft,
644 left, median - 1, root << 1);
645
646 if (right > median)
647 buildHeap(heap, heapIdx, heapXdi, minRight, max,
648 median + 1, right, (root << 1) + 1);
649 }
650
651
652
653 void balancePhotons (PhotonMap* pmap, double *photonFlux)
654 {
655 Photon *heap = pmap -> heap;
656 unsigned long i;
657 unsigned long *heapIdx; /* Photon index array */
658 unsigned long *heapXdi; /* Reverse index to heapIdx */
659 unsigned j;
660 COLOR flux;
661 /* Need doubles here to reduce errors from increment */
662 double avgFlux [3] = {0, 0, 0}, CoG [3] = {0, 0, 0}, CoGdist = 0;
663 FVECT d;
664
665 if (pmap -> heapEnd) {
666 pmap -> heapSize = pmap -> heapEnd;
667 heapIdx = (unsigned long*)malloc(pmap -> heapSize *
668 sizeof(unsigned long));
669 heapXdi = (unsigned long*)malloc(pmap -> heapSize *
670 sizeof(unsigned long));
671 if (!heapIdx || !heapXdi)
672 error(USER, "can't allocate heap index");
673
674 for (i = 0; i < pmap -> heapSize; i++) {
675 /* Initialize index arrays */
676 heapXdi [i] = heapIdx [i] = i;
677 getPhotonFlux(heap + i, flux);
678
679 /* Scale photon's flux (hitherto normalised to 1 over RGB); in case
680 * of a contrib photon map, this is done per light source, and
681 * photonFlux is assumed to be an array */
682 if (photonFlux) {
683 scalecolor(flux, photonFlux [isContribPmap(pmap) ?
684 photonSrcIdx(pmap, heap + i) : 0]);
685 setPhotonFlux(heap + i, flux);
686 }
687
688 /* Need a double here */
689 addcolor(avgFlux, flux);
690
691 /* Add photon position to centre of gravity */
692 for (j = 0; j < 3; j++)
693 CoG [j] += heap [i].pos [j];
694 }
695
696 /* Average photon positions to get centre of gravity */
697 for (j = 0; j < 3; j++)
698 pmap -> CoG [j] = CoG [j] /= pmap -> heapSize;
699
700 /* Compute average photon distance to CoG */
701 for (i = 0; i < pmap -> heapSize; i++) {
702 VSUB(d, heap [i].pos, CoG);
703 CoGdist += DOT(d, d);
704 }
705
706 pmap -> CoGdist = CoGdist /= pmap -> heapSize;
707
708 /* Average photon flux based on RGBE representation */
709 scalecolor(avgFlux, 1.0 / pmap -> heapSize);
710 copycolor(pmap -> photonFlux, avgFlux);
711
712 /* Build kd-tree */
713 buildHeap(pmap -> heap, heapIdx, heapXdi, pmap -> minPos,
714 pmap -> maxPos, 0, pmap -> heapSize - 1, 1);
715
716 free(heapIdx);
717 free(heapXdi);
718 }
719 }
720
721
722
723 void deletePhotons (PhotonMap* pmap)
724 {
725 free(pmap -> heap);
726 free(pmap -> squeue);
727 free(pmap -> biasCompHist);
728
729 pmap -> heapSize = 0;
730 pmap -> minGather = pmap -> maxGather =
731 pmap -> squeueSize = pmap -> squeueEnd = 0;
732 }