Skip to content

Commit

Permalink
Client|Map Renderer|WallEdge: Allocate storage for the first and last…
Browse files Browse the repository at this point in the history
… elements along with the edge

Todo: Performance is currently less than ideal as far as the old map
renderer is concerned (which presently rebuilds all wall geometries
each time they are needed). Idea: avoid sorting intercept instances
by mapping their properties to values owned by the edge instance.
  • Loading branch information
danij-deng committed May 24, 2013
1 parent 2ef1b6a commit 67e1c61
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 30 deletions.
2 changes: 1 addition & 1 deletion doomsday/client/include/ihplane.h
Expand Up @@ -71,7 +71,7 @@ class IHPlane
*/
virtual ddouble distance() const { return _distance; }

private:
protected:
ddouble _distance;
};

Expand Down
7 changes: 6 additions & 1 deletion doomsday/client/include/render/walledge.h
Expand Up @@ -66,6 +66,11 @@ class WallEdge : public IEdge

Vector3d origin() const;

friend class WallEdge;

protected:
void setDistance(double newDistance);

private:
DENG2_PRIVATE(d)
};
Expand All @@ -74,7 +79,7 @@ class WallEdge : public IEdge

public:
/**
* @param spec Wall section spec. A copy is made.
* @param spec Geometry specification for the wall section. A copy is made.
*/
WallEdge(WallSpec const &spec, HEdge &hedge, int edge);

Expand Down
81 changes: 53 additions & 28 deletions doomsday/client/src/render/walledge.cpp
Expand Up @@ -45,6 +45,11 @@ static bool shouldSmoothNormals(Surface &sufA, Surface &sufB, binangle_t angleDi
return INRANGE_OF(angleDiff, BANG_180, BANG_45);
}

static bool interceptSorter(WallEdge::Intercept *a, WallEdge::Intercept *b)
{
return *a < *b;
}

DENG2_PIMPL_NOREF(WallEdge::Intercept)
{
/// Wall edge instance which owns "this" intercept.
Expand All @@ -68,6 +73,11 @@ double WallEdge::Intercept::distance() const
return IHPlane::IIntercept::distance();
}

void WallEdge::Intercept::setDistance(double newDistance)
{
IHPlane::IIntercept::_distance = newDistance;
}

Vector3d WallEdge::Intercept::origin() const
{
return Vector3d(d->owner.origin(), distance());
Expand All @@ -86,6 +96,10 @@ DENG2_PIMPL(WallEdge), public IHPlane
Vector2f materialOrigin;
Vector3f edgeNormal;

/// Intercepts for the bottom and top edges are allocated with "this".
WallEdge::Intercept bottom;
WallEdge::Intercept top;

/// Data for the IHPlane model.
struct HPlane
{
Expand All @@ -104,15 +118,14 @@ DENG2_PIMPL(WallEdge), public IHPlane
: partition (other.partition),
intercepts (other.intercepts),
needSortIntercepts(other.needSortIntercepts)
{}

~HPlane() { clearIntercepts(); }

void clearIntercepts()
{
qDeleteAll(intercepts);
#ifdef DENG2_QT_4_7_OR_NEWER
intercepts.reserve(2 + 2);
#endif
}

~HPlane() { DENG_ASSERT(intercepts.isEmpty()); }

} hplane;

Instance(Public *i, WallSpec const &spec, Line::Side *mapSide, int edge,
Expand All @@ -123,8 +136,21 @@ DENG2_PIMPL(WallEdge), public IHPlane
edge(edge),
lineOffset(lineOffset),
lineVertex(lineVertex),
isValid(false)
{}
isValid(false),
bottom(*i),
top(*i)
{
coord_t lo, hi;
R_SideSectionCoords(*mapSide, spec.section, spec.flags.testFlag(WallSpec::SkyClip),
&lo, &hi, &materialOrigin);

bottom.setDistance(lo);
top.setDistance(hi);

isValid = (top.distance() >= bottom.distance());
}

~Instance() { clearIntercepts(); }

void verifyValid() const
{
Expand Down Expand Up @@ -179,14 +205,18 @@ DENG2_PIMPL(WallEdge), public IHPlane
// Any work to do?
if(!hplane.needSortIntercepts) return;

qSort(hplane.intercepts.begin(), hplane.intercepts.end());

qSort(hplane.intercepts.begin(), hplane.intercepts.end(), interceptSorter);
hplane.needSortIntercepts = false;
}

// Implements IHPlane
void clearIntercepts()
{
foreach(WallEdge::Intercept *icpt, hplane.intercepts)
{
if(icpt == &bottom || icpt == &top) continue;
delete icpt;
}
hplane.intercepts.clear();
// An empty intercept list is logically sorted.
hplane.needSortIntercepts = false;
Expand Down Expand Up @@ -388,40 +418,35 @@ DENG2_PIMPL(WallEdge), public IHPlane

void prepare()
{
coord_t bottom, top;
R_SideSectionCoords(*mapSide, spec.section, spec.flags.testFlag(WallSpec::SkyClip),
&bottom, &top, &materialOrigin);

isValid = (top >= bottom);
if(!isValid) return;

materialOrigin.x += lineOffset;

configure(Partition(lineVertex->origin(), Vector2d(0, top - bottom)));
coord_t const lo = bottom.distance();
coord_t const hi = top.distance();

// Intercepts are sorted in ascending distance order.
configure(Partition(lineVertex->origin(), Vector2d(0, hi - lo)));

// The first intercept is the bottom.
intercept(bottom);
// Intercepts are sorted in ascending distance order.

if(top > bottom)
if(!de::fequal(hi, lo))
{
// Add intercepts for neighboring planes (the "divisions").
addPlaneIntercepts(bottom, top);
}

// The last intercept is the top.
intercept(top);
addPlaneIntercepts(lo, hi);

if(interceptCount() > 2) // First two are always sorted.
{
// Sorting may be required. This shouldn't take too long...
// There seldom are more than two or three intercepts.
sortAndMergeIntercepts();
}

// The first intercept is the bottom.
hplane.intercepts.prepend(&bottom);

// The last intercept is the top.
hplane.intercepts.append(&top);

// Sanity check.
assertInterceptsInRange(bottom, top);
assertInterceptsInRange(lo, hi);

// Determine the edge normal.
/// @todo Cache the smoothed normal value somewhere.
Expand Down

0 comments on commit 67e1c61

Please sign in to comment.