Skip to content

Commit

Permalink
Optimize|World|SectorCluster: Avoid unnecessary Surface Decoration up…
Browse files Browse the repository at this point in the history
…dates

Previously if a mapped Plane move occurred then all of the Surfaces
of LineSides in the cluster-linked Sector were marked for updating,
irrespective of whether those surfaces are actually "dependent" on
said plane.

In large maps with lots of moving planes and light decorations, this
meant a lot of unnecessary surface redecoration.

SectorCluster's internal boundary info is automatically prepared the
first time one of the dependent Planes move if needed (map hacks may
mean this info is already prepared). The boundary info is then used
to limit light decoration updates to only those Surfaces which share
a boundary edge with the cluster.

Todo for later: Free the boundary info if the dependent planes have
not moved in a while.
  • Loading branch information
danij-deng committed Apr 23, 2014
1 parent ee85b27 commit 5710d3d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 32 deletions.
6 changes: 2 additions & 4 deletions doomsday/client/src/world/plane.cpp
Expand Up @@ -277,25 +277,23 @@ void Plane::resetSmoothedHeight()
{
d->heightSmoothed = newHeightSmoothed;
d->notifySmoothedHeightChanged();
d->surface.markAsNeedingDecorationUpdate();
}

d->surface.markAsNeedingDecorationUpdate();
}

void Plane::updateHeightTracking()
{
d->oldHeight[0] = d->oldHeight[1];
d->oldHeight[1] = d->height;

d->surface.markAsNeedingDecorationUpdate();

if(!de::fequal(d->oldHeight[0], d->oldHeight[1]))
{
if(de::abs(d->oldHeight[0] - d->oldHeight[1]) >= MAX_SMOOTH_MOVE)
{
// Too fast: make an instantaneous jump.
d->oldHeight[0] = d->oldHeight[1];
}
d->surface.markAsNeedingDecorationUpdate();
}
}

Expand Down
71 changes: 43 additions & 28 deletions doomsday/client/src/world/sectorcluster.cpp
Expand Up @@ -323,8 +323,10 @@ DENG2_OBSERVES(Plane, HeightChange)
return flags;
}

void initBoundaryInfo()
void initBoundaryInfoIfNeeded()
{
if(!boundaryInfo.isNull()) return;

QMap<Cluster *, HEdge *> extClusterMap;
foreach(BspLeaf *leaf, bspLeafs)
{
Expand All @@ -335,7 +337,8 @@ DENG2_OBSERVES(Plane, HeightChange)
if(!hedge->hasMapElement())
continue;

DENG2_ASSERT(hedge->twin().hasFace()); // Sanity check.
if(!hedge->twin().hasFace())
continue;

BspLeaf &backLeaf = hedge->twin().face().mapElementAs<BspLeaf>();
if(!backLeaf.hasCluster())
Expand Down Expand Up @@ -427,11 +430,7 @@ DENG2_OBSERVES(Plane, HeightChange)
{
// Should we permanently map planes to another cluster?

// Is it time to initialize the boundary info?
if(boundaryInfo.isNull())
{
initBoundaryInfo();
}
initBoundaryInfoIfNeeded();

foreach(HEdge *hedge, boundaryInfo->uniqueOuterEdges)
{
Expand Down Expand Up @@ -480,7 +479,6 @@ DENG2_OBSERVES(Plane, HeightChange)
}

// Permanent mappings won't be remapped.
boundaryInfo.reset();
return;
}
}
Expand All @@ -502,11 +500,7 @@ DENG2_OBSERVES(Plane, HeightChange)
if(!doFloor && !doCeiling)
return;

// Is it time to initialize the boundary info?
if(boundaryInfo.isNull())
{
initBoundaryInfo();
}
initBoundaryInfoIfNeeded();

// Map "this" cluster to the first outer cluster found.
foreach(HEdge *hedge, boundaryInfo->uniqueOuterEdges)
Expand Down Expand Up @@ -565,6 +559,25 @@ DENG2_OBSERVES(Plane, HeightChange)

#ifdef __CLIENT__

void markAllSurfacesForDecorationUpdate(Line &line)
{
LineSide &front = line.front();
DENG2_ASSERT(front.hasSections());
{
front.middle().markAsNeedingDecorationUpdate();
front.bottom().markAsNeedingDecorationUpdate();
front. top().markAsNeedingDecorationUpdate();
}

LineSide &back = line.back();
if(back.hasSections())
{
back.middle().markAsNeedingDecorationUpdate();
back.bottom().markAsNeedingDecorationUpdate();
back .top().markAsNeedingDecorationUpdate();
}
}

/**
* To be called when the height changes to update the plotted decoration
* origins for surfaces whose material offset is dependant upon this.
Expand All @@ -573,22 +586,24 @@ DENG2_OBSERVES(Plane, HeightChange)
{
if(ddMapSetup) return;

foreach(LineSide *side, self.sector().sides())
initBoundaryInfoIfNeeded();

// Mark surfaces of the outer edge loop.
HEdge *base = boundaryInfo->uniqueOuterEdges.first();
SectorClusterCirculator it(base);
do
{
if(side->hasSections())
{
side->middle().markAsNeedingDecorationUpdate();
side->bottom().markAsNeedingDecorationUpdate();
side ->top().markAsNeedingDecorationUpdate();
}
markAllSurfacesForDecorationUpdate(it->mapElementAs<LineSideSegment>().line());
} while(&it.next() != base);

if(side->back().hasSections())
// Mark surfaces of the inner edge loop(s).
foreach(HEdge *base, boundaryInfo->uniqueInnerEdges)
{
SectorClusterCirculator it(base);
do
{
LineSide &back = side->back();
back.middle().markAsNeedingDecorationUpdate();
back.bottom().markAsNeedingDecorationUpdate();
back .top().markAsNeedingDecorationUpdate();
}
markAllSurfacesForDecorationUpdate(it->mapElementAs<LineSideSegment>().line());
} while(&it.next() != base);
}
}

Expand Down Expand Up @@ -951,10 +966,10 @@ SectorCluster *SectorClusterCirculator::getCluster(HEdge const &hedge) // static
return hedge.face().mapElementAs<BspLeaf>().clusterPtr();
}

HEdge const &SectorClusterCirculator::getNeighbor(HEdge const &hedge, ClockDirection direction,
HEdge &SectorClusterCirculator::getNeighbor(HEdge const &hedge, ClockDirection direction,
SectorCluster const *cluster) // static
{
HEdge const *neighbor = &hedge.neighbor(direction);
HEdge *neighbor = &hedge.neighbor(direction);
// Skip over interior edges.
if(cluster)
{
Expand Down

0 comments on commit 5710d3d

Please sign in to comment.