Skip to content

Commit

Permalink
Refactor|Map Renderer: Reworked wall section drawing to move more log…
Browse files Browse the repository at this point in the history
…ic to SectionEdge
  • Loading branch information
danij-deng committed May 7, 2013
1 parent 6549845 commit b2c6f39
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 85 deletions.
10 changes: 10 additions & 0 deletions doomsday/client/include/map/plane.h
Expand Up @@ -88,6 +88,16 @@ class Plane : public de::MapElement
/// @todo Refactor away.
void setInSectorIndex(int newIndex);

/**
* Returns @c true iff this is the floor plane of the owning sector.
*/
bool isSectorFloor() const;

/**
* Returns @c true iff this is the ceiling plane of the owning sector.
*/
bool isSectorCeiling() const;

/**
* Returns the Surface of the plane.
*/
Expand Down
4 changes: 4 additions & 0 deletions doomsday/client/include/map/sectionedge.h
Expand Up @@ -29,6 +29,8 @@
#include "HEdge"
#include "IHPlane"

class Surface;

/// Maximum number of intercepts in a SectionEdge.
#define SECTIONEDGE_MAX_INTERCEPTS 64

Expand Down Expand Up @@ -92,6 +94,8 @@ class SectionEdge

Line::Side &lineSide() const;

Surface &surface() const;

int section() const;

int divisionCount() const;
Expand Down
10 changes: 10 additions & 0 deletions doomsday/client/src/map/plane.cpp
Expand Up @@ -220,6 +220,16 @@ void Plane::setInSectorIndex(int newIndex)
d->inSectorIndex = newIndex;
}

bool Plane::isSectorFloor() const
{
return this == &sector().floor();
}

bool Plane::isSectorCeiling() const
{
return this == &sector().ceiling();
}

Surface &Plane::surface()
{
return d->surface;
Expand Down
5 changes: 5 additions & 0 deletions doomsday/client/src/map/sectionedge.cpp
Expand Up @@ -360,6 +360,11 @@ Line::Side &SectionEdge::lineSide() const
return *d->lineSide;
}

Surface &SectionEdge::surface() const
{
return d->lineSide->surface(d->section);
}

int SectionEdge::section() const
{
return d->section;
Expand Down
16 changes: 16 additions & 0 deletions doomsday/client/src/map/surface.cpp
Expand Up @@ -89,6 +89,20 @@ DENG2_PIMPL(Surface)
flags(0)
{}

/// @todo Refactor away -ds
inline bool isSideMiddle()
{
return owner.type() == DMU_SIDE && &self == &owner.castTo<Line::Side>()->middle();
}

/// @todo Refactor away -ds
inline bool isSectorExtraPlane()
{
if(owner.type() != DMU_PLANE) return false;
Plane const &plane = *owner.castTo<Plane>();
return !(plane.isSectorFloor() || plane.isSectorCeiling());
}

void notifyNormalChanged(Vector3f const &oldNormal)
{
// Predetermine which axes have changed.
Expand Down Expand Up @@ -438,6 +452,8 @@ float Surface::opacity() const

void Surface::setOpacity(float newOpacity)
{
DENG_ASSERT(d->isSideMiddle() || d->isSectorExtraPlane());

newOpacity = de::clamp(0.f, newOpacity, 1.f);
if(!de::fequal(d->opacity, newOpacity))
{
Expand Down
154 changes: 69 additions & 85 deletions doomsday/client/src/render/rend_main.cpp
Expand Up @@ -1162,28 +1162,28 @@ static float calcLightLevelDelta(Vector3f const &normal)
return (1.0f / 255) * (normal.x * 18) * rendLightWallAngle;
}

static Line::Side *findSideBlendNeighbor(Line::Side const &side, bool right, binangle_t *diff = 0)
static Line::Side *findSideBlendNeighbor(Line::Side const &side, int edge, binangle_t *diff = 0)
{
LineOwner const *farVertOwner = side.line().vertexOwner(side.lineSideId() ^ (int)right);
LineOwner const *farVertOwner = side.line().vertexOwner(side.lineSideId() ^ edge);

if(diff) *diff = 0;

Line *neighbor;
if(R_SideBackClosed(side))
{
neighbor = R_FindSolidLineNeighbor(side.sectorPtr(), &side.line(), farVertOwner, right, diff);
neighbor = R_FindSolidLineNeighbor(side.sectorPtr(), &side.line(), farVertOwner, edge, diff);
}
else
{
neighbor = R_FindLineNeighbor(side.sectorPtr(), &side.line(), farVertOwner, right, diff);
neighbor = R_FindLineNeighbor(side.sectorPtr(), &side.line(), farVertOwner, edge, diff);
}

// No suitable line neighbor?
if(!neighbor) return 0;

// Choose the correct side of the neighbor (determined by which vertex is shared).
Line::Side *otherSide;
if(&neighbor->vertex(right ^ 1) == &side.vertex(right))
if(&neighbor->vertex(edge ^ 1) == &side.vertex(edge))
otherSide = &neighbor->front();
else
otherSide = &neighbor->back();
Expand Down Expand Up @@ -1214,44 +1214,40 @@ static bool shouldSmoothLightLevels(Surface &sufA, Surface &sufB, binangle_t ang
* The DOOM lighting model applies a sector light level delta when drawing
* walls based on their 2D world angle.
*
* @todo: Use the half-edge rings instead of LineOwners.
*
* @param side Line side to calculate light level deltas for.
* @param section Section of the side for which deltas are to be calculated.
* @param edge Edge of the side for which deltas are to be calculated.
*
* Return values:
* @param deltaL Light delta for the left edge written here.
* @param deltaR Light delta for the right edge written here.
*
* @todo: Use the half-edge rings instead of LineOwners.
* @return Light delta for the specified wall section edge.
*/
static void wallSectionLightLevelDeltas(Line::Side &side, int section, float &deltaL, float &deltaR)
static float wallSectionEdgeLightLevelDelta(Line::Side &side, int section, int edge)
{
deltaL = 0;
deltaR = 0;

// Are light level deltas disabled?
if(rendLightWallAngle <= 0) return;
if(rendLightWallAngle <= 0) return 0;

// ...always if the surface's material was chosen as a HOM fix (lighting
// must be consistent with that applied to the relative back sector plane).
if(side.hasSections() && side.back().hasSections() &&
side.surface(section).hasFixMaterial())
return;
return 0;

deltaL = deltaR = calcLightLevelDelta(side.surface(section).normal());
float delta = calcLightLevelDelta(side.surface(section).normal());

// Is delta smoothing disabled?
if(!rendLightWallAngleSmooth) return;
if(!rendLightWallAngleSmooth) return delta;
// ...always for polyobj lines (no owner rings).
if(side.line().isFromPolyobj()) return;
if(side.line().isFromPolyobj()) return delta;

/**
* Smoothing is enabled, so find the neighbor sides for each edge which
* we will use to calculate the averaged lightlevel delta for each.
* Smoothing is enabled, so find the neighbor side for the specified edge
* which we will use to calculate the averaged lightlevel delta for each.
*
* @todo Do not assume the neighbor is the middle section of @var otherSide.
*/
binangle_t angleDiff;

if(Line::Side *otherSide = findSideBlendNeighbor(side, false /*left neighbor*/, &angleDiff))
if(Line::Side *otherSide = findSideBlendNeighbor(side, edge, &angleDiff))
{
Surface &sufA = side.surface(section);
Surface &sufB = otherSide->surface(section);
Expand All @@ -1260,22 +1256,34 @@ static void wallSectionLightLevelDeltas(Line::Side &side, int section, float &de
{
// Average normals.
Vector3f avgNormal = Vector3f(sufA.normal() + sufB.normal()) / 2;
deltaL = calcLightLevelDelta(avgNormal);
return calcLightLevelDelta(avgNormal);
}
}

// Do the same for the right edge but with the right neighbor side.
if(Line::Side *otherSide = findSideBlendNeighbor(side, true /*right neighbor*/, &angleDiff))
return delta;
}

/**
* Calculate the light level deltas for this wall section.
* @todo Cache these values somewhere. -ds
*/
static void wallSectionLightLevelDeltas(SectionEdge const &leftEdge, SectionEdge const &rightEdge,
float &leftDelta, float &rightDelta)
{
leftDelta = wallSectionEdgeLightLevelDelta(leftEdge.lineSide(), leftEdge.section(), HEdge::From);
rightDelta = wallSectionEdgeLightLevelDelta(rightEdge.lineSide(), rightEdge.section(), HEdge::To);

if(!de::fequal(leftDelta, rightDelta))
{
Surface &sufA = side.surface(section);
Surface &sufB = otherSide->surface(section);
// Linearly interpolate to find the light level delta values for the
// vertical edges of this wall section.
coord_t const lineLength = leftEdge.lineSide().line().length();
coord_t const sectionOffset = leftEdge.lineOffset();
coord_t const sectionWidth = de::abs(Vector2d(rightEdge.origin() - leftEdge.origin()).length());

if(shouldSmoothLightLevels(sufA, sufB, angleDiff))
{
// Average normals.
Vector3f avgNormal = Vector3f(sufA.normal() + sufB.normal()) / 2;
deltaR = calcLightLevelDelta(avgNormal);
}
float deltaDiff = rightDelta - leftDelta;
rightDelta = leftDelta + ((sectionOffset + sectionWidth) / lineLength) * deltaDiff;
leftDelta += (sectionOffset / lineLength) * deltaDiff;
}
}

Expand Down Expand Up @@ -1343,13 +1351,6 @@ static uint projectSurfaceShadows(Surface &surface, float glowStrength,
surface.tangent(), surface.bitangent(), surface.normal());
}

static inline float wallSectionOpacity(Line::Side &side, int section)
{
if(section != Line::Side::Middle) return 1.f;
if(!side.hasSections() || !side.back().hasSections()) return 1.f;
return side.surface(section).opacity();
}

/**
* @defgroup writeWallSectionFlags Write Wall Section Flags
* Flags for writeWallSection()
Expand Down Expand Up @@ -1378,24 +1379,24 @@ static bool writeWallSection(SectionEdge const &leftEdge, SectionEdge const &rig
DENG_ASSERT(rightEdge.top().distance() > leftEdge.bottom().distance());

Line::Side &side = leftEdge.lineSide();
Line &line = side.line();
int const section = leftEdge.section();
Surface &surface = side.surface(section);
Surface &surface = leftEdge.surface();

bool const isTwoSidedMiddle = (section == Line::Side::Middle &&
side.hasSections() && side.back().hasSections());

float opacity = wallSectionOpacity(side, section);
float opacity = surface.opacity();

// Apply a fade out when the viewer is near to this geometry?
bool didNearFade = false;
if(isTwoSidedMiddle &&
((viewPlayer->shared.flags & (DDPF_NOCLIP|DDPF_CAMERA)) ||
!(side.line().isFlagged(DDLF_BLOCKING))) &&
!(line.isFlagged(DDLF_BLOCKING))) &&
(vOrigin[VY] > leftEdge.bottom().distance() &&
vOrigin[VY] < rightEdge.top().distance()))
{
mobj_t const *mo = viewPlayer->shared.mo;
Line const &line = side.line();

coord_t linePoint[2] = { line.fromOrigin().x, line.fromOrigin().y };
coord_t lineDirection[2] = { line.direction().x, line.direction().y };
Expand Down Expand Up @@ -1444,24 +1445,9 @@ static bool writeWallSection(SectionEdge const &leftEdge, SectionEdge const &rig
if(!material || !material->isDrawable())
return false;

coord_t width = de::abs(Vector2d(rightEdge.origin() - leftEdge.origin()).length());

// Calculate the light level deltas for this wall section.
/// @todo Cache these values somewhere. -ds
float deltaL, deltaR;
wallSectionLightLevelDeltas(side, section, deltaL, deltaR);

if(!de::fequal(deltaL, deltaR))
{
// Linearly interpolate to find the light level delta values for the
// vertical edges of this wall section.
coord_t const lineLength = side.line().length();
coord_t const sectionOffset = leftEdge.lineOffset();

float deltaDiff = deltaR - deltaL;
deltaR = deltaL + ((sectionOffset + width) / lineLength) * deltaDiff;
deltaL += (sectionOffset / lineLength) * deltaDiff;
}
float leftLightLevelDelta, rightLightLevelDelta;
wallSectionLightLevelDeltas(leftEdge, rightEdge, leftLightLevelDelta, rightLightLevelDelta);

rendworldpoly_params_t parm; zap(parm);

Expand All @@ -1474,14 +1460,14 @@ static bool writeWallSection(SectionEdge const &leftEdge, SectionEdge const &rig
parm.normal = &surface.normal();
parm.texTL = &texTL;
parm.texBR = &texBR;
parm.surfaceLightLevelDL = deltaL;
parm.surfaceLightLevelDR = deltaR;
parm.surfaceLightLevelDL = leftLightLevelDelta;
parm.surfaceLightLevelDR = rightLightLevelDelta;
parm.blendMode = BM_NORMAL;
parm.materialOrigin = &leftEdge.materialOrigin();
parm.materialScale = &materialScale;

parm.isWall = true;
parm.wall.sectionWidth = width;
parm.wall.sectionWidth = de::abs(Vector2d(rightEdge.origin() - leftEdge.origin()).length());
parm.wall.leftEdge = &leftEdge;
parm.wall.rightEdge = &rightEdge;

Expand Down Expand Up @@ -1583,34 +1569,32 @@ static bool writeWallSection(SectionEdge const &leftEdge, SectionEdge const &rig
if(opaque)
{
// Render FakeRadio for this section?
if((flags & WSF_ADD_RADIO) &&
!((parm.flags & RPF_SKYMASK) || parm.glowing > 0 || side.line().isFromPolyobj()))
if((flags & WSF_ADD_RADIO) && !(parm.flags & RPF_SKYMASK) &&
!(parm.glowing > 0) && currentSectorLightLevel > 0 &&
!line.isFromPolyobj())
{
if(currentSectorLightLevel > 0)
{
Rend_RadioUpdateForLineSide(side);
Rend_RadioUpdateForLineSide(side);

// Determine the shadow properties.
/// @todo Make cvars out of constants.
float shadowSize = 2 * (8 + 16 - currentSectorLightLevel * 16);
float shadowDark = Rend_RadioCalcShadowDarkness(currentSectorLightLevel);
// Determine the shadow properties.
/// @todo Make cvars out of constants.
float shadowSize = 2 * (8 + 16 - currentSectorLightLevel * 16);
float shadowDark = Rend_RadioCalcShadowDarkness(currentSectorLightLevel);

Sector *frontSec = 0, *backSec = 0;
Sector *frontSec = 0, *backSec = 0;
{
HEdge *hedge = mapElement.castTo<HEdge>();
frontSec = hedge->wallSectionSector();
if(hedge->hasTwin() && !isTwoSidedMiddle)
{
HEdge *hedge = mapElement.castTo<HEdge>();
frontSec = hedge->wallSectionSector();
if(hedge->hasTwin() && !isTwoSidedMiddle)
if(hedge->twin().hasLineSide() && hedge->twin().lineSide().hasSections())
{
if(hedge->twin().hasLineSide() && hedge->twin().lineSide().hasSections())
{
backSec = hedge->twin().bspLeaf().sectorPtr();
}
backSec = hedge->twin().bspLeaf().sectorPtr();
}
}

Rend_RadioWallSection(leftEdge, rightEdge, shadowDark, shadowSize,
frontSec, backSec);
}

Rend_RadioWallSection(leftEdge, rightEdge, shadowDark, shadowSize,
frontSec, backSec);
}
}

Expand Down

0 comments on commit b2c6f39

Please sign in to comment.