Page MenuHomec4science

pmcontrib4.c
No OneTemporary

File Metadata

Created
Sat, May 11, 10:17

pmcontrib4.c

#ifndef lint
static const char RCSid[] = "$Id: pmcontrib2.c,v 2.5 2018/11/08 00:54:07 greg Exp $";
#endif
/*
=========================================================================
Photon map routines for precomputed light source contributions.
These routines interface to rcontrib.
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")
=========================================================================
$Id$
*/
#ifdef PMAP_OOC
#include "pmapcontrib.h"
#include "pmapmat.h"
#include "pmapsrc.h"
#include "pmaprand.h"
#include "pmapio.h"
#include "pmapdiag.h"
#include "otypes.h"
#include "otspecial.h"
#include "oocnn.h"
void initPmapContribTab (LUTAB *contribTab, int *contribMode)
/* Set contribution table (interface to rcmain.c) */
{
pmapContribTab = contribTab;
pmapContribMode = contribMode;
}
/* ------------------ CONTRIB PMAP LOADING STUFF --------------------- */
static int checkContribModifier (const LUENT *modContNode, void *p)
/* Check for valid modifier in LUT entry */
{
MODCONT *modCont = (MODCONT*)modContNode -> data;
char *modName = (char*)modCont -> modname;
OBJECT modObj = modifier(modName);
if (modObj == OVOID) {
sprintf(errmsg, "invalid modifier %s", modName);
error(USER, errmsg);
}
if (!islight(objptr(modObj) -> otype)) {
sprintf(errmsg, "%s is not a light source modifier", modName);
error(USER, errmsg);
}
return 0;
}
void initPmapContrib (PhotonMap *pmap)
/* Set up photon map contributions and get binning parameters */
{
unsigned t;
/* Avoid incompatible photon maps */
for (t = 0; t < NUM_PMAP_TYPES; t++)
if (photonMaps [t] && t != PMAP_TYPE_CONTRIB) {
sprintf(errmsg, "%s photon map does not support contributions",
pmapName [t]
);
error(USER, errmsg);
}
if (!pmapContribTab)
error(INTERNAL,
"contribution LUT not initialised in initPmapContrib()"
);
/* Check for valid contribution modifiers */
lu_doall(pmapContribTab, checkContribModifier, NULL);
/* Set callback to collect contributions */
if (pmap) {
pmap -> lookup = getPreCompPhotonContrib;
/* XXX: Need tighter tolerance for contribution photon lookups? */
pmap -> gatherTolerance = 1.0;
}
}
static int loadPreCompContrib (const LUENT *modContNode, void *p)
/* Load child contribution photon map for current contrib modifier entry */
{
MODCONT *modCont = (MODCONT*)modContNode -> data;
char *modName = (char*)modCont -> modname;
PhotonMap *preCompContribPmap;
const PhotonMap *parentPmap = (const PhotonMap*)p;
LUENT *preCompContribNode;
PreComputedContrib *preCompContrib;
char dirName [1024];
/* Allocate new LUT entry for child precomputed contribution pmap */
preCompContribNode = lu_find(parentPmap -> preCompContribTab, modName);
if (!preCompContribNode)
error(SYSTEM,
"out of memory allocating LUT entry in loadPreCompContrib()"
);
preCompContribNode -> key = modName;
/* Allocate child precomputed contribution photon map */
preCompContribNode -> data = (char*)(
preCompContribPmap = malloc(sizeof(PhotonMap))
);
if (!preCompContribPmap)
error(SYSTEM, "out of memory allocating precomputed contribution "
"photon map in loadPreCompContrib()"
);
/* Set subdirectory from parent photon map's filename */
snprintf(dirName, sizeof(dirName), PMAP_CONTRIB_DIR,
parentPmap -> fileName
);
/* Allocate & set child pmap's filename from subdir and modifier */
preCompContribPmap -> fileName = malloc(strlen(parentPmap -> fileName) +
strlen(modName) + strlen(PMAP_CONTRIB_FILE)
);
if (!preCompContribPmap -> fileName)
error(SYSTEM, "out of memory allocating filename in "
"loadPreCompContrib()"
);
snprintf(preCompContribPmap -> fileName, sizeof(dirName) + 4,
PMAP_CONTRIB_FILE, dirName, modName
);
/* Load child precomp contrib photon map for current modifier;
loadPhotonMap() will not recurse and call loadContribPhotonMap()
again because preCompContribPmap -> preCompContribTab == NULL */
loadPhotonMap(preCompContribPmap, preCompContribPmap -> fileName);
/* Pass parent pmap's lookup parameters on to child */
preCompContribPmap -> minGather = parentPmap -> minGather;
preCompContribPmap -> maxGather = parentPmap -> maxGather;
preCompContribPmap -> gatherTolerance = parentPmap -> gatherTolerance;
/* Override contrib/coeff mode if it doesn't match precomputed */
if (*pmapContribMode != preCompContribPmap -> contribMode) {
sprintf(errmsg,
"photon map contains precomputed %s, overriding rcontrib setting",
preCompContribPmap -> contribMode ? "contributions" : "coefficients"
);
error(WARNING, errmsg);
*pmapContribMode = preCompContribPmap -> contribMode;
}
/* NOTE: preCompContribPmap -> preCompContrib is initialised by
* loadPhotonMap() */
preCompContrib = (PreComputedContrib*)(
preCompContribPmap -> preCompContrib
);
/* Set bins per dimension and number of bins */
preCompContrib -> scDim = PMAP_CONTRIB_SCDIM(preCompContrib -> l);
preCompContrib -> nBins = preCompContrib -> scDim *
preCompContrib -> scDim;
/* Set wavelet coeff filename */
preCompContrib -> waveletFname = malloc(strlen(dirName) +
strlen(modName) + strlen(PMAP_CONTRIB_WAVELETFILE)
);
if (!preCompContribPmap -> fileName)
error(SYSTEM, "out of memory allocating filename in "
"loadPreCompContrib()"
);
snprintf(preCompContrib -> waveletFname, sizeof(dirName) + 5,
PMAP_CONTRIB_WAVELETFILE, dirName, modName
);
return 0;
}
void loadContribPhotonMap (PhotonMap *pmap, const char *fname)
/* Load contribution pmap and its per-modifier precomputed children */
{
LUTAB lutInit = LU_SINIT(NULL, freePreCompContribNode);
/* Allocate & init LUT containing per-modifier child contrib pmaps */
if (!(pmap -> preCompContribTab = malloc(sizeof(lutInit))))
error(SYSTEM, "out of memory allocating precomputed contribution "
"LUT in loadContribPhotonMap()"
);
memcpy(pmap -> preCompContribTab, &lutInit, sizeof(lutInit));
/* NOTE: filename already set in loadPhotonMap()
pmap -> fileName = (char*)fname; */
/* Init contrib photon map for light source contributions */
initPmapContrib(pmap);
/* Load child contribution photon maps for each modifier in contribTab */
lu_doall(pmapContribTab, loadPreCompContrib, pmap);
}
/* ------------------ CONTRIB PMAP DECODING STUFF --------------------- */
static int decodeContribs (PreComputedContrib *preCompContrib,
DCOLOR *binnedContribs
)
/* Decode and decompress mRGBE-encoded wavelet coefficients in
preCompContrib -> mrgbeCoeffs, apply inverse wavelet transform and return
decoded contributions in binnedContribs.
NOTE: The average wavelet coefficient is expected as input in the upper
left of the wavelet matrix (i.e. preCompContrib->waveletMatrix [0][0]).
Returns 0 on success, else -1. */
{
unsigned b, i, coeffBin;
mRGBERange *mrgbeRange;
mRGBE *mrgbeCoeffs;
DCOLOR fCoeff;
if (!binnedContribs || !preCompContrib || !binnedContribs ||
!preCompContrib -> mrgbeCoeffs || !preCompContrib -> compressedBins
)
/* Should be initialised by caller! */
return -1;
mrgbeCoeffs = preCompContrib -> mrgbeCoeffs;
mrgbeRange = &preCompContrib -> mrgbeRange;
/* Init mRGBE coefficient normalisation from range */
mRGBEinit(mrgbeRange, mrgbeRange -> min, mrgbeRange -> max);
/* Zero all detail coeffs (omitting average at binnedContribs [0]) */
for (b = 1; b < preCompContrib -> nBins; b++)
setcolor(binnedContribs [b], 0, 0, 0);
/* Decode mRGBE to wavelet detail coefficients, omitting average at
* binnedContrib [0].
* NOTE: The encoded bin preserves the offset for the omitted 1st
* coefficient (i.e. the average), so no shifting done on decoding. */
for (b = 0; b < preCompContrib -> nCompressedBins; b++) {
coeffBin = mRGBEdecode(mrgbeCoeffs [b], mrgbeRange, fCoeff);
/* Check for rogue bins before assignment */
if (coeffBin < 1 || coeffBin >= preCompContrib -> nBins)
error(CONSISTENCY, "bin out of range in decodeContribs()");
copycolor(binnedContribs [coeffBin], fCoeff);
}
/* Do inverse 2D wavelet transform on preCompContrib -> waveletMatrix
(which actually maps to binnedContribs) */
if (waveletInvXform2(preCompContrib -> waveletMatrix,
preCompContrib -> tWaveletMatrix, preCompContrib -> l
) < 0
)
error(INTERNAL,
"failed inverse wavelet transform in decodeContribs()"
);
return 0;
}
static void getPreCompContribByPhoton (const Photon *photon,
OOC_DataIdx photonIdx, PreComputedContrib *preCompContrib,
DCOLOR *binnedContribs
)
/* Fetch and decode mRGBE-encoded wavelet coefficients for given photon
from wavelet file at offset photonIdx, perform inverse wavelet xform,
and return the reconstructed binned contributions in binnedContribs
(which is assumed to be variable). Returns 0 on success, else -1. */
/* XXX: HERE binnedContribs POINTS TO CACHE PAGE DATA! */
{
unsigned b;
COLR mrgbeRange32 [2];
COLOR fCoeff;
if (!binnedContribs || !preCompContrib)
/* Shouldn't happen */
error(INTERNAL,
"contributions not initialised in getPreCompContrib()"
);
if (preCompContrib -> nBins <= 1)
/* No binning, so nothing to decode */
return;
/* Lazily initialise preCompContrib */
if (!preCompContrib -> waveletFile) {
/* Lazily open wavelet coefficient file */
preCompContrib -> waveletFile = fopen(
preCompContrib -> waveletFname, "rb"
);
if (!preCompContrib -> waveletFile) {
sprintf(errmsg, "failed to open wavelet coefficient file %s "
"in getPreCompContrib()", preCompContrib -> waveletFname
);
error(SYSTEM, errmsg);
}
/* Set record size (in bytes) of encoded coeffs in wavelet file;
this consists of mRGBE coeffs plus RGBE range in 32-bit RGBE */
preCompContrib -> contribSize = 2 * sizeof(COLR) +
preCompContrib -> nCompressedBins * sizeof(mRGBE);
/* Lazily allocate buffer for mRGBE wavelet coeffs */
preCompContrib -> mrgbeCoeffs = calloc(
preCompContrib -> nCompressedBins, sizeof(mRGBE)
);
/* Lazily allocate buffer for decoded detail coefficients
(minus avg coeff, which is stored in corresponding photon) */
preCompContrib -> compressedBins = calloc(
preCompContrib -> nBins - 1, sizeof(DCOLOR)
);
if (!preCompContrib -> mrgbeCoeffs ||
!preCompContrib -> compressedBins
)
error(SYSTEM, "out of memory allocating decoded coefficients "
"in getPreCompContrib()"
);
/* Lazily allocate primary wavelet matrix rows */
preCompContrib -> waveletMatrix = calloc(
preCompContrib -> scDim, sizeof(WaveletCoeff3*)
);
if (!preCompContrib -> waveletMatrix)
error(SYSTEM, "out of memory allocating primary wavelet "
"matrix in getPreCompContrib()"
);
/* Lazily allocate transposed wavelet matrix */
preCompContrib -> tWaveletMatrix =
allocWaveletMatrix(preCompContrib -> l);
if (!preCompContrib -> tWaveletMatrix)
error(SYSTEM, "out of memory allocating transposed wavelet "
" matrix in getPreCompContrib()"
);
}
/* Seek to photon index in wavelet file and read mRGBE normalisation
and encoded bins */
if (fseek(preCompContrib -> waveletFile,
photonIdx * preCompContrib -> contribSize, SEEK_SET
) < 0
)
error(SYSTEM, "failed seek in wavelet coefficient file "
"in getPreCompContrib()"
);
if (getbinary(mrgbeRange32, sizeof(COLR), 2,
preCompContrib -> waveletFile
) != 2 ||
getbinary(preCompContrib -> mrgbeCoeffs, sizeof(mRGBE),
preCompContrib -> nCompressedBins, preCompContrib -> waveletFile
) != preCompContrib -> nCompressedBins
)
error(SYSTEM, "failed reading from wavelet coefficient file "
"in getPreCompContrib()"
);
/* Get mRGBE range */
colr_color(fCoeff, mrgbeRange32 [0]);
copycolor(preCompContrib -> mrgbeRange.min, fCoeff);
colr_color(fCoeff, mrgbeRange32 [1]);
copycolor(preCompContrib -> mrgbeRange.max, fCoeff);
/* Map primary wavelet matrix rows to linear output array
binnedContribs; do this every time under the assumption that
binnedContribs is not static! */
for (b = 0; b < preCompContrib -> scDim; b++)
/* Point to each row in cache linear output array */
preCompContrib -> waveletMatrix [b] =
&binnedContribs [b * preCompContrib -> scDim];
/* Set average wavelet coefficient from photon flux; this coefficient
is expected by the inverse transform routine in upper left of the
wavelet matrix (i.e. preCompContrib -> waveletMatrix [0][0] =
binnedContribs [0]) */
getPhotonFlux((Photon*)photon, fCoeff);
copycolor(preCompContrib -> waveletMatrix [0][0], fCoeff);
/* All set, now decode mRGBE coeffs and invert wavelet transform */
if (decodeContribs(preCompContrib, binnedContribs))
error(INTERNAL,
"failed contribution decoding/decompression in getPreCompContrib()"
);
}
typedef struct {
const RAY *ray;
RREAL rayCoeff [3];
COLORV *totalContrib;
} PreCompContribRCData;
static int getPreCompContribByMod (const LUENT *preCompContribTabNode,
void *p
)
/* Fetch and decode precomputed contributions from closest photon in pmap
* referenced by preCompContribTabNode, and accumulate in pmapContribTab
* for the corresponding modifier */
{
PhotonMap *preCompContribPmap = (PhotonMap*)(
preCompContribTabNode -> data
);
PreComputedContrib *preCompContrib;
const char *modName = preCompContribTabNode -> key;
MODCONT *modCont;
PreCompContribRCData *rcData = (PreCompContribRCData*)p;
LUENT *contribTabNode;
Photon photon;
OOC_DataIdx photonIdx;
COLOR photonContrib;
unsigned b;
if (!preCompContribPmap || !rcData ||
!(preCompContrib = (PreComputedContrib*)(
preCompContribPmap -> preCompContrib
))
) {
sprintf(errmsg, "missing precomputed contributions for modifier %s",
modName
);
error(INTERNAL, errmsg);
}
/* Find rcontrib's LUT entry for this modifier */
contribTabNode = lu_find(pmapContribTab, modName);
if (!contribTabNode || !contribTabNode -> key ||
!(modCont = (MODCONT*)contribTabNode -> data)
) {
sprintf(errmsg, "missing contribution LUT entry for modifier %s",
modName
);
error(INTERNAL, errmsg);
}
/* Reallocate rcontrib bins if they don't match precomputed */
if (modCont -> nbins != preCompContrib -> nBins) {
contribTabNode -> data = realloc(modCont,
sizeof(MODCONT) + sizeof(DCOLOR) * (preCompContrib -> nBins - 1)
);
if (!contribTabNode -> data) {
sprintf(errmsg, "out of memory reallocating contribution bins "
"for modifier %s", modCont -> modname
);
error(SYSTEM, errmsg);
}
else {
sprintf(errmsg, "bin count mismatch for modifier %s, resizing",
modCont -> modname
);
error(WARNING, errmsg);
}
modCont = (MODCONT*)contribTabNode -> data;
modCont -> nbins = preCompContrib -> nBins;
memset(modCont -> cbin, 0, sizeof(DCOLOR) * modCont -> nbins);
}
/* Fetch closest photon and its contributions */
if (find1Photon(preCompContribPmap, rcData -> ray, &photon,
&photonIdx
)) {
/* XXX: TEMPORARY BUFFER FOR DECODED BINS, PENDING CONTRIB CACHE */
DCOLOR binnedContribs [preCompContrib -> nBins];
if (preCompContrib -> nBins > 1) {
/* BINNING ENABLED; fetch and decode bins for found photon */
getPreCompContribByPhoton(&photon, photonIdx, preCompContrib,
binnedContribs
);
}
else {
/* NO BINNING; get single contribution directly from photon */
getPhotonFlux(&photon, photonContrib);
copycolor(binnedContribs [0], photonContrib);
}
for (b = 0; b <= preCompContrib -> nBins; b++) {
/* Accumulate binned contributions into rcontrib's LUT entry for
this modifier, weighted by ray coefficient. Also sum total
contributions. */
multcolor(binnedContribs [b], rcData -> rayCoeff);
addcolor(modCont -> cbin [b], binnedContribs [b]);
addcolor(rcData -> totalContrib, binnedContribs [b]);
}
}
return 0;
}
void getPreCompPhotonContrib (PhotonMap *pmap, RAY *ray,
COLOR totalContrib
)
/* Get precomputed light source contributions at ray -> rop for all
specified modifiers and accumulate them in pmapContribTab (which maps
to rcontrib's binning LUT). Also return total precomputed contribs. */
{
PreCompContribRCData rcData;
/* Ignore sources */
if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype))
return;
/* Get cumulative path coefficient up to photon lookup point */
raycontrib(rcData.rayCoeff, ray, PRIMARY);
setcolor(totalContrib, 0, 0, 0);
/* Rcontrib results passed to per-modifier child contrib pmaps */
rcData.ray = ray;
rcData.totalContrib = totalContrib;
/* Iterate over child contribution photon maps for each modifier and
* collect their contributions */
lu_doall(pmap -> preCompContribTab, getPreCompContribByMod, &rcData);
}
#endif /* PMAP_OOC */

Event Timeline