Skip to content

Commit

Permalink
World|Sector: Improved sector plane mapping wrt nested alternating ma…
Browse files Browse the repository at this point in the history
…p hacks

Dynamic plane mapping now correctly resolves constructs involving
nested map hacks alternating between floor and ceiling mappings.

eternall.wad MAP02 is now interpreted and rendered correctly.
  • Loading branch information
danij-deng committed Sep 15, 2013
1 parent db1ad4a commit 3ce11b4
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 38 deletions.
14 changes: 14 additions & 0 deletions doomsday/client/include/world/sector.h
Expand Up @@ -111,6 +111,20 @@ class Sector : public de::MapElement
*/
Plane &plane(int planeIndex) const;

/**
* Returns the sector plane which defines the @em physical floor of the
* cluster.
* @see hasSector(), plane()
*/
inline Plane &floor() const { return plane(Sector::Floor); }

/**
* Returns the sector plane which defines the @em physical ceiling of the
* cluster.
* @see hasSector(), plane()
*/
inline Plane &ceiling() const { return plane(Sector::Ceiling); }

/**
* Returns the identified @em visual sector plane for the cluster (which
* may or may not be the same as the physical plane).
Expand Down
127 changes: 89 additions & 38 deletions doomsday/client/src/world/sectorcluster.cpp
Expand Up @@ -348,62 +348,113 @@ DENG2_OBSERVES(Plane, HeightChange)
return;

// Evaluate the boundary to determine if mapping is required.
Cluster *exteriorCluster = 0;
QSet<Cluster *> exteriorFloorClusters;
QSet<Cluster *> exteriorCeilingClusters;
foreach(BspLeaf *leaf, bspLeafs)
{
HEdge *base = leaf->poly().hedge();
HEdge *hedge = base;
do
{
if(hedge->mapElement())
{
DENG_ASSERT(hedge->twin().hasFace());
if(!hedge->mapElement())
continue;

// Only consider non-selfref edges whose back face lies
// in another cluster.
LineSideSegment const &seg = hedge->mapElement()->as<LineSideSegment>();
if(!seg.line().isSelfReferencing())
{
BspLeaf const &backLeaf = hedge->twin().face().mapElement()->as<BspLeaf>();
if(backLeaf.hasCluster())
{
Cluster *otherCluster = &backLeaf.cluster();
if(otherCluster != thisPublic &&
otherCluster->d->mappedVisFloor != thisPublic)
{
LineSide const &lineSide = seg.lineSide();
DENG_ASSERT(hedge->twin().hasFace());

if(lineSide.bottom().hasMaterial() &&
!lineSide.bottom().hasFixMaterial())
missingAllBottom = false;
// Only consider non-selfref edges whose back face lies
// in another cluster.
LineSideSegment const &seg = hedge->mapElement()->as<LineSideSegment>();
if(seg.line().isSelfReferencing())
continue;

if(lineSide.top().hasMaterial() &&
!lineSide.top().hasFixMaterial())
missingAllTop = false;
BspLeaf const &backLeaf = hedge->twin().face().mapElement()->as<BspLeaf>();
if(!backLeaf.hasCluster())
continue;

if(!missingAllBottom && !missingAllTop)
return;
Cluster *otherCluster = &backLeaf.cluster();
if(otherCluster == thisPublic)
continue;

// Remember the exterior cluster.
exteriorCluster = otherCluster;
}
}
LineSide const &lineSide = seg.lineSide();
if(missingAllBottom &&
otherCluster->d->mappedVisFloor != thisPublic)
{
if(lineSide.bottom().hasMaterial() &&
!lineSide.bottom().hasFixMaterial())
{
missingAllBottom = false;
}
else
{
// Remember the exterior cluster.
exteriorFloorClusters.insert(otherCluster);
}
}

if(missingAllTop &&
otherCluster->d->mappedVisCeiling != thisPublic)
{
if(lineSide.top().hasMaterial() &&
!lineSide.top().hasFixMaterial())
{
missingAllTop = false;
}
else
{
// Remember the exterior cluster.
exteriorCeilingClusters.insert(otherCluster);
}
}

if(!missingAllBottom && !missingAllTop)
return;
} while((hedge = &hedge->next()) != base);
}

if(!exteriorCluster) return;

if(missingAllBottom &&
exteriorCluster->visFloor().height() > sectorFloor.height())
if(missingAllBottom)
{
map(Sector::Floor, exteriorCluster);
foreach(Cluster *exteriorCluster, exteriorFloorClusters)
{
Plane &exteriorPlane = exteriorCluster->visFloor();
if(exteriorPlane.height() < sectorFloor.height())
continue;

QRectF boundingRect = qrectFromAABox(self.aaBox());
if(boundingRect.contains(qrectFromAABox(exteriorCluster->aaBox())))
{
exteriorCluster->d->map(Sector::Floor, thisPublic);
}
else if(mappedVisFloor == thisPublic)
{
if(exteriorPlane.height() > sectorFloor.height())
{
map(Sector::Floor, exteriorCluster);
}
}
}
}
if(missingAllTop &&
exteriorCluster->visCeiling().height() < sectorCeiling.height())

if(missingAllTop)
{
map(Sector::Ceiling, exteriorCluster);
foreach(Cluster *exteriorCluster, exteriorCeilingClusters)
{
Plane &exteriorPlane = exteriorCluster->visCeiling();
if(exteriorPlane.height() > sectorCeiling.height())
continue;

QRectF boundingRect = qrectFromAABox(self.aaBox());
if(boundingRect.contains(qrectFromAABox(exteriorCluster->aaBox())))
{
exteriorCluster->d->map(Sector::Ceiling, thisPublic);
}
else if(mappedVisCeiling == thisPublic)
{
if(exteriorPlane.height() < sectorCeiling.height())
{
map(Sector::Ceiling, exteriorCluster);
}
}
}
}
}
}
Expand Down Expand Up @@ -673,7 +724,7 @@ Plane &Sector::Cluster::visPlane(int planeIndex) const

/// @todo Cache this result.
Cluster *mappedCluster = (planeIndex == Ceiling? d->mappedVisCeiling : d->mappedVisFloor);
if(mappedCluster != this)
if(mappedCluster && mappedCluster != this)
{
return mappedCluster->visPlane(planeIndex);
}
Expand Down

0 comments on commit 3ce11b4

Please sign in to comment.