Skip to content

Commit

Permalink
Refactor|World|Map: Better/cleaner mechanism for SectorCluster iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Oct 23, 2014
1 parent 3d31e7a commit dd6f907
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 65 deletions.
23 changes: 13 additions & 10 deletions doomsday/client/include/world/map.h
Expand Up @@ -39,15 +39,13 @@
# include "Lumobj"
#endif

#include <QList>
#include <QHash>
#include <QSet>
#include <doomsday/uri.h>

#include <de/BinaryTree>
#include <de/Observers>
#include <de/Vector>
#include <QList>
#include <QMultiMap>
#include <QSet>
#include <QHash>

class MapDef;
class BspLeaf;
Expand Down Expand Up @@ -136,7 +134,6 @@ class Map
typedef QList<Sector *> Sectors;

typedef QList<ConvexSubspace *> Subspaces;
typedef QMultiMap<Sector *, SectorCluster *> SectorClusters;

#ifdef __CLIENT__
typedef QSet<Plane *> PlaneSet;
Expand Down Expand Up @@ -268,14 +265,20 @@ class Map
inline int subspaceCount() const { return subspaces().count(); }

/**
* Provides access to the SectorCluster map for efficient traversal.
* Returns the total number of SectorClusters in the map.
*/
SectorClusters const &clusters() const;
int clusterCount() const;

/**
* Returns the total number of SectorClusters in the map.
* Iterate through the SectorClusters of the map.
*
* @param sector If not @c nullptr, traverse the clusters of this Sector only.
*/
inline int clusterCount() const { return clusters().count(); }
LoopResult forAllClusters(Sector *sector, std::function<LoopResult (SectorCluster &)> func);

inline LoopResult forAllClusters(std::function<LoopResult (SectorCluster &)> func) {
return forAllClusters(nullptr, func);
}

/**
* Helper function which returns the relevant side index given a @a lineIndex
Expand Down
38 changes: 18 additions & 20 deletions doomsday/client/src/render/rend_main.cpp
Expand Up @@ -4589,11 +4589,9 @@ static void drawTangentVectorsForWallSections(HEdge const *hedge)
/**
* @todo Use drawTangentVectorsForWallSections() for polyobjs too.
*/
static void drawSurfaceTangentVectors(SectorCluster *cluster)
static void drawSurfaceTangentVectors(SectorCluster &cluster)
{
if(!cluster) return;

foreach(ConvexSubspace *subspace, cluster->subspaces())
for(ConvexSubspace *subspace : cluster.subspaces())
{
HEdge const *base = subspace->poly().hedge();
HEdge const *hedge = base;
Expand All @@ -4602,23 +4600,23 @@ static void drawSurfaceTangentVectors(SectorCluster *cluster)
drawTangentVectorsForWallSections(hedge);
} while((hedge = &hedge->next()) != base);

foreach(Mesh *mesh, subspace->extraMeshes())
foreach(HEdge *hedge, mesh->hedges())
for(Mesh *mesh : subspace->extraMeshes())
for(HEdge *hedge : mesh->hedges())
{
drawTangentVectorsForWallSections(hedge);
}

foreach(Polyobj *polyobj, subspace->polyobjs())
foreach(HEdge *hedge, polyobj->mesh().hedges())
for(Polyobj *polyobj : subspace->polyobjs())
for(HEdge *hedge : polyobj->mesh().hedges())
{
drawTangentVectorsForWallSections(hedge);
}
}

int const planeCount = cluster->sector().planeCount();
int const planeCount = cluster.sector().planeCount();
for(int i = 0; i < planeCount; ++i)
{
Plane const &plane = cluster->visPlane(i);
Plane const &plane = cluster.visPlane(i);
coord_t height = 0;

if(plane.surface().hasSkyMaskedMaterial() &&
Expand All @@ -4631,7 +4629,7 @@ static void drawSurfaceTangentVectors(SectorCluster *cluster)
height = plane.heightSmoothed();
}

drawTangentVectorsForSurface(plane.surface(), Vector3d(cluster->center(), height));
drawTangentVectorsForSurface(plane.surface(), Vector3d(cluster.center(), height));
}
}

Expand All @@ -4644,10 +4642,11 @@ static void drawAllSurfaceTangentVectors(Map &map)

glDisable(GL_CULL_FACE);

foreach(SectorCluster *cluster, map.clusters())
map.forAllClusters([] (SectorCluster &cluster)
{
drawSurfaceTangentVectors(cluster);
}
return LoopContinue;
});

glEnable(GL_CULL_FACE);
}
Expand Down Expand Up @@ -5054,10 +5053,9 @@ static void drawVertexes(Map &map)
#undef MAX_VERTEX_POINT_DIST
}

static String labelForCluster(SectorCluster const *cluster)
static String labelForCluster(SectorCluster const &cluster)
{
DENG_ASSERT(cluster != 0);
return String("%1").arg(cluster->sector().indexInMap());
return String::number(cluster.sector().indexInMap());
}

/**
Expand All @@ -5070,18 +5068,18 @@ static void drawSectors(Map &map)
if(!devSectorIndices) return;

// Draw per-cluster sector labels:

foreach(SectorCluster *cluster, map.clusters())
map.forAllClusters([] (SectorCluster &cluster)
{
Vector3d const origin(cluster->center(), cluster->visPlane(Sector::Floor).heightSmoothed());
Vector3d const origin(cluster.center(), cluster.visPlane(Sector::Floor).heightSmoothed());
ddouble const distToEye = (eyeOrigin - origin).length();
if(distToEye < MAX_LABEL_DIST)
{
drawLabel(origin, labelForCluster(cluster),
distToEye / (DENG_GAMEVIEW_WIDTH / 2),
1 - distToEye / MAX_LABEL_DIST);
}
}
return LoopContinue;
});

#undef MAX_LABEL_DIST
}
Expand Down
65 changes: 44 additions & 21 deletions doomsday/client/src/world/map.cpp
Expand Up @@ -76,6 +76,7 @@
#include <de/vector1.h>
#include <de/timer.h>
#include <QBitArray>
#include <QMultiMap>
#include <QVarLengthArray>

static int bspSplitFactor = 7; // cvar
Expand Down Expand Up @@ -150,6 +151,8 @@ DENG2_PIMPL(Map)
} bsp;

Subspaces subspaces;

typedef QMultiMap<Sector *, SectorCluster *> SectorClusters;
SectorClusters clusters;

/// Map entities and element properties (things, line specials, etc...).
Expand Down Expand Up @@ -573,14 +576,14 @@ DENG2_PIMPL(Map)
*/
bool buildBspTree()
{
DENG2_ASSERT(bsp.tree == 0);
DENG2_ASSERT(bsp.tree == nullptr);
DENG2_ASSERT(subspaces.isEmpty());

// It begins...
Time begunAt;

LOGDEV_MAP_XVERBOSE("Building BSP for \"%s\" with split cost factor %d...")
<< (def? def->composeUri() : "(unknown map)") << bspSplitFactor;
<< (def? def->composeUri() : "(unknown map)") << bspSplitFactor;

// First we'll scan for so-called "one-way window" constructs and mark
// them so that the space partitioner can treat them specially.
Expand All @@ -594,8 +597,8 @@ DENG2_PIMPL(Map)
QSet<Line *> linesToBuildFor = QSet<Line *>::fromList(lines);

// Polyobj lines should be excluded.
foreach(Polyobj *po, polyobjs)
foreach(Line *line, po->lines())
for(Polyobj *po : polyobjs)
for(Line *line : po->lines())
{
linesToBuildFor.remove(line);
}
Expand All @@ -608,7 +611,7 @@ DENG2_PIMPL(Map)

// Build a new BSP tree.
bsp.tree = partitioner.makeBspTree(linesToBuildFor, mesh);
DENG2_ASSERT(bsp.tree != 0);
DENG2_ASSERT(bsp.tree);

LOG_MAP_VERBOSE("BSP built: %s. With %d Segments and %d Vertexes.")
<< bsp.tree->summary()
Expand All @@ -629,8 +632,8 @@ DENG2_PIMPL(Map)
#endif

// Iterative pre-order traversal of the map element tree.
BspTree const *cur = bsp.tree;
BspTree const *prev = 0;
BspTree const *cur = bsp.tree;
BspTree const *prev = nullptr;
while(cur)
{
while(cur)
Expand All @@ -643,7 +646,7 @@ DENG2_PIMPL(Map)
if(!leaf.sectorPtr())
{
LOG_MAP_WARNING("BSP leaf %p has degenerate geometry (%d half-edges).")
<< &leaf << (leaf.hasSubspace()? leaf.subspace().poly().hedgeCount() : 0);
<< &leaf << (leaf.hasSubspace()? leaf.subspace().poly().hedgeCount() : 0);
}

if(leaf.hasSubspace())
Expand All @@ -667,11 +670,11 @@ DENG2_PIMPL(Map)
if(discontinuities)
{
LOG_MAP_WARNING("Face geometry for BSP leaf [%p] at %s in sector %i "
"is not contiguous (%i gaps/overlaps).\n%s")
<< &leaf << subspace.poly().center().asText()
<< (leaf.sectorPtr()? leaf.sectorPtr()->indexInArchive() : -1)
<< discontinuities
<< subspace.poly().description();
"is not contiguous (%i gaps/overlaps).\n%s")
<< &leaf << subspace.poly().center().asText()
<< (leaf.sectorPtr()? leaf.sectorPtr()->indexInArchive() : -1)
<< discontinuities
<< subspace.poly().description();
}
#endif
}
Expand Down Expand Up @@ -714,16 +717,18 @@ DENG2_PIMPL(Map)
// How much time did we spend?
LOGDEV_MAP_VERBOSE("BSP built in %.2f seconds") << begunAt.since();

return bsp.tree != 0;
return bsp.tree != nullptr;
}

/**
* (Re)Build subspace clusters for the sector.
*/
void buildClusters(Sector &sector)
{
SectorClusters::iterator it = clusters.find(&sector);
while(it != clusters.end() && it.key() == &sector) { delete *it; }
for(auto it = clusters.find(&sector); it != clusters.end() && it.key() == &sector; )
{
delete *it;
}
clusters.remove(&sector);

typedef QList<ConvexSubspace *> Subspaces;
Expand All @@ -735,7 +740,7 @@ DENG2_PIMPL(Map)
* starting with a set per subspace and then keep merging these sets until
* no more shared edges are found.
*/
foreach(ConvexSubspace *subspace, subspaces)
for(ConvexSubspace *subspace : subspaces)
{
if(subspace->bspLeaf().sectorPtr() == &sector)
{
Expand All @@ -755,7 +760,7 @@ DENG2_PIMPL(Map)
{
if(i == k) continue;

foreach(ConvexSubspace *subspace, subspaceSets[i])
for(ConvexSubspace *subspace : subspaceSets[i])
{
HEdge *baseHEdge = subspace->poly().hedge();
HEdge *hedge = baseHEdge;
Expand Down Expand Up @@ -792,7 +797,7 @@ DENG2_PIMPL(Map)
// Clustering complete.

// Build clusters.
foreach(Subspaces const &subspaceSet, subspaceSets)
for(Subspaces const &subspaceSet : subspaceSets)
{
// Subspace ownership is not given to the cluster.
clusters.insert(&sector, new SectorCluster(subspaceSet));
Expand Down Expand Up @@ -1611,9 +1616,27 @@ Map::Subspaces const &Map::subspaces() const
return d->subspaces;
}

Map::SectorClusters const &Map::clusters() const
LoopResult Map::forAllClusters(Sector *sector, std::function<LoopResult (SectorCluster &)> func)
{
if(sector)
{
for(auto it = d->clusters.constFind(sector); it != d->clusters.end() && it.key() == sector; ++it)
{
if(auto result = func(**it)) return result;
}
}

for(SectorCluster *cluster : d->clusters)
{
if(auto result = func(*cluster)) return result;
}

return LoopContinue;
}

int Map::clusterCount() const
{
return d->clusters;
return d->clusters.count();
}

#ifdef __CLIENT__
Expand Down
23 changes: 9 additions & 14 deletions doomsday/client/src/world/sector.cpp
Expand Up @@ -104,22 +104,19 @@ DENG2_PIMPL(Sector)
aaBox.clear();
bool haveGeometry = false;

Map::SectorClusters const &clusterMap = self.map().clusters();
Map::SectorClusters::const_iterator i = clusterMap.constFind(thisPublic);
while(i != clusterMap.end() && i.key() == thisPublic)
self.map().forAllClusters(thisPublic, [&] (SectorCluster &cluster)
{
SectorCluster *cluster = *i;
if(haveGeometry)
{
V2d_UniteBox(aaBox.arvec2, cluster->aaBox().arvec2);
V2d_UniteBox(aaBox.arvec2, cluster.aaBox().arvec2);
}
else
{
aaBox = cluster->aaBox();
aaBox = cluster.aaBox();
haveGeometry = true;
}
++i;
}
return LoopContinue;
});

// The XY origin of our sound emitter can now be updated as the center
// point of the sector geometry is now known.
Expand All @@ -141,13 +138,11 @@ DENG2_PIMPL(Sector)
needRoughAreaUpdate = false;

roughArea = 0;
Map::SectorClusters const &clusterMap = self.map().clusters();
Map::SectorClusters::const_iterator i = clusterMap.constFind(thisPublic);
while(i != clusterMap.end() && i.key() == thisPublic)
self.map().forAllClusters(thisPublic, [&] (SectorCluster &cluster)
{
roughArea += (*i)->roughArea();
++i;
}
roughArea += cluster.roughArea();
return LoopContinue;
});
}
#endif // __CLIENT__

Expand Down

0 comments on commit dd6f907

Please sign in to comment.