Skip to content

Commit

Permalink
Refactor|BiasSurface: Integrated 'latent' light contribution concept …
Browse files Browse the repository at this point in the history
…at BiasSurface level

As light contributions are no longer referenced by the index of the
BiasSource, they no longer erroneously propagate to another source
when another is deleted.

Todo: The vertexes are still working under the assumption that they
must manage this concept, with the net result being a conflict come
interpolation time.
  • Loading branch information
danij-deng committed Jul 30, 2013
1 parent 15f60ef commit bfe52d9
Showing 1 changed file with 99 additions and 84 deletions.
183 changes: 99 additions & 84 deletions doomsday/client/src/render/biassurface.cpp
Expand Up @@ -46,10 +46,10 @@ static int devUseSightCheck = true; //cvar
struct Contributor
{
BiasSource *source;
float influence;
};

/// Contribution intensity => bias source.
typedef QMap<float, Contributor> Affection;
typedef Contributor Contributors[MAX_AFFECTED];

/**
* Per-vertex illumination data.
Expand Down Expand Up @@ -120,7 +120,7 @@ struct VertexIllum
/**
* @return Light contribution by the specified source.
*/
Vector3f &contribution(BiasSource *source, Affection const &affectedSources)
Vector3f &contribution(BiasSource *source, Contributors const &contributors)
{
DENG2_ASSERT(source != 0);

Expand All @@ -138,8 +138,9 @@ struct VertexIllum

if(casted[i].source)
{
foreach(Contributor const &ctbr, affectedSources)
for(int k = 0; k < MAX_AFFECTED; ++k)
{
Contributor const &ctbr = contributors[k];
if(ctbr.source == casted[i].source)
{
inUse = true;
Expand All @@ -161,37 +162,13 @@ struct VertexIllum
// Now how'd that happen?
throw Error("VertexIllum::casted", QString("No light emitted by source"));
}
};

Q_DECLARE_OPERATORS_FOR_FLAGS(VertexIllum::Flags)

/**
* evalLighting uses these -- they must be set before it is called.
*/
static uint biasTime;
static MapElement const *bspRoot;
static Vector3f const *mapSurfaceNormal;
static BiasTracker trackChanged;
static BiasTracker trackApplied;

DENG2_PIMPL_NOREF(BiasSurface)
{
QVector<VertexIllum> illums; /// @todo use std::vector instead?

BiasTracker tracker;

Affection affected;

uint lastUpdateOnFrame;

Instance(int size) : illums(size), lastUpdateOnFrame(0)
{}

void updateLightContribution(VertexIllum &vi, Vector3d const &surfacePoint,
Contributor const &ctbr)
void updateContribution(int index, Contributors const &contributors,
Vector3d const &surfacePoint, Vector3f const &surfaceNormal,
MapElement const &bspRoot)
{
BiasSource *source = ctbr.source;
Vector3f &casted = vi.contribution(source, affected);
BiasSource *source = contributors[index].source;
Vector3f &casted = contribution(source, contributors);

/// @todo LineSightTest should (optionally) perform this test.
Sector *sector = &source->bspLeafAtOrigin().sector();
Expand All @@ -209,7 +186,7 @@ DENG2_PIMPL_NOREF(BiasSurface)

if(devUseSightCheck &&
!LineSightTest(source->origin(),
surfacePoint + sourceToSurface / 100).trace(*bspRoot))
surfacePoint + sourceToSurface / 100).trace(bspRoot))
{
// LOS fail.
// This affecting source does not contribute any light.
Expand All @@ -218,7 +195,7 @@ DENG2_PIMPL_NOREF(BiasSurface)
}

double distance = sourceToSurface.length();
double dot = sourceToSurface.normalize().dot(*mapSurfaceNormal);
double dot = sourceToSurface.normalize().dot(surfaceNormal);

// The surface faces away from the light?
if(dot < 0)
Expand All @@ -231,6 +208,35 @@ DENG2_PIMPL_NOREF(BiasSurface)
float strength = dot * source->evaluateIntensity() / distance;
casted = source->color() * de::clamp(0.f, strength, 1.f);
}
};

Q_DECLARE_OPERATORS_FOR_FLAGS(VertexIllum::Flags)

/**
* evalLighting uses these -- they must be set before it is called.
*/
static uint biasTime;
static MapElement const *bspRoot;
static Vector3f const *mapSurfaceNormal;
static BiasTracker trackChanged;
static BiasTracker trackApplied;

/// @todo defer allocation of most data -- adopt a 'fly-weight' approach.
DENG2_PIMPL_NOREF(BiasSurface)
{
QVector<VertexIllum> illums; /// @todo use std::vector instead?

BiasTracker tracker;

Contributors affected;
uint activeContributors;

uint lastUpdateOnFrame;

Instance(int size) : illums(size), activeContributors(0), lastUpdateOnFrame(0)
{
zap(affected);
}

/**
* Perform lighting calculations for a vertex.
Expand Down Expand Up @@ -270,40 +276,26 @@ DENG2_PIMPL_NOREF(BiasSurface)
/*
* Determine if any affecting sources have changed since last frame.
*/
uint activeContributors = 0;
uint changedContributors = 0;

//if(map.biasSourceCount() > 0)
Contributor *ctbr = affected;
for(int i = 0; i < MAX_AFFECTED; ++i, ctbr++)
{
int n = 0;
foreach(Contributor const &ctbr, affected)
{
// Is this a valid index?
/*if(sourceIndex < 0 || sourceIndex >= map.biasSourceCount())
{
illumChanged = true;
continue;
}*/
if(!(activeContributors & (1 << i))) continue;

BiasSource *source = ctbr.source;
int sourceIndex = map.toIndex(*source);
activeContributors |= 1 << n;
int sourceIndex = map.toIndex(*ctbr->source);
if(!trackChanged.check(sourceIndex))
continue;

if(trackChanged.check(sourceIndex))
{
changedContributors |= 1 << n;
illumChanged = true;
trackApplied.mark(sourceIndex);
trackApplied.mark(sourceIndex);

// Remember the earliest time an affecting source changed.
if(latestSourceUpdate < source->lastUpdateTime())
{
latestSourceUpdate = source->lastUpdateTime();
}
}
changedContributors |= 1 << i;
illumChanged = true;

// Move to the next.
n++;
// Remember the earliest time an affecting source changed.
if(latestSourceUpdate < ctbr->source->lastUpdateTime())
{
latestSourceUpdate = ctbr->source->lastUpdateTime();
}
}

Expand All @@ -316,14 +308,13 @@ DENG2_PIMPL_NOREF(BiasSurface)
*/
if(changedContributors)
{
int n = 0;
foreach(Contributor const &ctbr, affected)
Contributor *ctbr = affected;
for(int i = 0; i < MAX_AFFECTED; ++i, ctbr++)
{
if(changedContributors & (1 << n))
if(changedContributors & (1 << i))
{
updateLightContribution(vi, surfacePoint, ctbr);
vi.updateContribution(i, affected, surfacePoint, *mapSurfaceNormal, *bspRoot);
}
n++;
}
}

Expand All @@ -334,18 +325,17 @@ DENG2_PIMPL_NOREF(BiasSurface)
*/
if(activeContributors)
{
int n = 0;
foreach(Contributor const &ctbr, affected)
Contributor *ctbr = affected;
for(int i = 0; i < MAX_AFFECTED; ++i, ctbr++)
{
if(activeContributors & (1 << n))
if(activeContributors & (1 << i))
{
newColor += vi.contribution(ctbr.source, affected);
newColor += vi.contribution(ctbr->source, affected);

// Stop once fully saturated.
if(newColor >= saturated)
break;
}
n++;
}

// Clamp.
Expand Down Expand Up @@ -415,7 +405,7 @@ void BiasSurface::setLastUpdateOnFrame(uint newLastUpdateFrameNumber)

void BiasSurface::clearAffected()
{
d->affected.clear();
d->activeContributors = 0;
}

void BiasSurface::addAffected(float intensity, BiasSource *source)
Expand All @@ -425,16 +415,33 @@ void BiasSurface::addAffected(float intensity, BiasSource *source)
// If its too weak we will ignore it entirely.
if(intensity < MIN_INTENSITY) return;

if(d->affected.count() == MAX_AFFECTED)
// Do we have a latent contribution, or a spare slot?
int weakest = -1;
int slot = 0;
Contributor *ctbr = d->affected;
for(; slot < MAX_AFFECTED; ++slot, ctbr++)
{
// Drop the weakest.
Affection::Iterator weakest = d->affected.begin();
if(intensity <= weakest.key()) return;
d->affected.remove(weakest.key());
// Remember the weakest.
if(weakest < 0 || ctbr->influence < d->affected[weakest].influence)
weakest = slot;

// A latent contribution?
if(ctbr->source == source)
break;
}

Contributor ctbr = { source };
d->affected.insert(intensity, ctbr);
if(slot == MAX_AFFECTED)
{
// No -- drop the weakest.
slot = weakest;
if(intensity <= d->affected[weakest].influence) return;

ctbr = &d->affected[slot];
}

ctbr->source = source;
ctbr->influence = intensity;
d->activeContributors |= 1 << slot;
}

void BiasSurface::updateAffection(BiasTracker &changes)
Expand All @@ -444,9 +451,13 @@ void BiasSurface::updateAffection(BiasTracker &changes)

// Determine whether these changes affect us.
bool needApplyChanges = false;
foreach(Contributor const &ctbr, d->affected)
Contributor *ctbr = d->affected;
for(int i = 0; i < MAX_AFFECTED; ++i, ctbr++)
{
if(changes.check(App_World().map().toIndex(*ctbr.source)))
if(!ctbr->source)
continue;

if(changes.check(App_World().map().toIndex(*ctbr->source)))
{
needApplyChanges = true;
break;
Expand All @@ -464,9 +475,13 @@ void BiasSurface::updateAffection(BiasTracker &changes)

void BiasSurface::updateAfterMove()
{
foreach(Contributor const &ctbr, d->affected)
Contributor *ctbr = d->affected;
for(int i = 0; i < MAX_AFFECTED; ++i, ctbr++)
{
ctbr.source->forceUpdate();
if(ctbr->source)
{
ctbr->source->forceUpdate();
}
}
}

Expand Down

0 comments on commit bfe52d9

Please sign in to comment.