Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F61162374
pmapooc.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, May 4, 22:33
Size
10 KB
Mime Type
text/x-c
Expires
Mon, May 6, 22:33 (2 d)
Engine
blob
Format
Raw Data
Handle
17373691
Attached To
R10977 RADIANCE Photon Map
pmapooc.c
View Options
/*
======================================================================
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
Log In to Comment