--- ray/src/rt/pmap.c 2016/05/17 17:39:47 2.11 +++ ray/src/rt/pmap.c 2018/03/20 19:55:33 2.14 @@ -1,7 +1,8 @@ #ifndef lint -static const char RCSid[] = "$Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $"; +static const char RCSid[] = "$Id: pmap.c,v 2.14 2018/03/20 19:55:33 rschregle Exp $"; #endif + /* ====================================================================== Photon map main module @@ -12,11 +13,10 @@ static const char RCSid[] = "$Id: pmap.c,v 2.11 2016/0 supported by the Swiss National Science Foundation (SNSF, #147053) ====================================================================== - $Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $ + $Id: pmap.c,v 2.14 2018/03/20 19:55:33 rschregle Exp $ */ - #include "pmap.h" #include "pmapmat.h" #include "pmapsrc.h" @@ -26,80 +26,13 @@ static const char RCSid[] = "$Id: pmap.c,v 2.11 2016/0 #include "pmapdiag.h" #include "otypes.h" #include -#include -#include -#include +#if NIX + #include + #include + #include +#endif -#define PMAP_REV "$Revision: 2.11 $" - -extern char *octname; - - - -/* Photon map lookup functions per type */ -void (*pmapLookup [NUM_PMAP_TYPES])(PhotonMap*, RAY*, COLOR) = { - photonDensity, photonPreCompDensity, photonDensity, volumePhotonDensity, - photonDensity, NULL -}; - - - -void colorNorm (COLOR c) -/* Normalise colour channels to average of 1 */ -{ - const float avg = colorAvg(c); - - if (!avg) - return; - - c [0] /= avg; - c [1] /= avg; - c [2] /= avg; -} - - - -void loadPmaps (PhotonMap **pmaps, const PhotonMapParams *parm) -{ - unsigned t; - struct stat octstat, pmstat; - PhotonMap *pm; - PhotonMapType type; - - for (t = 0; t < NUM_PMAP_TYPES; t++) - if (setPmapParam(&pm, parm + t)) { - /* Check if photon map newer than octree */ - if (pm -> fileName && octname && - !stat(pm -> fileName, &pmstat) && !stat(octname, &octstat) && - octstat.st_mtime > pmstat.st_mtime) { - sprintf(errmsg, "photon map in file %s may be stale", - pm -> fileName); - error(USER, errmsg); - } - - /* Load photon map from file and get its type */ - if ((type = loadPhotonMap(pm, pm -> fileName)) == PMAP_TYPE_NONE) - error(USER, "failed loading photon map"); - - /* Assign to appropriate photon map type (deleting previously - * loaded photon map of same type if necessary) */ - if (pmaps [type]) { - deletePhotons(pmaps [type]); - free(pmaps [type]); - } - pmaps [type] = pm; - - /* Check for invalid density estimate bandwidth */ - if (pm -> maxGather > pm -> numPhotons) { - error(WARNING, "adjusting density estimate bandwidth"); - pm -> minGather = pm -> maxGather = pm -> numPhotons; - } - } -} - - - void savePmaps (const PhotonMap **pmaps, int argc, char **argv) { unsigned t; @@ -111,20 +44,6 @@ void savePmaps (const PhotonMap **pmaps, int argc, cha } - -void cleanUpPmaps (PhotonMap **pmaps) -{ - unsigned t; - - for (t = 0; t < NUM_PMAP_TYPES; t++) { - if (pmaps [t]) { - deletePhotons(pmaps [t]); - free(pmaps [t]); - } - } -} - - static int photonParticipate (RAY *ray) /* Trace photon through participating medium. Returns 1 if passed through, @@ -209,7 +128,15 @@ void tracePhoton (RAY *ray) /* Follow photon as it bounces around... */ { long mod; - OBJREC* mat; + OBJREC *mat, *port = NULL; + + if (!ray -> parent) { + /* !!! PHOTON PORT REJECTION SAMPLING HACK: get photon port for + * !!! primary ray from ray -> ro, then reset the latter to NULL so + * !!! as not to interfere with localhit() */ + port = ray -> ro; + ray -> ro = NULL; + } if (ray -> rlvl > photonMaxBounce) { #ifdef PMAP_RUNAWAY_WARN @@ -220,10 +147,26 @@ void tracePhoton (RAY *ray) if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray)) return; - + if (localhit(ray, &thescene)) { mod = ray -> ro -> omod; - + + if (port && ray -> ro != port) { + /* !!! PHOTON PORT REJECTION SAMPLING HACK !!! + * Terminate photon if emitted from port without intersecting it; + * this can happen when the port's partitions extend beyond its + * actual geometry, e.g. with polygons. Since the total flux + * relayed by the port is based on the (in this case) larger + * partition area, it is overestimated; terminating these photons + * constitutes rejection sampling and thereby compensates any bias + * incurred by the overestimated flux. */ +#ifdef PMAP_PORTREJECT_WARN + sprintf(errmsg, "photon outside port %s", ray -> ro -> oname); + error(WARNING, errmsg); +#endif + return; + } + if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) { /* Transfer ray if modifier is VOID or clipped within antimatta */ RAY tray; @@ -255,11 +198,14 @@ static void preComputeGlobal (PhotonMap *pmap) repComplete = numPreComp = finalGather * pmap -> numPhotons; - if (photonRepTime) { - sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n", + if (verbose) { + sprintf(errmsg, + "\nPrecomputing irradiance for %ld global photons\n", numPreComp); eputs(errmsg); +#if NIX fflush(stderr); +#endif } /* Copy photon map for precomputed photons */ @@ -286,7 +232,7 @@ static void preComputeGlobal (PhotonMap *pmap) for (i = 0; i < numPreComp; i++) { /* Get random photon from stratified distribution in source heap to - * avoid duplicates and clutering */ + * avoid duplicates and clustering */ pIdx = firstPhoton(pmap) + (unsigned long)((i + pmapRandom(pmap -> randState)) / finalGather); @@ -324,9 +270,11 @@ static void preComputeGlobal (PhotonMap *pmap) deletePhotons(pmap); memcpy(pmap, &nuPmap, sizeof(PhotonMap)); - if (photonRepTime) { - eputs("Rebuilding precomputed photon map...\n"); + if (verbose) { + eputs("\nRebuilding precomputed photon map\n"); +#if NIX fflush(stderr); +#endif } /* Rebuild underlying data structure, destroying heap */ @@ -345,7 +293,7 @@ typedef struct { void distribPhotons (PhotonMap **pmaps, unsigned numProc) { EmissionMap emap; - char errmsg2 [128], shmFname [255]; + char errmsg2 [128], shmFname [PMAP_TMPFNLEN]; unsigned t, srcIdx, proc; double totalFlux = 0; int shmFile, stat, pid; @@ -377,41 +325,51 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr initPhotonHeap(pmaps [t]); /* Per-subprocess target count */ pmaps [t] -> distribTarget /= numProc; + + if (!pmaps [t] -> distribTarget) + error(INTERNAL, "no photons to distribute in distribPhotons"); } initPhotonEmissionFuncs(); initPhotonScatterFuncs(); - /* Get photon ports if specified */ - if (ambincl == 1) - getPhotonPorts(); + /* Get photon ports from modifier list */ + getPhotonPorts(photonPortList); /* Get photon sensor modifiers */ getPhotonSensors(photonSensorList); +#if NIX /* Set up shared mem for photon counters (zeroed by ftruncate) */ -#if 0 - snprintf(shmFname, 255, PMAP_SHMFNAME, getpid()); - shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); -#else - strcpy(shmFname, PMAP_SHMFNAME); + strcpy(shmFname, PMAP_TMPFNAME); shmFile = mkstemp(shmFname); -#endif - if (shmFile < 0) - error(SYSTEM, "failed opening shared memory file in distribPhotons"); + if (shmFile < 0 || ftruncate(shmFile, sizeof(*photonCnt)) < 0) + error(SYSTEM, "failed shared mem init in distribPhotons"); - if (ftruncate(shmFile, sizeof(*photonCnt)) < 0) - error(SYSTEM, "failed setting shared memory size in distribPhotons"); - photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE, MAP_SHARED, shmFile, 0); if (photonCnt == MAP_FAILED) - error(SYSTEM, "failed mapping shared memory in distribPhotons"); + error(SYSTEM, "failed mapping shared memory in distribPhotons"); +#else + /* Allocate photon counters statically on Windoze */ + if (!(photonCnt = malloc(sizeof(PhotonCnt)))) + error(SYSTEM, "failed trivial malloc in distribPhotons"); + photonCnt -> numEmitted = photonCnt -> numComplete = 0; +#endif /* NIX */ - if (photonRepTime) - eputs("\n"); + if (verbose) { + sprintf(errmsg, "\nIntegrating flux from %d sources", nsources); + + if (photonPorts) { + sprintf(errmsg2, " via %d ports", numPhotonPorts); + strcat(errmsg, errmsg2); + } + + strcat(errmsg, "\n"); + eputs(errmsg); + } /* =================================================================== * FLUX INTEGRATION - Get total photon flux from light sources @@ -425,20 +383,22 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr : NULL; photonPartition [emap.src -> so -> otype] (&emap); - if (photonRepTime) { - sprintf(errmsg, "Integrating flux from source %s ", + if (verbose) { + sprintf(errmsg, "\tIntegrating flux from source %s ", source [srcIdx].so -> oname); - + if (emap.port) { sprintf(errmsg2, "via port %s ", photonPorts [portCnt].so -> oname); strcat(errmsg, errmsg2); } - - sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions); + + sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions); strcat(errmsg, errmsg2); eputs(errmsg); +#if NIX fflush(stderr); +#endif } for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions; @@ -453,12 +413,25 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr if (totalFlux < FTINY) error(USER, "zero flux from light sources"); + + /* Record start time for progress reports */ + repStartTime = time(NULL); + if (verbose) { + sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc); + eputs(errmsg); + } + /* MAIN LOOP */ for (proc = 0; proc < numProc; proc++) { +#if NIX if (!(pid = fork())) { - /* SUBPROCESS ENTERS HERE. - All opened and memory mapped files are inherited */ + /* SUBPROCESS ENTERS HERE; open and mmapped files inherited */ +#else + if (1) { + /* No subprocess under Windoze */ +#endif + /* Local photon counters for this subprocess */ unsigned passCnt = 0, prePassCnt = 0; unsigned long lastNumPhotons [NUM_PMAP_TYPES]; unsigned long localNumEmitted = 0; /* Num photons emitted by this @@ -466,11 +439,11 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr /* Seed RNGs from PID for decorellated photon distribution */ pmapSeed(randSeed + proc, partState); - pmapSeed(randSeed + proc, emitState); - pmapSeed(randSeed + proc, cntState); - pmapSeed(randSeed + proc, mediumState); - pmapSeed(randSeed + proc, scatterState); - pmapSeed(randSeed + proc, rouletteState); + pmapSeed(randSeed + (proc + 1) % numProc, emitState); + pmapSeed(randSeed + (proc + 2) % numProc, cntState); + pmapSeed(randSeed + (proc + 3) % numProc, mediumState); + pmapSeed(randSeed + (proc + 4) % numProc, scatterState); + pmapSeed(randSeed + (proc + 5) % numProc, rouletteState); for (t = 0; t < NUM_PMAP_TYPES; t++) lastNumPhotons [t] = 0; @@ -491,9 +464,7 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr * iterations; make it clear to user which photon maps are * missing so (s)he can check geometry and materials */ if (++prePassCnt > maxPreDistrib) { - sprintf(errmsg, - "proc %d, source %s: too many prepasses", - proc, source [srcIdx].so -> oname); + sprintf(errmsg, "proc %d: too many prepasses", proc); for (t = 0; t < NUM_PMAP_TYPES; t++) if (pmaps [t] && !pmaps [t] -> numPhotons) { @@ -565,7 +536,7 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr break; } - /* Update shared completion counter for prog.report by parent */ + /* Update shared completion counter for progreport by parent */ photonCnt -> numComplete += numEmit; /* PHOTON DISTRIBUTION LOOP */ @@ -578,25 +549,29 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr ? photonPorts + portCnt : NULL; photonPartition [emap.src -> so -> otype] (&emap); - if (photonRepTime && !proc) { + if (verbose && !proc) { + /* Output from subproc 0 only to avoid race condition + * on console I/O */ if (!passCnt) - sprintf(errmsg, "PREPASS %d on source %s ", + sprintf(errmsg, "\tPREPASS %d on source %s ", prePassCnt, source [srcIdx].so -> oname); else - sprintf(errmsg, "MAIN PASS on source %s ", + sprintf(errmsg, "\tMAIN PASS on source %s ", source [srcIdx].so -> oname); - + if (emap.port) { sprintf(errmsg2, "via port %s ", photonPorts [portCnt].so -> oname); strcat(errmsg, errmsg2); } - + sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions); strcat(errmsg, errmsg2); eputs(errmsg); +#if NIX fflush(stderr); +#endif } for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions; @@ -611,8 +586,7 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr /* Number of photons to emit from ziss partishunn -- * proportional to flux; photon ray weight and scalar - * flux are uniform (the latter only varying in RGB). - * */ + * flux are uniform (latter only varying in RGB). */ partNumEmit = numEmit * colorAvg(emap.partFlux) / totalFlux; partEmitCnt = (unsigned long)partNumEmit; @@ -633,9 +607,17 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr /* Emit photon based on PDF and trace through scene * until absorbed/leaked */ emitPhoton(&emap, &photonRay); +#if 1 + if (emap.port) + /* !!! PHOTON PORT REJECTION SAMPLING HACK: set + * !!! photon port as fake hit object for + * !!! primary ray to check for intersection in + * !!! tracePhoton() */ + photonRay.ro = emap.port -> so; +#endif tracePhoton(&photonRay); } - + /* Update shared global photon count for each pmap */ for (t = 0; t < NUM_PMAP_TYPES; t++) if (pmaps [t]) { @@ -643,6 +625,15 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr pmaps [t] -> numPhotons - lastNumPhotons [t]; lastNumPhotons [t] = pmaps [t] -> numPhotons; } +#if !NIX + /* Synchronous progress report on Windoze */ + if (!proc && photonRepTime > 0 && + time(NULL) >= repLastTime + photonRepTime) { + repEmitted = repProgress = photonCnt -> numEmitted; + repComplete = photonCnt -> numComplete; + pmapDistribReport(); + } +#endif } portCnt++; @@ -658,55 +649,40 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr break; } - if (t >= NUM_PMAP_TYPES) { + if (t >= NUM_PMAP_TYPES) /* No empty photon maps found; now do pass 2 */ passCnt++; -#if 0 - if (photonRepTime) - eputs("\n"); -#endif - } } while (passCnt < 2); - /* Unmap shared photon counters */ -#if 0 - munmap(photonCnt, sizeof(*photonCnt)); - close(shmFile); -#endif - - /* Flush heap buffa for every pmap one final time; this is required - * to prevent data corruption! */ + /* Flush heap buffa for every pmap one final time; + * avoids potential data corruption! */ for (t = 0; t < NUM_PMAP_TYPES; t++) if (pmaps [t]) { -#if 0 - eputs("Final flush\n"); -#endif flushPhotonHeap(pmaps [t]); - fclose(pmaps [t] -> heap); + /* Heap file closed automatically on exit + fclose(pmaps [t] -> heap); */ #ifdef DEBUG_PMAP - sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(), + sprintf(errmsg, "Proc %d: total %ld photons\n", proc, pmaps [t] -> numPhotons); eputs(errmsg); #endif } - +#if NIX + /* Terminate subprocess */ exit(0); +#endif } else if (pid < 0) error(SYSTEM, "failed to fork subprocess in distribPhotons"); } +#if NIX /* PARENT PROCESS CONTINUES HERE */ - /* Record start time and enable progress report signal handler */ - repStartTime = time(NULL); #ifdef SIGCONT + /* Enable progress report signal handler */ signal(SIGCONT, pmapDistribReport); -#endif - - if (photonRepTime) - eputs("\n"); - - /* Wait for subprocesses to complete while reporting progress */ +#endif + /* Wait for subprocesses complete while reporting progress */ proc = numProc; while (proc) { while (waitpid(-1, &stat, WNOHANG) > 0) { @@ -719,21 +695,19 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr /* Nod off for a bit and update progress */ sleep(1); - /* Update progress report from shared subprocess counters */ + + /* Asynchronous progress report from shared subprocess counters */ repEmitted = repProgress = photonCnt -> numEmitted; - repComplete = photonCnt -> numComplete; + repComplete = photonCnt -> numComplete; + repProgress = repComplete = 0; for (t = 0; t < NUM_PMAP_TYPES; t++) if ((pm = pmaps [t])) { -#if 0 - /* Get photon count from heapfile size for progress update */ - fseek(pm -> heap, 0, SEEK_END); - pm -> numPhotons = ftell(pm -> heap) / sizeof(Photon); */ -#else /* Get global photon count from shmem updated by subprocs */ - pm -> numPhotons = photonCnt -> numPhotons [t]; -#endif + repProgress += pm -> numPhotons = photonCnt -> numPhotons [t]; + repComplete += pm -> distribTarget; } + repComplete *= numProc; if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime) pmapDistribReport(); @@ -741,187 +715,52 @@ void distribPhotons (PhotonMap **pmaps, unsigned numPr else signal(SIGCONT, pmapDistribReport); #endif } +#endif /* NIX */ /* =================================================================== * POST-DISTRIBUTION - Set photon flux and build data struct for photon * storage, etc. * =================================================================== */ #ifdef SIGCONT + /* Reset signal handler */ signal(SIGCONT, SIG_DFL); #endif free(emap.samples); - /* Set photon flux (repProgress is total num emitted) */ + /* Set photon flux */ totalFlux /= photonCnt -> numEmitted; - +#if NIX /* Photon counters no longer needed, unmap shared memory */ munmap(photonCnt, sizeof(*photonCnt)); close(shmFile); -#if 0 - shm_unlink(shmFname); -#else unlink(shmFname); +#else + free(photonCnt); #endif - + if (verbose) + eputs("\n"); + for (t = 0; t < NUM_PMAP_TYPES; t++) if (pmaps [t]) { - if (photonRepTime) { - sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]); + if (verbose) { + sprintf(errmsg, "Building %s photon map\n", pmapName [t]); eputs(errmsg); +#if NIX fflush(stderr); +#endif } /* Build underlying data structure; heap is destroyed */ buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc); } - + /* Precompute photon irradiance if necessary */ - if (preCompPmap) + if (preCompPmap) { + if (verbose) + eputs("\n"); preComputeGlobal(preCompPmap); -} - - - -void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad) -/* Photon density estimate. Returns irradiance at ray -> rop. */ -{ - unsigned i; - float r; - COLOR flux; - Photon *photon; - const PhotonSearchQueueNode *sqn; - - setcolor(irrad, 0, 0, 0); - - if (!pmap -> maxGather) - return; - - /* Ignore sources */ - if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype)) - return; - - findPhotons(pmap, ray); + } - /* Need at least 2 photons */ - if (pmap -> squeue.tail < 2) { -#ifdef PMAP_NONEFOUND - sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)", - ray -> ro ? ray -> ro -> oname : "", - ray -> rop [0], ray -> rop [1], ray -> rop [2]); - error(WARNING, errmsg); -#endif - - return; - } - - if (pmap -> minGather == pmap -> maxGather) { - /* No bias compensation. Just do a plain vanilla estimate */ - sqn = pmap -> squeue.node + 1; - - /* Average radius between furthest two photons to improve accuracy */ - r = max(sqn -> dist2, (sqn + 1) -> dist2); - r = 0.25 * (pmap -> maxDist2 + r + 2 * sqrt(pmap -> maxDist2 * r)); - - /* Skip the extra photon */ - for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) { - photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); - getPhotonFlux(photon, flux); -#ifdef PMAP_EPANECHNIKOV - /* Apply Epanechnikov kernel to photon flux based on photon dist */ - scalecolor(flux, 2 * (1 - sqn -> dist2 / r)); -#endif - addcolor(irrad, flux); - } - - /* Divide by search area PI * r^2, 1 / PI required as ambient - normalisation factor */ - scalecolor(irrad, 1 / (PI * PI * r)); - - return; - } - else - /* Apply bias compensation to density estimate */ - biasComp(pmap, irrad); -} - - - -void photonPreCompDensity (PhotonMap *pmap, RAY *r, COLOR irrad) -/* Returns precomputed photon density estimate at ray -> rop. */ -{ - Photon p; - - setcolor(irrad, 0, 0, 0); - - /* Ignore sources */ - if (r -> ro && islight(objptr(r -> ro -> omod) -> otype)) - return; - - find1Photon(preCompPmap, r, &p); - getPhotonFlux(&p, irrad); -} - - - -void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad) -/* Photon volume density estimate. Returns irradiance at ray -> rop. */ -{ - unsigned i; - float r, gecc2, ph; - COLOR flux; - Photon *photon; - const PhotonSearchQueueNode *sqn; - - setcolor(irrad, 0, 0, 0); - - if (!pmap -> maxGather) - return; - - findPhotons(pmap, ray); - - /* Need at least 2 photons */ - if (pmap -> squeue.tail < 2) - return; - -#if 0 - /* Volume biascomp disabled (probably redundant) */ - if (pmap -> minGather == pmap -> maxGather) -#endif - { - /* No bias compensation. Just do a plain vanilla estimate */ - gecc2 = ray -> gecc * ray -> gecc; - sqn = pmap -> squeue.node + 1; - - /* Average radius between furthest two photons to improve accuracy */ - r = max(sqn -> dist2, (sqn + 1) -> dist2); - r = 0.25 * (pmap -> maxDist2 + r + 2 * sqrt(pmap -> maxDist2 * r)); - - /* Skip the extra photon */ - for (i = 1; i < pmap -> squeue.tail; i++, sqn++) { - photon = getNearestPhoton(&pmap -> squeue, sqn -> idx); - - /* Compute phase function for inscattering from photon */ - if (gecc2 <= FTINY) - ph = 1; - else { - ph = DOT(ray -> rdir, photon -> norm) / 127; - ph = 1 + gecc2 - 2 * ray -> gecc * ph; - ph = (1 - gecc2) / (ph * sqrt(ph)); - } - - getPhotonFlux(photon, flux); - scalecolor(flux, ph); - addcolor(irrad, flux); - } - - /* Divide by search volume 4 / 3 * PI * r^3 and phase function - normalization factor 1 / (4 * PI) */ - scalecolor(irrad, 3 / (16 * PI * PI * r * sqrt(r))); - return; - } -#if 0 - else - /* Apply bias compensation to density estimate */ - volumeBiasComp(pmap, ray, irrad); -#endif + if (verbose) + eputs("\n"); }