ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmap.c
Revision: 2.12
Committed: Mon Sep 26 20:19:30 2016 UTC (7 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +2 -230 lines
Log Message:
Pulled pmap routines needed during rendering from pmap.c into pmutil.c

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $";
3 #endif
4
5 /*
6 ======================================================================
7 Photon map main module
8
9 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
10 (c) Fraunhofer Institute for Solar Energy Systems,
11 (c) Lucerne University of Applied Sciences and Arts,
12 supported by the Swiss National Science Foundation (SNSF, #147053)
13 ======================================================================
14
15 $Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $
16 */
17
18
19
20 #include "pmap.h"
21 #include "pmapmat.h"
22 #include "pmapsrc.h"
23 #include "pmaprand.h"
24 #include "pmapio.h"
25 #include "pmapbias.h"
26 #include "pmapdiag.h"
27 #include "otypes.h"
28 #include <time.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <sys/wait.h>
32
33
34
35 void savePmaps (const PhotonMap **pmaps, int argc, char **argv)
36 {
37 unsigned t;
38
39 for (t = 0; t < NUM_PMAP_TYPES; t++) {
40 if (pmaps [t])
41 savePhotonMap(pmaps [t], pmaps [t] -> fileName, argc, argv);
42 }
43 }
44
45
46
47 static int photonParticipate (RAY *ray)
48 /* Trace photon through participating medium. Returns 1 if passed through,
49 or 0 if absorbed and $*%&ed. Analogon to rayparticipate(). */
50 {
51 int i;
52 RREAL cosTheta, cosPhi, du, dv;
53 const float cext = colorAvg(ray -> cext),
54 albedo = colorAvg(ray -> albedo);
55 FVECT u, v;
56 COLOR cvext;
57
58 /* Mean free distance until interaction with medium */
59 ray -> rmax = -log(pmapRandom(mediumState)) / cext;
60
61 while (!localhit(ray, &thescene)) {
62 setcolor(cvext, exp(-ray -> rmax * ray -> cext [0]),
63 exp(-ray -> rmax * ray -> cext [1]),
64 exp(-ray -> rmax * ray -> cext [2]));
65
66 /* Modify ray color and normalise */
67 multcolor(ray -> rcol, cvext);
68 colorNorm(ray -> rcol);
69 VCOPY(ray -> rorg, ray -> rop);
70
71 if (albedo > FTINY && ray -> rlvl > 0)
72 /* Add to volume photon map */
73 newPhoton(volumePmap, ray);
74
75 /* Absorbed? */
76 if (pmapRandom(rouletteState) > albedo)
77 return 0;
78
79 /* Colour bleeding without attenuation (?) */
80 multcolor(ray -> rcol, ray -> albedo);
81 scalecolor(ray -> rcol, 1 / albedo);
82
83 /* Scatter photon */
84 cosTheta = ray -> gecc <= FTINY ? 2 * pmapRandom(scatterState) - 1
85 : 1 / (2 * ray -> gecc) *
86 (1 + ray -> gecc * ray -> gecc -
87 (1 - ray -> gecc * ray -> gecc) /
88 (1 - ray -> gecc + 2 * ray -> gecc *
89 pmapRandom(scatterState)));
90
91 cosPhi = cos(2 * PI * pmapRandom(scatterState));
92 du = dv = sqrt(1 - cosTheta * cosTheta); /* sin(theta) */
93 du *= cosPhi;
94 dv *= sqrt(1 - cosPhi * cosPhi); /* sin(phi) */
95
96 /* Get axes u & v perpendicular to photon direction */
97 i = 0;
98 do {
99 v [0] = v [1] = v [2] = 0;
100 v [i++] = 1;
101 fcross(u, v, ray -> rdir);
102 } while (normalize(u) < FTINY);
103 fcross(v, ray -> rdir, u);
104
105 for (i = 0; i < 3; i++)
106 ray -> rdir [i] = du * u [i] + dv * v [i] +
107 cosTheta * ray -> rdir [i];
108 ray -> rlvl++;
109 ray -> rmax = -log(pmapRandom(mediumState)) / cext;
110 }
111
112 setcolor(cvext, exp(-ray -> rot * ray -> cext [0]),
113 exp(-ray -> rot * ray -> cext [1]),
114 exp(-ray -> rot * ray -> cext [2]));
115
116 /* Modify ray color and normalise */
117 multcolor(ray -> rcol, cvext);
118 colorNorm(ray -> rcol);
119
120 /* Passed through medium */
121 return 1;
122 }
123
124
125
126 void tracePhoton (RAY *ray)
127 /* Follow photon as it bounces around... */
128 {
129 long mod;
130 OBJREC* mat;
131
132 if (ray -> rlvl > photonMaxBounce) {
133 #ifdef PMAP_RUNAWAY_WARN
134 error(WARNING, "runaway photon!");
135 #endif
136 return;
137 }
138
139 if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray))
140 return;
141
142 if (localhit(ray, &thescene)) {
143 mod = ray -> ro -> omod;
144
145 if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) {
146 /* Transfer ray if modifier is VOID or clipped within antimatta */
147 RAY tray;
148 photonRay(ray, &tray, PMAP_XFER, NULL);
149 tracePhoton(&tray);
150 }
151 else {
152 /* Scatter for modifier material */
153 mat = objptr(mod);
154 photonScatter [mat -> otype] (mat, ray);
155 }
156 }
157 }
158
159
160
161 static void preComputeGlobal (PhotonMap *pmap)
162 /* Precompute irradiance from global photons for final gathering for
163 a random subset of finalGather * pmap -> numPhotons photons, and builds
164 the photon map, discarding the original photons. */
165 /* !!! NOTE: PRECOMPUTATION WITH OOC CURRENTLY WITHOUT CACHE !!! */
166 {
167 unsigned long i, numPreComp;
168 unsigned j;
169 PhotonIdx pIdx;
170 Photon photon;
171 RAY ray;
172 PhotonMap nuPmap;
173
174 repComplete = numPreComp = finalGather * pmap -> numPhotons;
175
176 if (photonRepTime) {
177 sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n",
178 numPreComp);
179 eputs(errmsg);
180 fflush(stderr);
181 }
182
183 /* Copy photon map for precomputed photons */
184 memcpy(&nuPmap, pmap, sizeof(PhotonMap));
185
186 /* Zero counters, init new heap and extents */
187 nuPmap.numPhotons = 0;
188 initPhotonHeap(&nuPmap);
189
190 for (j = 0; j < 3; j++) {
191 nuPmap.minPos [j] = FHUGE;
192 nuPmap.maxPos [j] = -FHUGE;
193 }
194
195 /* Record start time, baby */
196 repStartTime = time(NULL);
197 #ifdef SIGCONT
198 signal(SIGCONT, pmapPreCompReport);
199 #endif
200 repProgress = 0;
201
202 photonRay(NULL, &ray, PRIMARY, NULL);
203 ray.ro = NULL;
204
205 for (i = 0; i < numPreComp; i++) {
206 /* Get random photon from stratified distribution in source heap to
207 * avoid duplicates and clutering */
208 pIdx = firstPhoton(pmap) +
209 (unsigned long)((i + pmapRandom(pmap -> randState)) /
210 finalGather);
211 getPhoton(pmap, pIdx, &photon);
212
213 /* Init dummy photon ray with intersection at photon position */
214 VCOPY(ray.rop, photon.pos);
215 for (j = 0; j < 3; j++)
216 ray.ron [j] = photon.norm [j] / 127.0;
217
218 /* Get density estimate at photon position */
219 photonDensity(pmap, &ray, ray.rcol);
220
221 /* Append photon to new heap from ray */
222 newPhoton(&nuPmap, &ray);
223
224 /* Update progress */
225 repProgress++;
226
227 if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
228 pmapPreCompReport();
229 #ifdef SIGCONT
230 else signal(SIGCONT, pmapPreCompReport);
231 #endif
232 }
233
234 /* Flush heap */
235 flushPhotonHeap(&nuPmap);
236
237 #ifdef SIGCONT
238 signal(SIGCONT, SIG_DFL);
239 #endif
240
241 /* Trash original pmap, replace with precomputed one */
242 deletePhotons(pmap);
243 memcpy(pmap, &nuPmap, sizeof(PhotonMap));
244
245 if (photonRepTime) {
246 eputs("Rebuilding precomputed photon map...\n");
247 fflush(stderr);
248 }
249
250 /* Rebuild underlying data structure, destroying heap */
251 buildPhotonMap(pmap, NULL, NULL, 1);
252 }
253
254
255
256 typedef struct {
257 unsigned long numPhotons [NUM_PMAP_TYPES],
258 numEmitted, numComplete;
259 } PhotonCnt;
260
261
262
263 void distribPhotons (PhotonMap **pmaps, unsigned numProc)
264 {
265 EmissionMap emap;
266 char errmsg2 [128], shmFname [255];
267 unsigned t, srcIdx, proc;
268 double totalFlux = 0;
269 int shmFile, stat, pid;
270 PhotonMap *pm;
271 PhotonCnt *photonCnt;
272
273 for (t = 0; t < NUM_PMAP_TYPES && !pmaps [t]; t++);
274
275 if (t >= NUM_PMAP_TYPES)
276 error(USER, "no photon maps defined in distribPhotons");
277
278 if (!nsources)
279 error(USER, "no light sources in distribPhotons");
280
281 /* ===================================================================
282 * INITIALISATION - Set up emission and scattering funcs
283 * =================================================================== */
284 emap.samples = NULL;
285 emap.maxPartitions = MAXSPART;
286 emap.partitions = (unsigned char*)malloc(emap.maxPartitions >> 1);
287 if (!emap.partitions)
288 error(INTERNAL, "can't allocate source partitions in distribPhotons");
289
290 /* Initialise all defined photon maps */
291 for (t = 0; t < NUM_PMAP_TYPES; t++)
292 if (pmaps [t]) {
293 initPhotonMap(pmaps [t], t);
294 /* Open photon heapfile */
295 initPhotonHeap(pmaps [t]);
296 /* Per-subprocess target count */
297 pmaps [t] -> distribTarget /= numProc;
298 }
299
300 initPhotonEmissionFuncs();
301 initPhotonScatterFuncs();
302
303 /* Get photon ports if specified */
304 if (ambincl == 1)
305 getPhotonPorts();
306
307 /* Get photon sensor modifiers */
308 getPhotonSensors(photonSensorList);
309
310 /* Set up shared mem for photon counters (zeroed by ftruncate) */
311 #if 0
312 snprintf(shmFname, 255, PMAP_SHMFNAME, getpid());
313 shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
314 #else
315 strcpy(shmFname, PMAP_SHMFNAME);
316 shmFile = mkstemp(shmFname);
317 #endif
318
319 if (shmFile < 0)
320 error(SYSTEM, "failed opening shared memory file in distribPhotons");
321
322 if (ftruncate(shmFile, sizeof(*photonCnt)) < 0)
323 error(SYSTEM, "failed setting shared memory size in distribPhotons");
324
325 photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE,
326 MAP_SHARED, shmFile, 0);
327
328 if (photonCnt == MAP_FAILED)
329 error(SYSTEM, "failed mapping shared memory in distribPhotons");
330
331 if (photonRepTime)
332 eputs("\n");
333
334 /* ===================================================================
335 * FLUX INTEGRATION - Get total photon flux from light sources
336 * =================================================================== */
337 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
338 unsigned portCnt = 0;
339 emap.src = source + srcIdx;
340
341 do { /* Need at least one iteration if no ports! */
342 emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
343 : NULL;
344 photonPartition [emap.src -> so -> otype] (&emap);
345
346 if (photonRepTime) {
347 sprintf(errmsg, "Integrating flux from source %s ",
348 source [srcIdx].so -> oname);
349
350 if (emap.port) {
351 sprintf(errmsg2, "via port %s ",
352 photonPorts [portCnt].so -> oname);
353 strcat(errmsg, errmsg2);
354 }
355
356 sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
357 strcat(errmsg, errmsg2);
358 eputs(errmsg);
359 fflush(stderr);
360 }
361
362 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
363 emap.partitionCnt++) {
364 initPhotonEmission(&emap, pdfSamples);
365 totalFlux += colorAvg(emap.partFlux);
366 }
367
368 portCnt++;
369 } while (portCnt < numPhotonPorts);
370 }
371
372 if (totalFlux < FTINY)
373 error(USER, "zero flux from light sources");
374
375 /* MAIN LOOP */
376 for (proc = 0; proc < numProc; proc++) {
377 if (!(pid = fork())) {
378 /* SUBPROCESS ENTERS HERE.
379 All opened and memory mapped files are inherited */
380 unsigned passCnt = 0, prePassCnt = 0;
381 unsigned long lastNumPhotons [NUM_PMAP_TYPES];
382 unsigned long localNumEmitted = 0; /* Num photons emitted by this
383 subprocess alone */
384
385 /* Seed RNGs from PID for decorellated photon distribution */
386 pmapSeed(randSeed + proc, partState);
387 pmapSeed(randSeed + proc, emitState);
388 pmapSeed(randSeed + proc, cntState);
389 pmapSeed(randSeed + proc, mediumState);
390 pmapSeed(randSeed + proc, scatterState);
391 pmapSeed(randSeed + proc, rouletteState);
392
393 for (t = 0; t < NUM_PMAP_TYPES; t++)
394 lastNumPhotons [t] = 0;
395
396 /* =============================================================
397 * 2-PASS PHOTON DISTRIBUTION
398 * Pass 1 (pre): emit fraction of target photon count
399 * Pass 2 (main): based on outcome of pass 1, estimate remaining
400 * number of photons to emit to approximate target
401 * count
402 * ============================================================= */
403 do {
404 double numEmit;
405
406 if (!passCnt) {
407 /* INIT PASS 1 */
408 /* Skip if no photons contributed after sufficient
409 * iterations; make it clear to user which photon maps are
410 * missing so (s)he can check geometry and materials */
411 if (++prePassCnt > maxPreDistrib) {
412 sprintf(errmsg,
413 "proc %d, source %s: too many prepasses",
414 proc, source [srcIdx].so -> oname);
415
416 for (t = 0; t < NUM_PMAP_TYPES; t++)
417 if (pmaps [t] && !pmaps [t] -> numPhotons) {
418 sprintf(errmsg2, ", no %s photons stored",
419 pmapName [t]);
420 strcat(errmsg, errmsg2);
421 }
422
423 error(USER, errmsg);
424 break;
425 }
426
427 /* Num to emit is fraction of minimum target count */
428 numEmit = FHUGE;
429
430 for (t = 0; t < NUM_PMAP_TYPES; t++)
431 if (pmaps [t])
432 numEmit = min(pmaps [t] -> distribTarget, numEmit);
433
434 numEmit *= preDistrib;
435 }
436 else {
437 /* INIT PASS 2 */
438 /* Based on the outcome of the predistribution we can now
439 * estimate how many more photons we have to emit for each
440 * photon map to meet its respective target count. This
441 * value is clamped to 0 in case the target has already been
442 * exceeded in the pass 1. */
443 double maxDistribRatio = 0;
444
445 /* Set the distribution ratio for each map; this indicates
446 * how many photons of each respective type are stored per
447 * emitted photon, and is used as probability for storing a
448 * photon by newPhoton(). Since this biases the photon
449 * density, newPhoton() promotes the flux of stored photons
450 * to compensate. */
451 for (t = 0; t < NUM_PMAP_TYPES; t++)
452 if ((pm = pmaps [t])) {
453 pm -> distribRatio = (double)pm -> distribTarget /
454 pm -> numPhotons - 1;
455
456 /* Check if photon map "overflowed", i.e. exceeded its
457 * target count in the prepass; correcting the photon
458 * flux via the distribution ratio is no longer
459 * possible, as no more photons of this type will be
460 * stored, so notify the user rather than deliver
461 * incorrect results. In future we should handle this
462 * more intelligently by using the photonFlux in each
463 * photon map to individually correct the flux after
464 * distribution. */
465 if (pm -> distribRatio <= FTINY) {
466 sprintf(errmsg, "%s photon map overflow in "
467 "prepass, reduce -apD", pmapName [t]);
468 error(INTERNAL, errmsg);
469 }
470
471 maxDistribRatio = max(pm -> distribRatio,
472 maxDistribRatio);
473 }
474
475 /* Normalise distribution ratios and calculate number of
476 * photons to emit in main pass */
477 for (t = 0; t < NUM_PMAP_TYPES; t++)
478 if ((pm = pmaps [t]))
479 pm -> distribRatio /= maxDistribRatio;
480
481 if ((numEmit = localNumEmitted * maxDistribRatio) < FTINY)
482 /* No photons left to distribute in main pass */
483 break;
484 }
485
486 /* Update shared completion counter for prog.report by parent */
487 photonCnt -> numComplete += numEmit;
488
489 /* PHOTON DISTRIBUTION LOOP */
490 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
491 unsigned portCnt = 0;
492 emap.src = source + srcIdx;
493
494 do { /* Need at least one iteration if no ports! */
495 emap.port = emap.src -> sflags & SDISTANT
496 ? photonPorts + portCnt : NULL;
497 photonPartition [emap.src -> so -> otype] (&emap);
498
499 if (photonRepTime && !proc) {
500 if (!passCnt)
501 sprintf(errmsg, "PREPASS %d on source %s ",
502 prePassCnt, source [srcIdx].so -> oname);
503 else
504 sprintf(errmsg, "MAIN PASS on source %s ",
505 source [srcIdx].so -> oname);
506
507 if (emap.port) {
508 sprintf(errmsg2, "via port %s ",
509 photonPorts [portCnt].so -> oname);
510 strcat(errmsg, errmsg2);
511 }
512
513 sprintf(errmsg2, "(%lu partitions)\n",
514 emap.numPartitions);
515 strcat(errmsg, errmsg2);
516 eputs(errmsg);
517 fflush(stderr);
518 }
519
520 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
521 emap.partitionCnt++) {
522 double partNumEmit;
523 unsigned long partEmitCnt;
524
525 /* Get photon origin within current source partishunn
526 * and build emission map */
527 photonOrigin [emap.src -> so -> otype] (&emap);
528 initPhotonEmission(&emap, pdfSamples);
529
530 /* Number of photons to emit from ziss partishunn --
531 * proportional to flux; photon ray weight and scalar
532 * flux are uniform (the latter only varying in RGB).
533 * */
534 partNumEmit = numEmit * colorAvg(emap.partFlux) /
535 totalFlux;
536 partEmitCnt = (unsigned long)partNumEmit;
537
538 /* Probabilistically account for fractional photons */
539 if (pmapRandom(cntState) < partNumEmit - partEmitCnt)
540 partEmitCnt++;
541
542 /* Update local and shared (global) emission counter */
543 photonCnt -> numEmitted += partEmitCnt;
544 localNumEmitted += partEmitCnt;
545
546 /* Integer counter avoids FP rounding errors during
547 * iteration */
548 while (partEmitCnt--) {
549 RAY photonRay;
550
551 /* Emit photon based on PDF and trace through scene
552 * until absorbed/leaked */
553 emitPhoton(&emap, &photonRay);
554 tracePhoton(&photonRay);
555 }
556
557 /* Update shared global photon count for each pmap */
558 for (t = 0; t < NUM_PMAP_TYPES; t++)
559 if (pmaps [t]) {
560 photonCnt -> numPhotons [t] +=
561 pmaps [t] -> numPhotons - lastNumPhotons [t];
562 lastNumPhotons [t] = pmaps [t] -> numPhotons;
563 }
564 }
565
566 portCnt++;
567 } while (portCnt < numPhotonPorts);
568 }
569
570 for (t = 0; t < NUM_PMAP_TYPES; t++)
571 if (pmaps [t] && !pmaps [t] -> numPhotons) {
572 /* Double preDistrib in case a photon map is empty and
573 * redo pass 1 --> possibility of infinite loop for
574 * pathological scenes (e.g. absorbing materials) */
575 preDistrib *= 2;
576 break;
577 }
578
579 if (t >= NUM_PMAP_TYPES) {
580 /* No empty photon maps found; now do pass 2 */
581 passCnt++;
582 #if 0
583 if (photonRepTime)
584 eputs("\n");
585 #endif
586 }
587 } while (passCnt < 2);
588
589 /* Unmap shared photon counters */
590 #if 0
591 munmap(photonCnt, sizeof(*photonCnt));
592 close(shmFile);
593 #endif
594
595 /* Flush heap buffa for every pmap one final time; this is required
596 * to prevent data corruption! */
597 for (t = 0; t < NUM_PMAP_TYPES; t++)
598 if (pmaps [t]) {
599 #if 0
600 eputs("Final flush\n");
601 #endif
602 flushPhotonHeap(pmaps [t]);
603 fclose(pmaps [t] -> heap);
604 #ifdef DEBUG_PMAP
605 sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(),
606 pmaps [t] -> numPhotons);
607 eputs(errmsg);
608 #endif
609 }
610
611 exit(0);
612 }
613 else if (pid < 0)
614 error(SYSTEM, "failed to fork subprocess in distribPhotons");
615 }
616
617 /* PARENT PROCESS CONTINUES HERE */
618 /* Record start time and enable progress report signal handler */
619 repStartTime = time(NULL);
620 #ifdef SIGCONT
621 signal(SIGCONT, pmapDistribReport);
622 #endif
623
624 if (photonRepTime)
625 eputs("\n");
626
627 /* Wait for subprocesses to complete while reporting progress */
628 proc = numProc;
629 while (proc) {
630 while (waitpid(-1, &stat, WNOHANG) > 0) {
631 /* Subprocess exited; check status */
632 if (!WIFEXITED(stat) || WEXITSTATUS(stat))
633 error(USER, "failed photon distribution");
634
635 --proc;
636 }
637
638 /* Nod off for a bit and update progress */
639 sleep(1);
640 /* Update progress report from shared subprocess counters */
641 repEmitted = repProgress = photonCnt -> numEmitted;
642 repComplete = photonCnt -> numComplete;
643
644 for (t = 0; t < NUM_PMAP_TYPES; t++)
645 if ((pm = pmaps [t])) {
646 #if 0
647 /* Get photon count from heapfile size for progress update */
648 fseek(pm -> heap, 0, SEEK_END);
649 pm -> numPhotons = ftell(pm -> heap) / sizeof(Photon); */
650 #else
651 /* Get global photon count from shmem updated by subprocs */
652 pm -> numPhotons = photonCnt -> numPhotons [t];
653 #endif
654 }
655
656 if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
657 pmapDistribReport();
658 #ifdef SIGCONT
659 else signal(SIGCONT, pmapDistribReport);
660 #endif
661 }
662
663 /* ===================================================================
664 * POST-DISTRIBUTION - Set photon flux and build data struct for photon
665 * storage, etc.
666 * =================================================================== */
667 #ifdef SIGCONT
668 signal(SIGCONT, SIG_DFL);
669 #endif
670 free(emap.samples);
671
672 /* Set photon flux (repProgress is total num emitted) */
673 totalFlux /= photonCnt -> numEmitted;
674
675 /* Photon counters no longer needed, unmap shared memory */
676 munmap(photonCnt, sizeof(*photonCnt));
677 close(shmFile);
678 #if 0
679 shm_unlink(shmFname);
680 #else
681 unlink(shmFname);
682 #endif
683
684 for (t = 0; t < NUM_PMAP_TYPES; t++)
685 if (pmaps [t]) {
686 if (photonRepTime) {
687 sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]);
688 eputs(errmsg);
689 fflush(stderr);
690 }
691
692 /* Build underlying data structure; heap is destroyed */
693 buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc);
694 }
695
696 /* Precompute photon irradiance if necessary */
697 if (preCompPmap)
698 preComputeGlobal(preCompPmap);
699 }