ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapdata.c
Revision: 2.5
Committed: Wed May 20 14:44:12 2015 UTC (8 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +6 -4 lines
Log Message:
Reduced primary photon struct size using encoded direction

File Contents

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