Page MenuHomec4science

pmapooc.c
No OneTemporary

File Metadata

Created
Sat, May 4, 22:33

pmapooc.c

/*
======================================================================
Photon map interface to out-of-core octree
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",
SNSF #179067, "Light Fields for Spatio-Temporal Glare Assessment")
(c) Tokyo University of Science,
supported by the JSPS Grants-in-Aid for Scientific Research
(KAKENHI JP19KK0115, "Three-Dimensional Light Flow")
======================================================================
$Id: pmapooc.c,v 1.7 2021/03/22 23:00:00 rschregle Exp $
*/
#include "pmapdata.h" /* Includes pmapooc.h */
#include "source.h"
#include "otspecial.h"
#include "oocsort.h"
#include "oocbuild.h"
#include "pmcontribsort.h"
/* PHOTON MAP BUILD ROUTINES ------------------------------------------ */
/* Returns photon position as sorting key for OOC_Octree & friends
* (notably for Morton code generation).
* !!! XXX: Uses type conversion from float via TEMPORARY storage;
* !!! THIS IS NOT THREAD SAFE!
* !!! RETURNED KEY PERSISTS ONLY IF COPIED BEFORE NEXT CALL! */
RREAL *OOC_PhotonKey (const void *p)
{
static FVECT photonPos; /* Temp storage for type conversion */
VCOPY(photonPos, ((Photon*)p) -> pos);
return photonPos;
}
#ifdef DEBUG_OOC
static void OOC_CheckKeys (FILE *file, const OOC_Octree *oct)
{
Photon p, lastp;
RREAL *key;
MortonIdx zIdx, lastzIdx = 0;
rewind(file);
memset(&lastp, 0, sizeof(lastp));
while (fread(&p, sizeof(p), 1, file) > 0) {
key = OOC_PhotonKey(&p);
zIdx = OOC_KEY2MORTON(key, oct);
if (zIdx < lastzIdx)
error(INTERNAL, "photons not sorted");
if (zIdx == lastzIdx) {
sprintf(errmsg, "identical key %021ld "
"for [%.9f, %.9f, %.9f]\tand [%.9f, %.9f, %.9f]",
zIdx, lastp.pos [0], lastp.pos [1], lastp.pos [2],
p.pos [0], p.pos [1], p.pos [2]
);
error(WARNING, errmsg);
}
lastzIdx = zIdx;
memcpy(&lastp, &p, sizeof(p));
}
}
#endif
void OOC_BuildPhotonMap (struct PhotonMap *pmap, unsigned numProc)
{
FILE *leafFile;
char *leafFname;
FVECT d, octOrg;
int i;
RREAL octSize = 0;
/* Determine octree size and origin from pmap extent and init octree */
VCOPY(octOrg, pmap -> minPos);
VSUB(d, pmap -> maxPos, pmap -> minPos);
for (i = 0; i < 3; i++)
if (octSize < d [i])
octSize = d [i];
if (octSize < FTINY)
error(INTERNAL, "zero octree size in OOC_BuildPhotonMap");
/* Derive leaf filename from photon map and open file */
leafFname = malloc(
strlen(pmap -> fileName) + strlen(PMAP_OOC_LEAFSUFFIX) + 1
);
if (!leafFname)
error(SYSTEM, "failed leaf filename alloc in OOC_BuildPhotonMap");
strcpy(leafFname, pmap -> fileName);
strcat(leafFname, PMAP_OOC_LEAFSUFFIX);
if (!(leafFile = fopen(leafFname, "w+b")))
error(SYSTEM, "failed to open leaf file in OOC_BuildPhotonMap");
#ifdef DEBUG_OOC
eputs("Sorting photons by Morton code...\n");
#endif
/* Sort photons in heapfile by Morton code and write to leaf file;
redirect to contrib sorting routine if contrib child pmap and
we have precomputed contributions, else we need a regular sort
before we can precompute */
if (isContribChildPmap(pmap) && pmap -> preCompContrib
? contribPhotonSort(pmap, leafFile, octOrg, octSize,
PMAP_OOC_NUMBLK, PMAP_OOC_BLKSIZE, numProc
)
: OOC_Sort(pmap -> heap, leafFile, PMAP_OOC_NUMBLK, PMAP_OOC_BLKSIZE,
numProc, sizeof(Photon), octOrg, octSize, OOC_PhotonKey
)
)
error(INTERNAL, "failed out-of-core photon sort in OOC_BuildPhotonMap");
/* Init and build octree */
OOC_Init(&pmap -> store, sizeof(Photon), octOrg, octSize, OOC_PhotonKey,
leafFile, leafFname
);
#ifdef DEBUG_OOC
eputs("Checking leaf file consistency...\n");
OOC_CheckKeys(leafFile, &pmap -> store);
eputs("Building out-of-core octree...\n");
#endif
if (!OOC_Build(&pmap -> store, PMAP_OOC_LEAFMAX, PMAP_OOC_MAXDEPTH))
error(INTERNAL, "failed out-of-core octree build in OOC_BuildPhotonMap");
#ifdef DEBUG_OOC
eputs("Checking out-of-core octree consistency...\n");
if (OOC_Check(&pmap -> store, OOC_ROOT(&pmap -> store),
octOrg, octSize, 0
))
error(INTERNAL, "inconsistent out-of-core octree; Time4Harakiri");
#endif
}
/* PHOTON MAP I/O ROUTINES ------------------------------------------ */
int OOC_SavePhotons (const struct PhotonMap *pmap, FILE *out)
{
return OOC_SaveOctree(&pmap -> store, out);
}
int OOC_LoadPhotons (struct PhotonMap *pmap, FILE *nodeFile)
{
FILE *leafFile;
char leafFname [1024];
/* Derive leaf filename from photon map and open file */
strncpy(leafFname, pmap -> fileName, sizeof(leafFname));
strncat(leafFname, PMAP_OOC_LEAFSUFFIX,
sizeof(leafFname) - strlen(leafFname) - 1
);
if (!(leafFile = fopen(leafFname, "r")))
error(SYSTEM, "failed to open leaf file in OOC_LoadPhotons");
if (OOC_LoadOctree(&pmap -> store, nodeFile, OOC_PhotonKey, leafFile))
return -1;
#ifdef DEBUG_OOC
/* Check octree for consistency */
if (OOC_Check(&pmap -> store, OOC_ROOT(&pmap -> store),
pmap -> store.org, pmap -> store.size, 0
))
return -1;
#endif
return 0;
}
/* PHOTON MAP SEARCH ROUTINES ------------------------------------------ */
void OOC_InitFindPhotons (struct PhotonMap *pmap)
{
if (OOC_InitNearest(&pmap -> squeue, pmap -> maxGather + 1,
sizeof(Photon)
))
error(SYSTEM, "can't allocate photon search queue");
#ifdef PMAP_PATHFILT
initPhotonPaths(pmap);
#endif
}
static void OOC_InitPhotonCache (struct PhotonMap *pmap)
/* Initialise OOC photon cache */
{
static char warn = 1;
if (!pmap -> store.cache && !pmap -> numDensity) {
if (pmapCacheSize > 0) {
const unsigned pageSize = pmapCachePageSize * pmap -> maxGather,
numPages = pmapCacheSize / pageSize;
/* Allocate & init I/O cache in octree */
pmap -> store.cache = malloc(sizeof(OOC_Cache));
if (!pmap -> store.cache || OOC_CacheInit(pmap -> store.cache,
numPages, pageSize, sizeof(Photon)
)) {
error(SYSTEM, "failed OOC photon map cache init");
}
}
else if (warn) {
error(WARNING, "OOC photon map cache DISABLED");
warn = 0;
}
}
}
int OOC_FindPhotons (struct PhotonMap *pmap,
const FVECT pos, const FVECT norm
)
{
OOC_SearchFilterCallback filt;
OOC_SearchFilterState filtState;
#ifdef PMAP_PATHFILT
OOC_SearchAttribCallback paths, *pathsPtr = NULL;
#endif
float res, n [3];
/* Lazily init OOC cache */
if (!pmap -> store.cache)
OOC_InitPhotonCache(pmap);
/* Set up filter callback */
if (norm)
VCOPY(n, norm);
filtState.pmap = pmap;
filtState.pos = pos;
filtState.norm = norm ? n : NULL;
filt.state = &filtState;
filt.filtFunc = filterPhoton;
/* Get sought light source modifier from pmap -> lastContribSrc if
precomputing contribution photon */
filtState.srcMod = isContribPmap(pmap)
? findmaterial(source [pmap -> lastContribSrc.srcIdx].so)
: NULL;
#ifdef PMAP_PATHFILT
/* Set up path ID callback to filter for photons from unique paths */
paths.state = pmap;
paths.findFunc = findPhotonPath;
paths.addFunc = addPhotonPath;
paths.delFunc = deletePhotonPath;
paths.checkFunc = checkPhotonPaths;
pathsPtr = &paths;
resetPhotonPaths(pmap);
res = OOC_FindNearest(
&pmap -> store, OOC_ROOT(&pmap -> store), 0,
pmap -> store.org, pmap -> store.size, pos, &filt, pathsPtr,
&pmap -> squeue, pmap -> maxDist2
);
#else
res = OOC_FindNearest(
&pmap -> store, OOC_ROOT(&pmap -> store), 0,
pmap -> store.org, pmap -> store.size, pos, &filt, NULL,
&pmap -> squeue, pmap -> maxDist2
);
#endif /* PMAP_PATHFILT */
if (res < 0)
error(INTERNAL, "failed k-NN photon lookup in OOC_FindPhotons");
/* Get (maximum distance)^2 from search queue head */
pmap -> maxDist2 = pmap -> squeue.node [0].dist2;
/* Return success or failure (empty queue => none found) */
return pmap -> squeue.tail ? 0 : -1;
}
int OOC_Find1Photon (struct PhotonMap* pmap,
const FVECT pos, const FVECT norm,
Photon *photon, OOC_DataIdx *photonIdx
)
{
OOC_SearchFilterCallback filt;
OOC_SearchFilterState filtState;
float n [3], maxDist2;
/* Lazily init OOC cache */
if (!pmap -> store.cache)
OOC_InitPhotonCache(pmap);
/* Set up filter callback */
if (norm)
VCOPY(n, norm);
filtState.pmap = pmap;
filtState.norm = norm ? n : NULL;
filtState.srcMod = NULL;
filt.state = &filtState;
filt.filtFunc = filterPhoton;
*photonIdx = (OOC_DataIdx)(-1);
maxDist2 = OOC_Find1Nearest(&pmap -> store, OOC_ROOT(&pmap -> store), 0,
pmap -> store.org, pmap -> store.size,pos, &filt, photon, photonIdx,
pmap -> maxDist2
);
if (maxDist2 < 0)
error(INTERNAL, "failed 1-NN photon lookup in OOC_Find1Photon");
if (maxDist2 >= pmap -> maxDist2)
/* No photon found => failed */
return -1;
else {
/* Set photon distance => success */
pmap -> maxDist2 = maxDist2;
return 0;
}
}
/* PHOTON ACCESS ROUTINES ------------------------------------------ */
int OOC_GetPhoton (struct PhotonMap *pmap, PhotonIdx idx, Photon *photon)
{
return OOC_GetData(&pmap -> store, idx, photon);
}
Photon *OOC_GetNearestPhoton (const PhotonSearchQueue *squeue, PhotonIdx idx)
{
return OOC_GetNearest(squeue, idx);
}
PhotonIdx OOC_FirstPhoton (const struct PhotonMap* pmap)
{
return 0;
}

Event Timeline