| 1 | #ifndef lint | 
| 2 | static const char RCSid[] = "$Id: mkpmap.c,v 2.5 2016/05/17 17:39:47 rschregle 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 | Lucerne University of Applied Sciences & Arts | 
| 13 | (c) Lucerne University of Applied Sciences and Arts, | 
| 14 | supported by the Swiss National Science Foundation (SNSF, #147053) | 
| 15 | ====================================================================== | 
| 16 |  | 
| 17 | $Id: mkpmap.c,v 2.5 2016/05/17 17:39:47 rschregle Exp $ | 
| 18 | */ | 
| 19 |  | 
| 20 |  | 
| 21 | #include "pmap.h" | 
| 22 | #include "pmapmat.h" | 
| 23 | #include "pmapcontrib.h" | 
| 24 | #include "pmaprand.h" | 
| 25 | #include "paths.h" | 
| 26 | #include "ambient.h" | 
| 27 | #include "resolu.h" | 
| 28 | #include "source.h" | 
| 29 | #include <string.h> | 
| 30 | #include <sys/stat.h> | 
| 31 |  | 
| 32 |  | 
| 33 | extern char VersionID []; | 
| 34 |  | 
| 35 |  | 
| 36 | char*    progname;                  /* argv[0] */ | 
| 37 | int      dimlist [MAXDIM];          /* sampling dimensions */ | 
| 38 | int      ndims = 0;                 /* number of sampling dimenshunns */ | 
| 39 | char*    octname = NULL;            /* octree name */ | 
| 40 | CUBE     thescene;                  /* scene top-level octree */ | 
| 41 | OBJECT   nsceneobjs;                /* number of objects in scene */ | 
| 42 | double   srcsizerat = 0.01;         /* source partition size ratio */ | 
| 43 | int      backvis = 1;               /* back face visibility */ | 
| 44 | int      clobber = 0;               /* overwrite output */ | 
| 45 | COLOR    cextinction = BLKCOLOR;    /* global extinction coefficient */ | 
| 46 | COLOR    salbedo = BLKCOLOR;        /* global scattering albedo */ | 
| 47 | double   seccg = 0;                 /* global scattering eccentricity */ | 
| 48 | int      ambincl = -1;              /* photon port flag */ | 
| 49 | char     *amblist [AMBLLEN + 1];    /* photon port list */ | 
| 50 | char     *diagFile = NULL;          /* diagnostics output file */ | 
| 51 | int      rand_samp = 1;             /* uncorrelated random sampling */ | 
| 52 | unsigned nproc = 1;                 /* number of parallel processes */ | 
| 53 | #ifdef EVALDRC_HACK | 
| 54 | char  *angsrcfile = NULL;        /* angular source file for EvalDRC */ | 
| 55 | #endif | 
| 56 |  | 
| 57 |  | 
| 58 | /* Dummies for linkage */ | 
| 59 |  | 
| 60 | COLOR ambval = BLKCOLOR; | 
| 61 | double shadthresh = .05, ambacc = 0.2, shadcert = .5, minweight = 5e-3, | 
| 62 | ssampdist = 0, dstrsrc = 0.0, specthresh = 0.15, specjitter = 1.0, | 
| 63 | avgrefl = 0.5; | 
| 64 | int ambvwt = 0, ambssamp = 0, ambres = 32, ambounce = 0, directrelay = 1, | 
| 65 | directvis = 1, samplendx, do_irrad = 0, ambdiv = 128, vspretest = 512, | 
| 66 | maxdepth = 6, contrib = 0; | 
| 67 | char *shm_boundary = NULL, *ambfile = NULL, *RCCONTEXT = NULL; | 
| 68 | void (*trace)() = NULL, (*addobjnotify [])() = {ambnotify, NULL}; | 
| 69 |  | 
| 70 |  | 
| 71 | void printdefaults() | 
| 72 | /* print default values to stdout */ | 
| 73 | { | 
| 74 | puts("-apg file nPhotons\t\t# global photon map"); | 
| 75 | puts("-apc file nPhotons\t\t# caustic photon map"); | 
| 76 | puts("-apd file nPhotons\t\t# direct photon map"); | 
| 77 | puts("-app file nPhotons bwidth\t# precomputed global photon map"); | 
| 78 | puts("-apv file nPhotons\t\t# volume photon map"); | 
| 79 | puts("-apC file nPhotons\t\t# contribution photon map"); | 
| 80 |  | 
| 81 | printf("-apD %f\t\t\t# predistribution factor\n", preDistrib); | 
| 82 | printf("-apM %d\t\t\t\t# max predistrib passes\n", maxPreDistrib); | 
| 83 | printf("-apm %ld\t\t\t# max photon bounces\n", photonMaxBounce); | 
| 84 | puts("-apo mod\t\t\t# photon port modifier"); | 
| 85 | puts("-apO file\t\t\t# photon port file"); | 
| 86 | printf("-apP %f\t\t\t# precomputation factor\n", finalGather); | 
| 87 | printf("-apr %d\t\t\t\t# random seed\n", randSeed); | 
| 88 | puts("-aps mod\t\t\t# antimatter sensor modifier"); | 
| 89 | puts("-apS file\t\t\t# antimatter sensor file"); | 
| 90 |  | 
| 91 | printf(backvis ? "-bv+\t\t\t\t# back face visibility on\n" | 
| 92 | : "-bv-\t\t\t\t# back face visibility off\n"); | 
| 93 | printf("-dp  %.1f\t\t\t# PDF samples / sr\n", pdfSamples); | 
| 94 | printf("-ds  %f\t\t\t# source partition size ratio\n", srcsizerat); | 
| 95 | printf("-e   %s\t\t\t# diagnostics output file\n", diagFile); | 
| 96 | printf(clobber ? "-fo+\t\t\t\t# force overwrite\n" | 
| 97 | : "-fo-\t\t\t\t# do not overwrite\n"); | 
| 98 | printf("-ma  %.2f %.2f %.2f\t\t# scattering albedo\n", | 
| 99 | colval(salbedo,RED), colval(salbedo,GRN), colval(salbedo,BLU)); | 
| 100 | printf("-me  %.2e %.2e %.2e\t# extinction coefficient\n", | 
| 101 | colval(cextinction,RED), colval(cextinction,GRN), | 
| 102 | colval(cextinction,BLU)); | 
| 103 | printf("-mg  %.2f\t\t\t# scattering eccentricity\n", seccg); | 
| 104 | #if NIX | 
| 105 | /* Multiprocessing on NIX only */ | 
| 106 | printf("-n   %d\t\t\t\t# number of parallel processes\n", nproc); | 
| 107 | #endif | 
| 108 | printf("-t   %-9d\t\t\t# time between reports\n", photonRepTime); | 
| 109 | printf(verbose ? "-v+\t\t\t\t# verbose console output\n" | 
| 110 | : "-v-\t\t\t\t# terse console output\n"); | 
| 111 | #ifdef PMAP_ROI | 
| 112 | /* Ziss option for ze egg-spurtz only! */ | 
| 113 | puts("-api xmin ymin zmin\n     xmax ymax zmax\t\t# region of interest"); | 
| 114 | #endif | 
| 115 | #ifdef EVALDRC_HACK | 
| 116 | /* ... and ziss one... */ | 
| 117 | puts("-A\t\t\t\t# angular source file"); | 
| 118 | #endif | 
| 119 | } | 
| 120 |  | 
| 121 |  | 
| 122 | int main (int argc, char* argv []) | 
| 123 | { | 
| 124 | #define check(ol, al) if (argv [i][ol] || \ | 
| 125 | badarg(argc - i - 1,argv + i + 1, al)) \ | 
| 126 | goto badopt | 
| 127 |  | 
| 128 | #define check_bool(olen, var) switch (argv [i][olen]) { \ | 
| 129 | case '\0': var = !var; break; \ | 
| 130 | case 'y': case 'Y': case 't': case 'T': \ | 
| 131 | case '+': case '1': var = 1; break; \ | 
| 132 | case 'n': case 'N': case 'f': case 'F': \ | 
| 133 | case '-': case '0': var = 0; break; \ | 
| 134 | default: goto badopt; \ | 
| 135 | } | 
| 136 |  | 
| 137 | int loadflags = IO_CHECK | IO_SCENE | IO_TREE | IO_BOUNDS, rval, i; | 
| 138 | char **portLp = NULL, **sensLp = photonSensorList; | 
| 139 | struct stat pmstat; | 
| 140 |  | 
| 141 | /* Global program name */ | 
| 142 | progname = fixargv0(argv [0]); | 
| 143 | /* Initialize object types */ | 
| 144 | initotypes(); | 
| 145 |  | 
| 146 | /* Parse options */ | 
| 147 | for (i = 1; i < argc; i++) { | 
| 148 | /* Eggs-pand arguments */ | 
| 149 | while ((rval = expandarg(&argc, &argv, i))) | 
| 150 | if (rval < 0) { | 
| 151 | sprintf(errmsg, "cannot eggs-pand '%s'", argv [i]); | 
| 152 | error(SYSTEM, errmsg); | 
| 153 | } | 
| 154 |  | 
| 155 | if (argv[i] == NULL) | 
| 156 | break; | 
| 157 |  | 
| 158 | if (!strcmp(argv [i], "-version")) { | 
| 159 | puts(VersionID); | 
| 160 | quit(0); | 
| 161 | } | 
| 162 |  | 
| 163 | if (!strcmp(argv [i], "-defaults") || !strcmp(argv [i], "-help")) { | 
| 164 | printdefaults(); | 
| 165 | quit(0); | 
| 166 | } | 
| 167 |  | 
| 168 | /* Get octree */ | 
| 169 | if (i == argc - 1) { | 
| 170 | octname = argv [i]; | 
| 171 | break; | 
| 172 | } | 
| 173 |  | 
| 174 | switch (argv [i][1]) { | 
| 175 | case 'a': | 
| 176 | if (!strcmp(argv [i] + 2, "pg")) { | 
| 177 | /* Global photon map */ | 
| 178 | check(4, "ss"); | 
| 179 | globalPmapParams.fileName = argv [++i]; | 
| 180 | globalPmapParams.distribTarget = | 
| 181 | parseMultiplier(argv [++i]); | 
| 182 | if (!globalPmapParams.distribTarget) | 
| 183 | goto badopt; | 
| 184 | globalPmapParams.minGather = globalPmapParams.maxGather = 0; | 
| 185 | } | 
| 186 |  | 
| 187 | else if (!strcmp(argv [i] + 2, "pm")) { | 
| 188 | /* Max photon bounces */ | 
| 189 | check(4, "i"); | 
| 190 | photonMaxBounce = atol(argv [++i]); | 
| 191 | if (photonMaxBounce <= 0) | 
| 192 | error(USER, "max photon bounces must be > 0"); | 
| 193 | } | 
| 194 |  | 
| 195 | else if (!strcmp(argv [i] + 2, "pp")) { | 
| 196 | /* Precomputed global photon map */ | 
| 197 | check(4, "ssi"); | 
| 198 | preCompPmapParams.fileName = argv [++i]; | 
| 199 | preCompPmapParams.distribTarget = | 
| 200 | parseMultiplier(argv [++i]); | 
| 201 | if (!preCompPmapParams.distribTarget) | 
| 202 | goto badopt; | 
| 203 | preCompPmapParams.minGather = preCompPmapParams.maxGather = | 
| 204 | atoi(argv [++i]); | 
| 205 | if (!preCompPmapParams.maxGather) | 
| 206 | goto badopt; | 
| 207 | } | 
| 208 |  | 
| 209 | else if (!strcmp(argv [i] + 2, "pc")) { | 
| 210 | /* Caustic photon map */ | 
| 211 | check(4, "ss"); | 
| 212 | causticPmapParams.fileName = argv [++i]; | 
| 213 | causticPmapParams.distribTarget = | 
| 214 | parseMultiplier(argv [++i]); | 
| 215 | if (!causticPmapParams.distribTarget) | 
| 216 | goto badopt; | 
| 217 | } | 
| 218 |  | 
| 219 | else if (!strcmp(argv [i] + 2, "pv")) { | 
| 220 | /* Volume photon map */ | 
| 221 | check(4, "ss"); | 
| 222 | volumePmapParams.fileName = argv [++i]; | 
| 223 | volumePmapParams.distribTarget = | 
| 224 | parseMultiplier(argv [++i]); | 
| 225 | if (!volumePmapParams.distribTarget) | 
| 226 | goto badopt; | 
| 227 | } | 
| 228 |  | 
| 229 | else if (!strcmp(argv [i] + 2, "pd")) { | 
| 230 | /* Direct photon map */ | 
| 231 | check(4, "ss"); | 
| 232 | directPmapParams.fileName = argv [++i]; | 
| 233 | directPmapParams.distribTarget = | 
| 234 | parseMultiplier(argv [++i]); | 
| 235 | if (!directPmapParams.distribTarget) | 
| 236 | goto badopt; | 
| 237 | } | 
| 238 |  | 
| 239 | else if (!strcmp(argv [i] + 2, "pC")) { | 
| 240 | /* Light source contribution photon map */ | 
| 241 | check(4, "ss"); | 
| 242 | contribPmapParams.fileName = argv [++i]; | 
| 243 | contribPmapParams.distribTarget = | 
| 244 | parseMultiplier(argv [++i]); | 
| 245 | if (!contribPmapParams.distribTarget) | 
| 246 | goto badopt; | 
| 247 | } | 
| 248 |  | 
| 249 | else if (!strcmp(argv [i] + 2, "pD")) { | 
| 250 | /* Predistribution factor */ | 
| 251 | check(4, "f"); | 
| 252 | preDistrib = atof(argv [++i]); | 
| 253 | if (preDistrib <= 0) | 
| 254 | error(USER, "predistribution factor must be > 0"); | 
| 255 | } | 
| 256 |  | 
| 257 | else if (!strcmp(argv [i] + 2, "pM")) { | 
| 258 | /* Max predistribution passes */ | 
| 259 | check(4, "i"); | 
| 260 | maxPreDistrib = atoi(argv [++i]); | 
| 261 | if (maxPreDistrib <= 0) | 
| 262 | error(USER, "max predistribution passes must be > 0"); | 
| 263 | } | 
| 264 |  | 
| 265 | #ifdef PMAP_ROI | 
| 266 | /* Add region of interest; for ze egg-spurtz only! */ | 
| 267 | else if (!strcmp(argv [i] + 2, "pi")) { | 
| 268 | unsigned j, n = pmapNumROI; | 
| 269 | check(4, "ffffff"); | 
| 270 |  | 
| 271 | pmapROI = realloc(pmapROI, | 
| 272 | ++pmapNumROI * sizeof(PhotonMapROI)); | 
| 273 | if (!pmapROI) | 
| 274 | 1                  error(SYSTEM, "failed to allocate ROI"); | 
| 275 |  | 
| 276 | pmapROI [n].min [0] = atof(argv [++i]); | 
| 277 | pmapROI [n].min [1] = atof(argv [++i]); | 
| 278 | pmapROI [n].min [2] = atof(argv [++i]); | 
| 279 | pmapROI [n].max [0] = atof(argv [++i]); | 
| 280 | pmapROI [n].max [1] = atof(argv [++i]); | 
| 281 | pmapROI [n].max [2] = atof(argv [++i]); | 
| 282 |  | 
| 283 | for (j = 0; j < 3; j++) | 
| 284 | if (pmapROI [n].min [j] >= pmapROI [n].max [j]) | 
| 285 | error(USER, | 
| 286 | "invalid region of interest (swapped min/max?)"); | 
| 287 | } | 
| 288 | #endif | 
| 289 |  | 
| 290 | else if (!strcmp(argv [i] + 2, "pP")) { | 
| 291 | /* Global photon precomputation factor */ | 
| 292 | check(4, "f"); | 
| 293 | finalGather = atof(argv [++i]); | 
| 294 | if (finalGather <= 0 || finalGather > 1) | 
| 295 | error(USER, "global photon precomputation factor " | 
| 296 | "must be in range ]0, 1]"); | 
| 297 | } | 
| 298 |  | 
| 299 | else if (!strcmp(argv [i] + 2, "po") || | 
| 300 | !strcmp(argv [i] + 2, "pO")) { | 
| 301 | /* Photon port */ | 
| 302 | check(4, "s"); | 
| 303 |  | 
| 304 | if (ambincl != 1) { | 
| 305 | ambincl = 1; | 
| 306 | portLp = amblist; | 
| 307 | } | 
| 308 |  | 
| 309 | if (argv[i][3] == 'O') { | 
| 310 | /* Get port modifiers from file */ | 
| 311 | rval = wordfile(portLp, AMBLLEN-(portLp-amblist), | 
| 312 | getpath(argv [++i], getrlibpath(), R_OK)); | 
| 313 |  | 
| 314 | if (rval < 0) { | 
| 315 | sprintf(errmsg, "cannot open photon port file %s", | 
| 316 | argv [i]); | 
| 317 | error(SYSTEM, errmsg); | 
| 318 | } | 
| 319 |  | 
| 320 | portLp += rval; | 
| 321 | } | 
| 322 |  | 
| 323 | else { | 
| 324 | /* Append modifier to port list */ | 
| 325 | *portLp++ = argv [++i]; | 
| 326 | *portLp = NULL; | 
| 327 | } | 
| 328 | } | 
| 329 |  | 
| 330 | else if (!strcmp(argv [i] + 2, "pr")) { | 
| 331 | /* Random seed */ | 
| 332 | check(4, "i"); | 
| 333 | randSeed = atoi(argv [++i]); | 
| 334 | } | 
| 335 |  | 
| 336 | else if (!strcmp(argv [i] + 2, "ps") || | 
| 337 | !strcmp(argv [i] + 2, "pS")) { | 
| 338 | /* Antimatter sensor */ | 
| 339 | check(4, "s"); | 
| 340 |  | 
| 341 | if (argv[i][3] == 'S') { | 
| 342 | /* Get sensor modifiers from file */ | 
| 343 | rval = wordfile(sensLp, MAXSET-(sensLp-photonSensorList), | 
| 344 | getpath(argv [++i], getrlibpath(), R_OK)); | 
| 345 |  | 
| 346 | if (rval < 0) { | 
| 347 | sprintf(errmsg, "cannot open antimatter sensor file %s", | 
| 348 | argv [i]); | 
| 349 | error(SYSTEM, errmsg); | 
| 350 | } | 
| 351 |  | 
| 352 | sensLp += rval; | 
| 353 | } | 
| 354 |  | 
| 355 | else { | 
| 356 | /* Append modifier to sensor list */ | 
| 357 | *sensLp++ = argv [++i]; | 
| 358 | *sensLp = NULL; | 
| 359 | } | 
| 360 | } | 
| 361 |  | 
| 362 | else goto badopt; | 
| 363 | break; | 
| 364 |  | 
| 365 | case 'b': | 
| 366 | if (argv [i][2] == 'v') { | 
| 367 | /* Back face visibility */ | 
| 368 | check_bool(3, backvis); | 
| 369 | } | 
| 370 |  | 
| 371 | else goto badopt; | 
| 372 | break; | 
| 373 |  | 
| 374 | case 'd': /* Direct */ | 
| 375 | switch (argv [i][2]) { | 
| 376 | case 'p': /* PDF samples */ | 
| 377 | check(3, "f"); | 
| 378 | pdfSamples = atof(argv [++i]); | 
| 379 | break; | 
| 380 |  | 
| 381 | case 's': /* Source partition size ratio */ | 
| 382 | check(3, "f"); | 
| 383 | srcsizerat = atof(argv [++i]); | 
| 384 | break; | 
| 385 |  | 
| 386 | default: goto badopt; | 
| 387 | } | 
| 388 | break; | 
| 389 |  | 
| 390 | case 'e': /* Diagnostics file */ | 
| 391 | check(2, "s"); | 
| 392 | diagFile = argv [++i]; | 
| 393 | break; | 
| 394 |  | 
| 395 | case 'f': | 
| 396 | if (argv [i][2] == 'o') { | 
| 397 | /* Force overwrite */ | 
| 398 | check_bool(3, clobber); | 
| 399 | } | 
| 400 |  | 
| 401 | else goto badopt; | 
| 402 | break; | 
| 403 |  | 
| 404 | case 'm': /* Medium */ | 
| 405 | switch (argv[i][2]) { | 
| 406 | case 'e':        /* Eggs-tinction coefficient */ | 
| 407 | check(3, "fff"); | 
| 408 | setcolor(cextinction, atof(argv [i + 1]), | 
| 409 | atof(argv [i + 2]), atof(argv [i + 3])); | 
| 410 | i += 3; | 
| 411 | break; | 
| 412 |  | 
| 413 | case 'a':        /* Albedo */ | 
| 414 | check(3, "fff"); | 
| 415 | setcolor(salbedo, atof(argv [i + 1]), | 
| 416 | atof(argv [i + 2]), atof(argv [i + 3])); | 
| 417 | i += 3; | 
| 418 | break; | 
| 419 |  | 
| 420 | case 'g':        /* Scattering eccentricity */ | 
| 421 | check(3, "f"); | 
| 422 | seccg = atof(argv [++i]); | 
| 423 | break; | 
| 424 |  | 
| 425 | default: goto badopt; | 
| 426 | } | 
| 427 | break; | 
| 428 | #if NIX | 
| 429 | case 'n': /* Num parallel processes (NIX only) */ | 
| 430 | check(2, "i"); | 
| 431 | nproc = atoi(argv [++i]); | 
| 432 |  | 
| 433 | if (nproc > PMAP_MAXPROC) { | 
| 434 | nproc = PMAP_MAXPROC; | 
| 435 | sprintf(errmsg, "too many parallel processes, clamping to " | 
| 436 | "%d\n", nproc); | 
| 437 | error(WARNING, errmsg); | 
| 438 | } | 
| 439 | break; | 
| 440 | #endif | 
| 441 | case 't': /* Timer */ | 
| 442 | check(2, "i"); | 
| 443 | photonRepTime = atoi(argv [++i]); | 
| 444 | break; | 
| 445 |  | 
| 446 | case 'v':   /* Verbosity */ | 
| 447 | check_bool(2, verbose); | 
| 448 | break; | 
| 449 | #ifdef EVALDRC_HACK | 
| 450 | case 'A':   /* Angular source file */ | 
| 451 | check(2,"s"); | 
| 452 | angsrcfile = argv[++i]; | 
| 453 | break; | 
| 454 | #endif | 
| 455 | default: goto badopt; | 
| 456 | } | 
| 457 | } | 
| 458 |  | 
| 459 | /* Open diagnostics file */ | 
| 460 | if (diagFile) { | 
| 461 | if (!freopen(diagFile, "a", stderr)) quit(2); | 
| 462 | fprintf(stderr, "**************\n*** PID %5d: ", getpid()); | 
| 463 | printargs(argc, argv, stderr); | 
| 464 | putc('\n', stderr); | 
| 465 | fflush(stderr); | 
| 466 | } | 
| 467 |  | 
| 468 | #ifdef NICE | 
| 469 | /* Lower priority */ | 
| 470 | nice(NICE); | 
| 471 | #endif | 
| 472 |  | 
| 473 | if (octname == NULL) | 
| 474 | error(USER, "missing octree argument"); | 
| 475 |  | 
| 476 | /* Allocate photon maps and set parameters */ | 
| 477 | for (i = 0; i < NUM_PMAP_TYPES; i++) { | 
| 478 | setPmapParam(photonMaps + i, pmapParams + i); | 
| 479 |  | 
| 480 | /* Don't overwrite existing photon map unless clobbering enabled */ | 
| 481 | if (photonMaps [i] && !stat(photonMaps [i] -> fileName, &pmstat) && | 
| 482 | !clobber) { | 
| 483 | sprintf(errmsg, "photon map file %s exists, not overwritten", | 
| 484 | photonMaps [i] -> fileName); | 
| 485 | error(USER, errmsg); | 
| 486 | } | 
| 487 | } | 
| 488 |  | 
| 489 | for (i = 0; i < NUM_PMAP_TYPES && !photonMaps [i]; i++); | 
| 490 | if (i >= NUM_PMAP_TYPES) | 
| 491 | error(USER, "no photon maps specified"); | 
| 492 |  | 
| 493 | readoct(octname, loadflags, &thescene, NULL); | 
| 494 | #ifdef EVALDRC_HACK | 
| 495 | if (angsrcfile) | 
| 496 | readobj(angsrcfile);    /* load angular sources */ | 
| 497 | #endif | 
| 498 | nsceneobjs = nobjects; | 
| 499 |  | 
| 500 | /* Get sources */ | 
| 501 | marksources(); | 
| 502 |  | 
| 503 | /* Do forward pass and build photon maps */ | 
| 504 | if (contribPmap) | 
| 505 | /* Just build contrib pmap, ignore others */ | 
| 506 | distribPhotonContrib(contribPmap, nproc); | 
| 507 | else | 
| 508 | distribPhotons(photonMaps, nproc); | 
| 509 |  | 
| 510 | /* Save photon maps; no idea why GCC needs an explicit cast here... */ | 
| 511 | savePmaps((const PhotonMap**)photonMaps, argc, argv); | 
| 512 | cleanUpPmaps(photonMaps); | 
| 513 |  | 
| 514 | quit(0); | 
| 515 |  | 
| 516 | badopt: | 
| 517 | sprintf(errmsg, "command line error at '%s'", argv[i]); | 
| 518 | error(USER, errmsg); | 
| 519 |  | 
| 520 | #undef check | 
| 521 | #undef check_bool | 
| 522 | return 0; | 
| 523 | } |