diff --git a/pmapfilt.c b/pmapfilt.c index ae02150..13bb96b 100644 --- a/pmapfilt.c +++ b/pmapfilt.c @@ -1,349 +1,349 @@ /* ====================================================================== Photon map filter callbacks for nearest neighbour search Roland Schregle (roland.schregle@{hslu.ch, gmail.com}) (c) Lucerne University of Applied Sciences and Arts, supported by the Swiss National Science Foundation (SNSF #147053, "Daylight Redirecting Components") (c) Tokyo University of Science, supported by the JSPS Grants-in-Aid for Scientific Research (KAKENHI JP19KK0115, "Three-Dimensional Light Flow") ====================================================================== $Id: pmapfilt.c,v 1.2 2020/11/16 22:28:23 u-no-hoo Exp u-no-hoo $ */ #include "pmapfilt.h" #include "pmapdata.h" #include "random.h" #include "source.h" #include "otspecial.h" int filterPhoton (const void *rec, const void *state) /* Filter callback for photon kNN search */ { const Photon *photon = rec; const PhotonSearchFilterState *filtState = state; const PhotonMap *pmap = filtState -> pmap; /* Reject photon if normal faces away (ignored for volume photons) with * tolerance to account for perturbation; note photon normal is coded * in range [-127,127], hence we factor this in */ if ( filtState -> norm && DOT(filtState->norm, photon->norm) <= PMAP_NORM_TOL * 127 * frandom() ) return 0; if (isContribPmap(pmap)) { /* Lookup in contribution photon map; filter according to emitting * light source if contrib list set, else accept all */ if (pmap -> srcContrib) { OBJREC *srcMod; const int srcIdx = photonSrcIdx(pmap, photon); if (srcIdx < 0 || srcIdx >= nsources) error(INTERNAL, "invalid light source index in photon map"); srcMod = findmaterial(source [srcIdx].so); /* Reject photon if contributions from light source which emitted * it are not sought */ if (!lu_find(pmap -> srcContrib, srcMod -> oname) -> data) return 0; } /* Reject non-caustic photon if lookup for caustic contribs */ if (pmap -> lookupCaustic && !photon -> caustic) return 0; } /* Accept photon */ return 1; } -#ifdef PMAP_PHOTONFLOW +#ifdef PMAP_PATHFILT /* Length of key strings for photon path LUT (plus terminator) */ #define PMAP_PATHKEYLEN ((sizeof(PhotonPrimaryIdx) + 1 << 1) + 1) void initPhotonPaths (void *state) /* Lazily allocate and initialise photon path ID lookup table and * associate key buffer */ { PhotonMap *pmap = state; if (!pmap -> pathLUT) { /* Allocate and init photon path ID lookup table of same size as * search queue */ LUTAB initLUT = LU_SINIT(NULL, NULL); if (!(pmap -> pathLUT = malloc(sizeof(LUTAB)))) error(SYSTEM, "failed photon path lookup table allocation"); memcpy(pmap -> pathLUT, &initLUT, sizeof(initLUT)); if (!lu_init(pmap -> pathLUT, pmap -> squeue.len)) error(INTERNAL, "failed photon path lookup table init"); } if (!pmap -> pathLUTKeys) { /* Allocate key buffer of same size as search queue (+1 for * scratchpad at tail) */ unsigned k, maxKeys = pmap -> squeue.len + 1; pmap -> pathLUTKeys = (char**)calloc(maxKeys, sizeof(char*)); for (k = 0; k < maxKeys; k++) if ( !pmap -> pathLUTKeys || !(pmap -> pathLUTKeys [k] = (char*)malloc(PMAP_PATHKEYLEN)) ) error(SYSTEM, "failed photon path LUT key buffer allocation"); } /* Reset photon path ID key buffer */ pmap -> numPathLUTKeys = 0; } static char *photonPathKey (const Photon *photon, char *key) { /* Generate LUT key from photon path ID. Writes transposed hex string into specified key buffer. */ PhotonPrimaryIdx pathId1 = photon -> primary; unsigned char pathId2 = photon -> proc; char *kp = key; unsigned i; for ( i = sizeof(PhotonPrimaryIdx) << 1; i; *kp++ = (pathId1 & 0x0f) + 'A', pathId1 >>= 4, i-- ); for ( i = sizeof(unsigned char) << 1; i; *kp++ = (pathId2 & 0x0f) + 'A', pathId2 >>= 4, i-- ); *kp++ = '\0'; return key; } int checkPhotonPaths (const void *state) /* Run sanity check on photon path ID lookup table */ { const PhotonMap *pmap = state; const PhotonSearchQueue *squeue = &pmap -> squeue; const PhotonSearchQueueNode *squeueNode; const Photon *photon; const LUENT *lutEntry; unsigned squeueIdx; char key [PMAP_PATHKEYLEN]; if (!pmap -> pathLUT || !pmap -> pathLUTKeys) error(INTERNAL, "photon path lookup table not initialised"); for ( squeueIdx = 0, squeueNode = squeue -> node; squeueIdx < squeue -> tail; squeueIdx++, squeueNode++ ) { photon = getNearestPhoton(squeue, squeueNode -> idx); photonPathKey(photon, key); lutEntry = lu_find(pmap -> pathLUT, key); if (!lutEntry || !lutEntry -> key || strcmp(lutEntry -> key, key)) error(CONSISTENCY, "invalid key in photon path LUT check"); if ( !lutEntry -> data || (PhotonSearchQueueNode*)lutEntry -> data != squeueNode ) error(CONSISTENCY, "invalid data in photon path LUT check"); } return 0; } /* TODO: REPLACE pathLUTKeys SCRATCHPAD WITH LOCAL ARRAYS??? */ void **findPhotonPath (const void *rec, const void *state) /* Photon path callback for k-NN search to map photon path IDs to search * queue nodes via a lookup table. State points to the associated photon * map containing the path lookup table. Returns modifiable pointer to data * field of found LUT entry, which in turn points to the search queue node * for the corresponding record. If no entry exists for the path ID, NULL * is returned. */ { const Photon *photon = rec; const PhotonMap *pmap = state; char *key; LUENT *lutEntry; if (!pmap -> pathLUT || !pmap -> pathLUTKeys) error(INTERNAL, "photon path lookup table not initialised"); /* Generate key for photon's path and write into next free slot in key buffer (using it as scratchpad) */ key = photonPathKey( photon, pmap -> pathLUTKeys [pmap -> numPathLUTKeys] ); #ifdef PMAP_DEBUGPATHS printf("%s ", key); #endif /* Look up attribute for generated key, set last LUT entry in state */ if (!(lutEntry = lu_find(pmap -> pathLUT, key))) /* Outta mammaries */ error(SYSTEM, "failed photon path lookup entry allocation"); return (void**)(lutEntry -> data ? &lutEntry -> data : NULL); } void addPhotonPath (const void *rec, void *data, void *state) /* Photon path callback for k-NN search to add photon path IDs to lookup table entries. State points to the associated photon map containing the path lookup table. The new lookup table entry is initialised with the specified data pointer */ { const Photon *photon = rec; PhotonMap *pmap = state; char *key; LUENT *lutEntry; if (!pmap -> pathLUT || !pmap -> pathLUTKeys) error(INTERNAL, "photon path lookup table not initialised"); /* Generate key for photon's path and write into next free slot in key buffer */ key = photonPathKey( photon, pmap -> pathLUTKeys [pmap -> numPathLUTKeys] ); /* Find free LUT entry for generated key */ if (!(lutEntry = lu_find(pmap -> pathLUT, key))) /* Outta mammaries */ error(SYSTEM, "failed photon path lookup entry allocation"); if (lutEntry -> data) /* Occupied */ error(INTERNAL, "attempt to overwrite photon path lookup entry"); #ifdef PMAP_DEBUGPATHS printf("%s add\n", key); #endif /* Set data and key fields, advance key buffer tail */ lutEntry -> data = data; lutEntry -> key = pmap -> pathLUTKeys [pmap -> numPathLUTKeys]; if (pmap -> numPathLUTKeys > pmap -> squeue.tail) /* Number of keys (and distinct path IDs) can never exceed the number of photons currently in the search queue (+1 for scratchpad) */ error(INTERNAL, "photon path lookup table key overflow"); else pmap -> numPathLUTKeys++; } static char emptyKey = '\0'; void deletePhotonPath (const void *rec, void *state) /* Photon path callback for k-NN search to delete photon path IDs from lookup table. State points to the associated photon map containing the path ID lookup table. */ { const Photon *photon = rec; PhotonMap *pmap = state; LUENT *lutEntry; char *delKey, *relocKey; if (!pmap -> pathLUT || !pmap -> pathLUTKeys) error(INTERNAL, "photon path lookup table not initialised"); /* Generate key for photon's path and write into scratchpad at key buffer tail (will be overwritten) */ delKey = photonPathKey( photon, pmap -> pathLUTKeys [pmap -> numPathLUTKeys] ); #ifdef PMAP_DEBUGPATHS printf("%s del\n", delKey); #endif /* Find photon's LUT entry, check if valid, and get its key buffer slot */ lutEntry = lu_find(pmap -> pathLUT, delKey); if (!lutEntry || !lutEntry -> key || !lutEntry -> data) error(CONSISTENCY, "attempt to delete empty photon path LUT entry"); /* Delete photon LUT entry */ lu_delete(pmap -> pathLUT, delKey); delKey = lutEntry -> key; lutEntry -> key = &emptyKey; /* ??? */ /* Decrement key buffer tail and get last valid key */ relocKey = pmap -> pathLUTKeys [--pmap -> numPathLUTKeys]; if (delKey != relocKey) { /* Reclaim deleted photon's key buffer slot by overwriting with last valid key */ memcpy(delKey, relocKey, PMAP_PATHKEYLEN); relocKey = delKey; #ifdef PMAP_DEBUGPATHS printf("%s reloc\n", relocKey); #endif /* Update the LUT entry owning the relocated key to point to its new position in the overwritten slot, again checking for validity */ lutEntry = lu_find(pmap -> pathLUT, relocKey); if (!lutEntry || !lutEntry -> key || !lutEntry -> data) error(CONSISTENCY, "attempt to delete empty photon path LUT entry"); lutEntry -> key = relocKey; } } int clearPhotonPath (const LUENT *lutEntry, void *lut) /* Clear entry in photon path ID lookup table */ { #ifdef PMAP_DEBUGPATHS printf("%s clr\n", lutEntry -> key); #endif lu_delete(lut, lutEntry -> key); /* Apologies to Don Gregorio for abusing his LUT here... */ ((LUENT*)lutEntry) -> key = &emptyKey; return 0; } void resetPhotonPaths (void *state) /* Reset (clear) all entries in photon path ID lookup table */ { PhotonMap *pmap = state; if (!pmap -> pathLUT) error(INTERNAL, "photon path lookup table not initialised"); lu_doall(pmap -> pathLUT, clearPhotonPath, pmap -> pathLUT); /* Reset photon path ID key buffer */ pmap -> numPathLUTKeys = 0; } -#endif /* PMAP_PHOTONFLOW */ +#endif /* PMAP_PATHFILT */ diff --git a/pmapfilt.h b/pmapfilt.h index 6b3da7e..69f36c4 100644 --- a/pmapfilt.h +++ b/pmapfilt.h @@ -1,117 +1,117 @@ /* ====================================================================== Photon map filter callbacks for nearest neighbour search Roland Schregle (roland.schregle@{hslu.ch, gmail.com}) (c) Lucerne University of Applied Sciences and Arts, supported by the Swiss National Science Foundation (SNSF #147053, "Daylight Redirecting Components") (c) Tokyo University of Science, supported by the JSPS Grants-in-Aid for Scientific Research (KAKENHI JP19KK0115, "Three-Dimensional Light Flow") ====================================================================== $Id$ */ #ifndef PMAP_FILT_H #define PMAP_FILT_H #include "lookup.h" /* Tolerance for photon normal check during lookups */ #define PMAP_NORM_TOL 0.02 /* Forward declarations */ struct PhotonMap; /* Generic callback function container with context/state data to filter photons during k-NN search */ typedef struct { int (*filtFunc)(const void *rec, const void *state); void *state; } PhotonSearchFilterCallback; /* State data for PhotonSearchFilterCallback, used by filterPhoton() */ typedef struct { const struct PhotonMap *pmap; const float *norm; } PhotonSearchFilterState; #ifdef PMAP_OOC /* Interface to out-of-core photon map routines */ typedef PhotonSearchFilterCallback OOC_SearchFilterCallback; typedef PhotonSearchFilterState OOC_SearchFilterState; #else /* Interface to in-core kd-tree photon map routines */ typedef PhotonSearchFilterCallback kdT_SearchFilterCallback; typedef PhotonSearchFilterState kdT_SearchFilterState; #endif int filterPhoton (const void *rec, const void *state); /* Filter callback for photon kNN search */ - #ifdef PMAP_PHOTONFLOW + #ifdef PMAP_PATHFILT /* Generic callback function container with context/state data to maintain table of photon attributes and exclude possible duplicates during k-NN search */ typedef struct { void **(*findFunc)(const void *rec, const void *state); void (*addFunc)(const void *rec, void *data, void *state); void (*delFunc)(const void *rec, void *state); int (*checkFunc)(const void *state); void *state; } PhotonSearchAttribCallback; #ifdef PMAP_OOC /* Interface to out-of-core photon map routines */ typedef PhotonSearchAttribCallback OOC_SearchAttribCallback; #else /* Interface to in-core kd-tree photon map routines */ typedef PhotonSearchAttribCallback kdT_SearchAttribCallback; #endif void initPhotonPaths (void *state); /* Lazily allocate and initialise photon path ID lookup table and * associate key buffer */ int checkPhotonPaths (const void *state); /* Run sanity check on photon path ID lookup table */ void **findPhotonPath (const void *rec, const void *state); /* Photon path callback for k-NN search to map photon path IDs to * search queue nodes via a lookup table. State points to the * associated photon map containing the path lookup table. Returns * modifiable pointer to data field of found LUT entry, which in turn * points to the search queue node for the corresponding record. If * no entry exists for the path ID, NULL is returned. */ void addPhotonPath (const void *rec, void *data, void *state); /* Photon path callback for k-NN search to add photon path IDs to lookup table entries. State points to the associated photon map containing the path lookup table. The new lookup table entry is initialised with the specified data pointer */ void deletePhotonPath (const void *rec, void *state); /* Photon path callback for k-NN search to delete photon path IDs from lookup table. State points to the associated photon map containing the path ID lookup table. */ int clearPhotonPath (const LUENT *lutEntry, void *lut); /* Clear entry in photon path ID lookup table */ void resetPhotonPaths (void *state); /* Reset (clear) all entries in photon path ID lookup table */ #else #ifdef PMAP_OOC typedef void OOC_SearchAttribCallback; #else typedef void kdT_SearchAttribCallback; #endif - #endif /* PMAP_PHOTONFLOW */ + #endif /* PMAP_PATHFILT */ #endif