Skip to content

Commit

Permalink
SectionEdge: The class user must handle the degenerate case (top < bo…
Browse files Browse the repository at this point in the history
…ttom)

Note that top == bottom is not degenerate and is supported, however.

It remains to be seen whether this is semantically the right approach
for this class. We'll know for sure once the WallDivs implementation
has been revised.
  • Loading branch information
danij-deng committed May 2, 2013
1 parent c59caf1 commit 7f525a5
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 21 deletions.
14 changes: 11 additions & 3 deletions doomsday/client/include/map/hedge.h
Expand Up @@ -44,14 +44,17 @@ class Sector;
class SectionEdge
{
public:
de::WallDivs wallDivs;
/// Invalid range geometry was specified to prepare() @ingroup errors
DENG2_ERROR(InvalidError);

public:
SectionEdge(HEdge &hedge, int edge, int section);

void prepare(coord_t bottom, coord_t top);

int divisionCount() const { return _interceptCount - 2; }
bool isValid() const;

int divisionCount() const;

de::WallDivs::Intercept &firstDivision() const;

Expand All @@ -70,14 +73,19 @@ class SectionEdge
coord_t offset() const;

private:
void assertDivisionsInRange(coord_t low, coord_t hi);
void verifyValid() const;

void assertDivisionsInRange(coord_t low, coord_t hi) const;

void addPlaneIntercepts(coord_t bottom, coord_t top);

de::WallDivs wallDivs; /// @todo does not belong here.

HEdge *_hedge;
int _edge;
int _section;

bool _isValid;
int _interceptCount;
de::WallDivs::Intercept *_firstIntercept;
de::WallDivs::Intercept *_lastIntercept;
Expand Down
50 changes: 40 additions & 10 deletions doomsday/client/src/map/hedge.cpp
Expand Up @@ -355,30 +355,54 @@ SectionEdge::SectionEdge(HEdge &hedge, int edge, int section)
: _hedge(&hedge),
_edge(edge),
_section(section),
_isValid(false), // Not yet prepared.
_interceptCount(0),
_firstIntercept(0),
_lastIntercept(0)
{
DENG_ASSERT(_hedge->hasLineSide() && _hedge->lineSide().hasSections());
}

bool SectionEdge::isValid() const
{
return _isValid;
}

void SectionEdge::verifyValid() const
{
if(!isValid())
{
/// @throw InvalidError Invalid range geometry was specified.
throw InvalidError("SectionEdge::verifyValid", "Specified range geometry was not valid (top < bottom)");
}
}

int SectionEdge::divisionCount() const
{
return isValid()? _interceptCount - 2 : 0;
}

WallDivs::Intercept &SectionEdge::firstDivision() const
{
verifyValid();
return _firstIntercept->next();
}

WallDivs::Intercept &SectionEdge::lastDivision() const
{
verifyValid();
return _lastIntercept->prev();
}

WallDivs::Intercept &SectionEdge::bottom() const
{
verifyValid();
return *_firstIntercept;
}

WallDivs::Intercept &SectionEdge::top() const
{
verifyValid();
return *_lastIntercept;
}

Expand Down Expand Up @@ -517,18 +541,18 @@ void SectionEdge::addPlaneIntercepts(coord_t bottom, coord_t top)
/**
* Ensure the divisions do not exceed the specified range.
*/
void SectionEdge::assertDivisionsInRange(coord_t low, coord_t hi)
void SectionEdge::assertDivisionsInRange(coord_t low, coord_t hi) const
{
#ifdef DENG_DEBUG
if(wallDivs.isEmpty()) return;

WallDivs::Intercept *node = &wallDivs.first();
WallDivs::Intercept *icpt = &wallDivs.first();
forever
{
DENG2_ASSERT(node->distance() >= low && node->distance() <= hi);
DENG2_ASSERT(icpt->distance() >= low && icpt->distance() <= hi);

if(!node->hasNext()) break;
node = &node->next();
if(!icpt->hasNext()) break;
icpt = &icpt->next();
}
#else
DENG2_UNUSED2(low, hi);
Expand All @@ -539,22 +563,28 @@ void SectionEdge::prepare(coord_t bottom, coord_t top)
{
DENG_ASSERT(wallDivs.isEmpty());

// Nodes are arranged according to their Z axis height in ascending order.
// The first node is the bottom.
_isValid = (top >= bottom);
if(!_isValid) return;

// Intercepts are arranged in ascending distance order.

// The first intercept is the bottom.
wallDivs.intercept(bottom);

// Add nodes for intercepts.
// Add intercepts for neighboring planes (the "divisions").
addPlaneIntercepts(bottom, top);

// The last node is the top.
// The last intercept is the top.
wallDivs.intercept(top);

if(wallDivs.count() > 2)
{
wallDivs.sort();
assertDivisionsInRange(bottom, top);
}

// Sanity check.
assertDivisionsInRange(bottom, top);

_firstIntercept = &wallDivs.first();
_lastIntercept = &wallDivs.last();
_interceptCount = wallDivs.count();
Expand Down
15 changes: 7 additions & 8 deletions doomsday/client/src/render/rend_main.cpp
Expand Up @@ -1925,13 +1925,10 @@ static void prepareWallSectionEdges(SectionEdge &leftEdge, SectionEdge &rightEdg
R_SideSectionCoords(leftEdge.hedge().lineSide(), leftEdge.section(), frontSec, backSec,
&bottom, &top, &materialOrigin);

if(top > bottom)
{
leftEdge.prepare(bottom, top);
rightEdge.prepare(bottom, top);
leftEdge.prepare(bottom, top);
rightEdge.prepare(bottom, top);

materialOrigin.x += float(leftEdge.offset());
}
materialOrigin.x += float(leftEdge.offset());
}

/**
Expand Down Expand Up @@ -1967,7 +1964,8 @@ static bool prepareEdgesAndWriteWallSection(HEdge &hedge, int section, bool *opa

prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin);

if(rightEdge.top().distance() > leftEdge.bottom().distance())
if(leftEdge.isValid() && rightEdge.isValid() &&
rightEdge.top().distance() > leftEdge.bottom().distance())
{
bool wroteOpaquePoly =
writeWallSection(leftEdge, rightEdge, materialOrigin,
Expand Down Expand Up @@ -2021,7 +2019,8 @@ static bool writeWallSections2Twosided(HEdge &hedge, int sections)
Vector2f materialOrigin;

prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin);
if(rightEdge.top().distance() > leftEdge.bottom().distance())
if(leftEdge.isValid() && rightEdge.isValid() &&
rightEdge.top().distance() > leftEdge.bottom().distance())
{
opaque = writeWallSection(leftEdge, rightEdge, materialOrigin,
hedge, hedge.biasSurfaceForGeometryGroup(section));
Expand Down

0 comments on commit 7f525a5

Please sign in to comment.