ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/mkpmap.c
Revision: 2.14
Committed: Thu Jun 5 18:28:25 2025 UTC (2 weeks, 1 day ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.13: +2 -3 lines
Log Message:
fix(mkpman): Removed redundant progname definition

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: mkpmap.c,v 2.13 2025/04/23 02:13:34 greg Exp $";
3 #endif
4
5
6 /*
7 ======================================================================
8 Photon map generator
9
10 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
11 (c) Fraunhofer Institute for Solar Energy Systems,
12 supported by the German Research Foundation
13 (DFG LU-204/10-2, "Fassadenintegrierte Regelsysteme" (FARESYS))
14 (c) Lucerne University of Applied Sciences and Arts,
15 supported by the Swiss National Science Foundation
16 (SNSF #147053, "Daylight Redirecting Components")
17 (c) Tokyo University of Science,
18 supported by the JSPS Grants-in-Aid for Scientific Research
19 (KAKENHI JP19KK0115, "Three-Dimensional Light Flow")
20 ======================================================================
21
22 $Id: mkpmap.c,v 2.13 2025/04/23 02:13:34 greg Exp $
23 */
24
25
26 #include "pmap.h"
27 #include "pmapmat.h"
28 #include "pmapsrc.h"
29 #include "pmapcontrib.h"
30 #include "pmaprand.h"
31 #include "paths.h"
32 #include "ambient.h"
33 #include "resolu.h"
34 #include "source.h"
35 #include "func.h"
36 #include <ctype.h>
37 #include <string.h>
38 #include <sys/stat.h>
39
40
41 /* Enable options for Ze Ekspertz only! */
42 #define PMAP_EKSPERTZ
43
44
45 extern char VersionID [];
46
47
48 int dimlist [MAXDIM]; /* sampling dimensions */
49 int ndims = 0; /* number of sampling dimenshunns */
50 char* octname = NULL; /* octree name */
51 CUBE thescene; /* scene top-level octree */
52 OBJECT nsceneobjs; /* number of objects in scene */
53 double srcsizerat = 0.01; /* source partition size ratio */
54 int backvis = 1; /* back face visibility */
55 int clobber = 0; /* overwrite output */
56 COLOR cextinction = BLKCOLOR; /* global extinction coefficient */
57 COLOR salbedo = BLKCOLOR; /* global scattering albedo */
58 double seccg = 0; /* global scattering eccentricity */
59 char *amblist [AMBLLEN + 1]; /* ambient include/exclude list */
60 int ambincl = -1; /* include == 1, exclude == 0 */
61 char *diagFile = NULL; /* diagnostics output file */
62 int rand_samp = 1; /* uncorrelated random sampling */
63 unsigned nproc = 1; /* number of parallel processes */
64 #ifdef EVALDRC_HACK
65 char *angsrcfile = NULL; /* angular source file for EvalDRC */
66 #endif
67
68
69 /* Dummies for linkage */
70
71 COLOR ambval = BLKCOLOR;
72 double shadthresh = .05, ambacc = 0.2, shadcert = .5, minweight = 5e-3,
73 ssampdist = 0, dstrsrc = 0.0, specthresh = 0.15, specjitter = 1.0,
74 avgrefl = 0.5;
75 int ambvwt = 0, ambssamp = 0, ambres = 32, ambounce = 0,
76 directrelay = 1, directvis = 1, samplendx, do_irrad = 0,
77 ambdiv = 128, vspretest = 512, maxdepth = 6, contrib = 0;
78 char *ambfile = NULL, *RCCONTEXT = NULL;
79 void (*trace)() = NULL, (*addobjnotify [])() = {ambnotify, NULL};
80
81
82 void printdefaults()
83 /* print default values to stdout */
84 {
85 #ifdef EVALDRC_HACK
86 /* EvalDRC support */
87 puts("-A\t\t\t\t# angular source file");
88 #endif
89 puts("-ae mod\t\t\t\t# exclude modifier");
90 puts("-aE file\t\t\t\t# exclude modifiers from file");
91 puts("-ai mod\t\t\t\t# include modifier");
92 puts("-aI file\t\t\t\t# include modifiers from file");
93 #ifdef PMAP_EKSPERTZ
94 puts("-api xmin ymin zmin xmax ymax zmax\t# rectangular region of interest");
95 puts("-apI xpos ypos zpos radius\t\t# spherical region of interest");
96 #endif
97 puts("-apg file nPhotons\t\t\t# global photon map");
98 puts("-apc file nPhotons\t\t\t# caustic photon map");
99 puts("-apd file nPhotons\t\t\t# direct photon map");
100 puts("-app file nPhotons bwidth\t\t# precomputed global photon map");
101 puts("-apv file nPhotons\t\t\t# volume photon map");
102 puts("-apC file nPhotons\t\t\t# contribution photon map");
103 printf("-apD %f\t\t\t\t# predistribution factor\n", preDistrib);
104 printf("-apM %d\t\t\t\t\t# max predistrib passes\n", maxPreDistrib);
105 #if 1
106 /* Kept for backwards compat, will be gradually phased out by -ld, -lr */
107 printf("-apm %ld\t\t\t\t# limit photon bounces\n", photonMaxBounce);
108 #endif
109 puts("-apo+ mod\t\t\t\t# photon port modifier");
110 puts("-apO+ file\t\t\t\t# photon ports from file");
111 printf("-apP %f\t\t\t\t# precomputation factor\n", finalGather);
112 printf("-apr %d\t\t\t\t\t# random seed\n", randSeed);
113 puts("-aps mod\t\t\t\t# antimatter sensor modifier");
114 puts("-apS file\t\t\t\t# antimatter sensors from file");
115
116 printf(backvis
117 ? "-bv+\t\t\t\t\t# back face visibility on\n"
118 : "-bv-\t\t\t\t\t# back face visibility off\n"
119 );
120 printf("-dp %.1f\t\t\t\t# PDF samples / sr\n", pdfSamples);
121 printf("-ds %f\t\t\t\t# source partition size ratio\n", srcsizerat);
122 printf("-e %s\t\t\t\t# diagnostics output file\n", diagFile);
123 printf(clobber
124 ? "-fo+\t\t\t\t\t# force overwrite\n"
125 : "-fo-\t\t\t\t\t# do not overwrite\n"
126 );
127 #ifdef PMAP_EKSPERTZ
128 /* (Formerly) NU STUFF for Ze Exspertz! */
129 printf("-ld %.1f\t\t\t\t\t# limit photon distance\n", photonMaxDist);
130 printf("-lr %ld\t\t\t\t# limit photon bounces\n", photonMaxBounce);
131 #endif
132 printf(
133 "-ma %.2f %.2f %.2f\t\t\t# scattering albedo\n",
134 colval(salbedo,RED), colval(salbedo,GRN), colval(salbedo,BLU)
135 );
136 printf(
137 "-me %.2e %.2e %.2e\t\t# extinction coefficient\n",
138 colval(cextinction,RED), colval(cextinction,GRN),
139 colval(cextinction,BLU)
140 );
141 printf("-mg %.2f\t\t\t\t# scattering eccentricity\n", seccg);
142 #if NIX
143 /* Multiprocessing on NIX only; so tuff luck, Windoze Weenies! */
144 printf("-n %d\t\t\t\t\t# number of parallel processes\n", nproc);
145 #endif
146 printf("-t %-9d\t\t\t\t# time between reports\n", photonRepTime);
147 printf(verbose
148 ? "-v+\t\t\t\t\t# verbose console output\n"
149 : "-v-\t\t\t\t\t# terse console output\n"
150 );
151 }
152
153
154 int main (int argc, char* argv [])
155 {
156 #define check(ol, al) if ( \
157 argv [i][ol] || badarg(argc - i - 1,argv + i + 1, al) \
158 ) goto badopt
159
160 /* Evaluate boolean option, setting var accordingly */
161 #define check_bool(olen, var) switch (argv [i][olen]) { \
162 case '\0': \
163 var = !var; break; \
164 case 'y': case 'Y': case 't': case 'T': case '+': case '1': \
165 var = 1; break; \
166 case 'n': case 'N': case 'f': case 'F': case '-': case '0': \
167 var = 0; break; \
168 default: \
169 goto badopt; \
170 }
171
172 /* Evaluate trinary option, setting bits v1 and v2 in var accordingly */
173 #define check_tri(olen, v1, v2, var) switch (argv [i][olen]) { \
174 case '\0': case '+': \
175 var = v1; break; \
176 case '-': \
177 var = v2; break;\
178 case '0': \
179 var = v1 | v2; break; \
180 default: \
181 goto badopt; \
182 }
183
184 int loadflags = IO_CHECK | IO_SCENE | IO_TREE | IO_BOUNDS,
185 rval, i, j, n;
186 char **portLp = photonPortList, **sensLp = photonSensorList,
187 **amblp = NULL, sbuf [MAXSTR], portFlags [2] = "\0\0";
188 struct stat pmstat;
189
190 /* Global program name */
191 progname = fixargv0(argv [0]);
192 /* Initialize object types */
193 initotypes();
194 /* initialize calcomp routines */
195 initfunc();
196
197 /* Parse options */
198 for (i = 1; i < argc; i++) {
199 /* Eggs-pand arguments */
200 while ((rval = expandarg(&argc, &argv, i)))
201 if (rval < 0) {
202 sprintf(errmsg, "cannot eggs-pand '%s'", argv [i]);
203 error(SYSTEM, errmsg);
204 }
205
206 if (argv[i] == NULL)
207 break;
208
209 if (!strcmp(argv [i], "-version")) {
210 puts(VersionID);
211 quit(0);
212 }
213
214 if (!strcmp(argv [i], "-defaults") || !strcmp(argv [i], "-help")) {
215 printdefaults();
216 quit(0);
217 }
218
219 /* Get octree */
220 if (i == argc - 1) {
221 octname = argv [i];
222 break;
223 }
224
225 switch (argv [i][1]) {
226 case 'a': /* Ambient */
227 switch (argv [i][2]) {
228 case 'i': /* Ambient include */
229 case 'I':
230 check(3, "s");
231 if (ambincl != 1) {
232 ambincl = 1;
233 amblp = amblist;
234 }
235 if (isupper(argv [i][2])) {
236 /* Add modifiers from file */
237 rval = wordfile(
238 amblp, AMBLLEN - (amblp - amblist),
239 getpath(argv [++i], getrlibpath(), R_OK)
240 );
241 if (rval < 0) {
242 sprintf(
243 errmsg, "cannot open ambient include file \"%s\"",
244 argv [i]
245 );
246 error(SYSTEM, errmsg);
247 }
248 amblp += rval;
249 }
250 else {
251 /* Add modifier from next arg */
252 *amblp++ = savqstr(argv [++i]);
253 *amblp = NULL;
254 }
255 break;
256
257 case 'e': /* Ambient exclude */
258 case 'E':
259 check(3, "s");
260 if (ambincl != 0) {
261 ambincl = 0;
262 amblp = amblist;
263 }
264 if (isupper(argv [i][2])) {
265 /* Add modifiers from file */
266 rval = wordfile(
267 amblp, AMBLLEN - (amblp - amblist),
268 getpath(argv [++i], getrlibpath(), R_OK)
269 );
270 if (rval < 0) {
271 sprintf(
272 errmsg, "cannot open ambient exclude file \"%s\"",
273 argv [i]
274 );
275 error(SYSTEM, errmsg);
276 }
277 amblp += rval;
278 }
279 else {
280 /* Add modifier from next arg */
281 *amblp++ = savqstr(argv [++i]);
282 *amblp = NULL;
283 }
284 break;
285
286 case 'p': /* Pmap-specific */
287 switch (argv [i][3]) {
288 case 'g': /* Global photon map */
289 check(4, "ss");
290 globalPmapParams.fileName = argv [++i];
291 globalPmapParams.distribTarget =
292 parseMultiplier(argv [++i]);
293 if (!globalPmapParams.distribTarget)
294 goto badopt;
295 globalPmapParams.minGather =
296 globalPmapParams.maxGather = 0;
297 break;
298
299 case 'p': /* Precomputed global photon map */
300 check(4, "ssi");
301 preCompPmapParams.fileName = argv [++i];
302 preCompPmapParams.distribTarget =
303 parseMultiplier(argv [++i]);
304 if (!preCompPmapParams.distribTarget)
305 goto badopt;
306 preCompPmapParams.minGather =
307 preCompPmapParams.maxGather = atoi(argv [++i]);
308 if (!preCompPmapParams.maxGather)
309 goto badopt;
310 break;
311
312 case 'c': /* Caustic photon map */
313 check(4, "ss");
314 causticPmapParams.fileName = argv [++i];
315 causticPmapParams.distribTarget =
316 parseMultiplier(argv [++i]);
317 if (!causticPmapParams.distribTarget)
318 goto badopt;
319 break;
320
321 case 'v': /* Volume photon map */
322 check(4, "ss");
323 volumePmapParams.fileName = argv [++i];
324 volumePmapParams.distribTarget =
325 parseMultiplier(argv [++i]);
326 if (!volumePmapParams.distribTarget)
327 goto badopt;
328 break;
329
330 case 'd': /* Direct photon map */
331 check(4, "ss");
332 directPmapParams.fileName = argv [++i];
333 directPmapParams.distribTarget =
334 parseMultiplier(argv [++i]);
335 if (!directPmapParams.distribTarget)
336 goto badopt;
337 break;
338
339 case 'C': /* Contribution photon map */
340 check(4, "ss");
341 contribPmapParams.fileName = argv [++i];
342 contribPmapParams.distribTarget =
343 parseMultiplier(argv [++i]);
344 if (!contribPmapParams.distribTarget)
345 goto badopt;
346 break;
347
348 case 'D': /* Predistribution factor */
349 check(4, "f");
350 preDistrib = atof(argv [++i]);
351 if (preDistrib <= 0)
352 error(USER, "predistrib factor must be > 0");
353 break;
354
355 case 'M': /* Max predistribution passes */
356 check(4, "i");
357 maxPreDistrib = atoi(argv [++i]);
358 if (maxPreDistrib <= 0)
359 error(USER, "max predistrib passes must be > 0");
360 break;
361
362 #if 1
363 /* Kept for backwards compat, to be phased out by -lr */
364 case 'm': /* Max photon bounces */
365 check(4, "i");
366 photonMaxBounce = atol(argv [++i]);
367 if (photonMaxBounce <= 0)
368 error(USER, "max photon bounces must be > 0");
369 break;
370 #endif
371
372 #ifdef PMAP_EKSPERTZ
373 case 'i': /* Add rectangular region of interest */
374 case 'I': /* Add spherical region of interest */
375 check(4, isupper(argv [j=i][3]) ? "ffff" : "ffffff");
376 n = pmapNumROI;
377
378 pmapROI = realloc(
379 pmapROI, ++pmapNumROI * sizeof(PhotonMapROI)
380 );
381 if (!pmapROI)
382 error(SYSTEM, "failed to allocate ROI");
383
384 pmapROI [n].pos [0] = atof(argv [++i]);
385 pmapROI [n].pos [1] = atof(argv [++i]);
386 pmapROI [n].pos [2] = atof(argv [++i]);
387 pmapROI [n].siz [0] = atof(argv [++i]);
388
389 if (isupper(argv [j][3])) {
390 /* Spherical ROI; radius^2 */
391 pmapROI [n].siz [0] *= pmapROI [n].siz [0];
392 PMAP_ROI_SETSPHERE(pmapROI + n);
393 if (pmapROI [n].siz [0] <= FTINY)
394 error(
395 USER,
396 "region of interest has invalid radius"
397 );
398 }
399 else {
400 /* Rectangular ROI */
401 pmapROI [n].siz [1] = atof(argv [++i]);
402 pmapROI [n].siz [2] = atof(argv [++i]);
403
404 for (j = 0; j < 3; j++) {
405 /* Pos at rectangle centre, siz symmetric */
406 pmapROI [n].pos [j] = 0.5 * (
407 pmapROI [n].pos [j] + pmapROI [n].siz [j]
408 );
409 pmapROI [n].siz [j] = fabs(
410 pmapROI [n].siz [j] - pmapROI [n].pos [j]
411 );
412 if (pmapROI [n].siz [j] <= FTINY)
413 error(
414 USER,
415 "region of interest has invalid size"
416 );
417 }
418 }
419 break;
420 #endif
421
422 case 'P': /* Global photon precomp ratio */
423 check(4, "f");
424 finalGather = atof(argv [++i]);
425 if (finalGather <= 0 || finalGather > 1)
426 error(
427 USER, "global photon precomputation ratio "
428 "must be in range ]0, 1]"
429 );
430 break;
431
432 case 'o': /* Photon port */
433 case 'O':
434 /* Check for bad arg and length, taking into account
435 * default forward orientation if none specified, in
436 * order to maintain previous behaviour */
437 check(argv [i][4] ? 5 : 4, "s");
438 /* Get port orientation flags */
439 check_tri(
440 4, PMAP_PORTFWD, PMAP_PORTBWD, portFlags [0]
441 );
442
443 if (isupper(argv [i][3])) {
444 /* Add port modifiers from file */
445 rval = wordfile(
446 portLp, MAXSET - (portLp - photonPortList),
447 getpath(argv [++i], getrlibpath(), R_OK)
448 );
449 if (rval < 0) {
450 sprintf(
451 errmsg, "cannot open photon port file %s",
452 argv [i]
453 );
454 error(SYSTEM, errmsg);
455 }
456 /* HACK: append port orientation flags to every
457 * modifier; note this requires reallocation */
458 for (; rval--; portLp++) {
459 j = strlen(*portLp);
460 if (!(*portLp = realloc(*portLp, j + 2))) {
461 sprintf(
462 errmsg,
463 "cannot allocate photon port modifiers"
464 " from file %s", argv [i]
465 );
466 error(SYSTEM, errmsg);
467 }
468 strcat(*portLp, portFlags);
469 }
470 }
471 else {
472 /* Append port flags to port modifier, add to
473 * port list and mark of end list with NULL */
474 strcpy(sbuf, argv [++i]);
475 strcat(sbuf, portFlags);
476 *portLp++ = savqstr(sbuf);
477 *portLp = NULL;
478 }
479 break;
480
481 case 'r': /* Random seed */
482 check(4, "i");
483 randSeed = atoi(argv [++i]);
484 break;
485
486 case 's': /* Antimatter sensor */
487 case 'S':
488 check(4, "s");
489 if (isupper(argv[i][3])) {
490 /* Add sensor modifiers from file */
491 rval = wordfile(
492 sensLp, MAXSET - (sensLp - photonSensorList),
493 getpath(argv [++i], getrlibpath(), R_OK)
494 );
495 if (rval < 0) {
496 sprintf(
497 errmsg,
498 "cannot open antimatter sensor file %s",
499 argv [i]
500 );
501 error(SYSTEM, errmsg);
502 }
503 sensLp += rval;
504 }
505 else {
506 /* Append modifier to sensor list, mark end with
507 * NULL */
508 *sensLp++ = savqstr(argv [++i]);
509 *sensLp = NULL;
510 }
511 break;
512
513 default: goto badopt;
514 }
515 break;
516
517 default: goto badopt;
518 }
519 break;
520
521 case 'b': /* Back face visibility */
522 if (argv [i][2] == 'v') {
523 check_bool(3, backvis);
524 }
525 else goto badopt;
526 break;
527
528 case 'd': /* Direct */
529 switch (argv [i][2]) {
530 case 'p': /* PDF samples */
531 check(3, "f");
532 pdfSamples = atof(argv [++i]);
533 break;
534
535 case 's': /* Source partition size ratio */
536 check(3, "f");
537 srcsizerat = atof(argv [++i]);
538 break;
539
540 default: goto badopt;
541 }
542 break;
543
544 case 'e': /* Diagnostics file */
545 check(2, "s");
546 diagFile = argv [++i];
547 break;
548
549 case 'f': /* Force overwrite */
550 if (argv [i][2] == 'o') {
551 check_bool(3, clobber);
552 }
553 else goto badopt;
554 break;
555
556 #ifdef PMAP_EKSPERTZ
557 case 'l': /* Limits */
558 switch (argv [i][2]) {
559 case 'd': /* Limit photon path distance */
560 check(3, "f");
561 photonMaxDist = atof(argv [++i]);
562 if (photonMaxDist <= 0)
563 error(USER, "max photon distance must be > 0");
564 break;
565
566 case 'r': /* Limit photon bounces */
567 check(3, "i");
568 photonMaxBounce = atol(argv [++i]);
569 if (photonMaxBounce <= 0)
570 error(USER, "max photon bounces must be > 0");
571 break;
572
573 default: goto badopt;
574 }
575 break;
576 #endif
577
578 case 'm': /* Medium */
579 switch (argv[i][2]) {
580 case 'e': /* Eggs-tinction coefficient */
581 check(3, "fff");
582 setcolor(
583 cextinction, atof(argv [i + 1]),
584 atof(argv [i + 2]), atof(argv [i + 3])
585 );
586 i += 3;
587 break;
588
589 case 'a': /* Albedo */
590 check(3, "fff");
591 setcolor(
592 salbedo, atof(argv [i + 1]),
593 atof(argv [i + 2]), atof(argv [i + 3])
594 );
595 i += 3;
596 break;
597
598 case 'g': /* Scattering eccentricity */
599 check(3, "f");
600 seccg = atof(argv [++i]);
601 break;
602
603 default: goto badopt;
604 }
605 break;
606
607 #if NIX
608 case 'n': /* Num parallel processes (NIX only) */
609 check(2, "i");
610 nproc = atoi(argv [++i]);
611
612 if (nproc > PMAP_MAXPROC) {
613 nproc = PMAP_MAXPROC;
614 sprintf(
615 errmsg, "too many parallel processes, clamping to %d\n",
616 nproc
617 );
618 error(WARNING, errmsg);
619 }
620 break;
621 #endif
622
623 case 't': /* Timer */
624 check(2, "i");
625 photonRepTime = atoi(argv [++i]);
626 break;
627
628 case 'v': /* Verbosity */
629 check_bool(2, verbose);
630 break;
631
632 #ifdef EVALDRC_HACK
633 case 'A': /* Angular source file */
634 check(2,"s");
635 angsrcfile = argv[++i];
636 break;
637 #endif
638
639 default: goto badopt;
640 }
641 }
642
643 /* Open diagnostics file */
644 if (diagFile) {
645 if (!freopen(diagFile, "a", stderr))
646 quit(2);
647 fprintf(stderr, "**************\n*** PID %5d: ", getpid());
648 printargs(argc, argv, stderr);
649 putc('\n', stderr);
650 fflush(stderr);
651 }
652
653 #ifdef NICE
654 /* Lower priority */
655 nice(NICE);
656 #endif
657
658 if (octname == NULL)
659 error(USER, "missing octree argument");
660
661 /* Allocate photon maps and set parameters */
662 for (i = 0; i < NUM_PMAP_TYPES; i++) {
663 setPmapParam(photonMaps + i, pmapParams + i);
664
665 /* Don't overwrite existing photon map unless clobbering enabled */
666 if (
667 photonMaps [i] && !stat(photonMaps [i] -> fileName, &pmstat) &&
668 !clobber
669 ) {
670 sprintf(
671 errmsg, "photon map file %s exists, not overwritten",
672 photonMaps [i] -> fileName
673 );
674 error(USER, errmsg);
675 }
676 }
677
678 for (i = 0; i < NUM_PMAP_TYPES && !photonMaps [i]; i++);
679 if (i >= NUM_PMAP_TYPES)
680 error(USER, "no photon maps specified");
681
682 readoct(octname, loadflags, &thescene, NULL);
683 #ifdef EVALDRC_HACK
684 if (angsrcfile)
685 readobj(angsrcfile); /* load angular sources */
686 #endif
687 nsceneobjs = nobjects;
688
689 /* Get sources */
690 marksources();
691
692 /* Do forward pass and build photon maps */
693 if (contribPmap)
694 /* Just build contrib pmap, ignore others */
695 distribPhotonContrib(contribPmap, nproc);
696 else
697 distribPhotons(photonMaps, nproc);
698
699 /* Save photon maps; no idea why GCC needs an explicit cast here... */
700 savePmaps((const PhotonMap**)photonMaps, argc, argv);
701 cleanUpPmaps(photonMaps);
702
703 quit(0);
704
705 badopt:
706 sprintf(errmsg, "command line error at '%s'", argv[i]);
707 error(USER, errmsg);
708
709 #undef check
710 #undef check_bool
711 return 0;
712 }
713