ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapdata.c
Revision: 2.22
Committed: Wed Apr 8 15:14:21 2020 UTC (4 years ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.21: +37 -8 lines
Log Message:
Fixed est00pid bug in single photon lookups that returned junk when none found, added code to detect and handle (ignore).

File Contents

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