From 085b4a535a2c63dfc6178c62c46a6c00500ba96a Mon Sep 17 00:00:00 2001 From: danij Date: Wed, 1 May 2013 16:44:56 +0100 Subject: [PATCH] Map Renderer: Began remodeling wall geometry construction Transitioning to an edge-centric model. --- doomsday/client/include/map/hedge.h | 49 ++ .../client/include/render/rend_dynlight.h | 15 +- .../client/include/render/rend_fakeradio.h | 18 +- doomsday/client/include/render/rend_shadow.h | 15 +- doomsday/client/include/render/rendpoly.h | 11 +- doomsday/client/include/render/walldiv.h | 105 +--- doomsday/client/src/map/hedge.cpp | 291 +++++++++ doomsday/client/src/render/rend_dynlight.cpp | 33 +- doomsday/client/src/render/rend_fakeradio.cpp | 38 +- doomsday/client/src/render/rend_main.cpp | 594 +++++++----------- doomsday/client/src/render/rend_shadow.cpp | 31 +- doomsday/client/src/render/rendpoly.cpp | 64 +- 12 files changed, 723 insertions(+), 541 deletions(-) diff --git a/doomsday/client/include/map/hedge.h b/doomsday/client/include/map/hedge.h index c70ca6688b..2121b30724 100644 --- a/doomsday/client/include/map/hedge.h +++ b/doomsday/client/include/map/hedge.h @@ -29,6 +29,7 @@ #include "Vertex" #include "render/rend_bias.h" +#include "render/walldiv.h" class Sector; @@ -40,6 +41,54 @@ class Sector; #define HEDGEINF_FACINGFRONT 0x0001 ///@} +class SectionEdge +{ +public: + de::WallDivs wallDivs; + +public: + SectionEdge(HEdge &hedge, int section, int right); + + void prepare(coord_t bottom, coord_t top); + + void configure() { + _firstIntercept = &wallDivs.first(); + _lastIntercept = &wallDivs.last(); + _interceptCount = wallDivs.count(); + } + + int divisionCount() const { return _interceptCount - 2; } + + de::WallDivs::Intercept &firstDivision() const; + + de::WallDivs::Intercept &lastDivision() const; + + de::WallDivs::Intercept &bottom() const; + + de::WallDivs::Intercept &top() const; + + HEdge &hedge() const; + + int section() const; + + de::Vector2d const &origin() const; + + coord_t offset() const; + +private: + void assertDivisionsInRange(coord_t low, coord_t hi); + + void addPlaneIntercepts(coord_t bottom, coord_t top); + + HEdge *_hedge; + int _section; + int _right; + + int _interceptCount; + de::WallDivs::Intercept *_firstIntercept; + de::WallDivs::Intercept *_lastIntercept; +}; + /** * Map geometry half-edge. * diff --git a/doomsday/client/include/render/rend_dynlight.h b/doomsday/client/include/render/rend_dynlight.h index 723b494835..f19692e8a8 100644 --- a/doomsday/client/include/render/rend_dynlight.h +++ b/doomsday/client/include/render/rend_dynlight.h @@ -22,8 +22,9 @@ #include -#include "render/rendpoly.h" -#include "render/walldiv.h" +//#include "render/rendpoly.h" + +#include "HEdge" /// Paramaters for Rend_RenderLightProjections (POD). typedef struct { @@ -34,14 +35,8 @@ typedef struct { de::Vector3d const *texBR; bool isWall; struct { - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } left; - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } right; + SectionEdge const *leftEdge; + SectionEdge const *rightEdge; } wall; } renderlightprojectionparams_t; diff --git a/doomsday/client/include/render/rend_fakeradio.h b/doomsday/client/include/render/rend_fakeradio.h index e64cde2aa1..1918f53a09 100644 --- a/doomsday/client/include/render/rend_fakeradio.h +++ b/doomsday/client/include/render/rend_fakeradio.h @@ -34,11 +34,11 @@ #ifndef DENG_RENDER_FAKERADIO #define DENG_RENDER_FAKERADIO +#include "HEdge" #include "Line" -#include "Vertex" #include "Sector" -#include "render/rendpoly.h" -#include "render/walldiv.h" +#include "Vertex" +//#include "render/rendpoly.h" /** * Used to link a line to a BSP leaf for the purposes of FakeRadio shadowing. @@ -159,16 +159,8 @@ struct RendRadioWallSectionParms coord_t segLength; Line const *line; Sector const *frontSec, *backSec; - struct { - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } left; - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } right; - } wall; + SectionEdge const *leftEdge; + SectionEdge const *rightEdge; }; /** diff --git a/doomsday/client/include/render/rend_shadow.h b/doomsday/client/include/render/rend_shadow.h index 852c7df93f..1b72d44e6f 100644 --- a/doomsday/client/include/render/rend_shadow.h +++ b/doomsday/client/include/render/rend_shadow.h @@ -22,8 +22,9 @@ #include -#include "render/rendpoly.h" -#include "render/walldiv.h" +//#include "render/rendpoly.h" + +#include "HEdge" /** * This value defines the offset from the shadowed surface applied to @@ -51,14 +52,8 @@ typedef struct { de::Vector3d const *texBR; bool isWall; struct { - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } left; - struct { - de::WallDivs::Intercept *firstDiv; - uint divCount; - } right; + SectionEdge const *leftEdge; + SectionEdge const *rightEdge; } wall; } rendershadowprojectionparams_t; diff --git a/doomsday/client/include/render/rendpoly.h b/doomsday/client/include/render/rendpoly.h index c3a327a0ea..ccbca50cad 100644 --- a/doomsday/client/include/render/rendpoly.h +++ b/doomsday/client/include/render/rendpoly.h @@ -29,7 +29,7 @@ #include -#include "render/walldiv.h" +class SectionEdge; typedef struct rvertex_s { float pos[3]; @@ -211,17 +211,14 @@ inline void Rtu_TranslateOffset(rtexmapunit_t *rtu, float s, float t) } void R_DivVerts(rvertex_t *dst, rvertex_t const *src, - de::WallDivs::Intercept *leftDivFirst, uint leftDivCount, - de::WallDivs::Intercept *rightDivFirst, uint rightDivCount); + SectionEdge const &leftEdge, SectionEdge const &rightEdge); void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, - de::WallDivs::Intercept *leftDivFirst, uint leftDivCount, - de::WallDivs::Intercept *rightDivFirst, uint rightDivCount, + SectionEdge const &leftEdge, SectionEdge const &rightEdge, float bL, float tL, float bR, float tR); void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, - de::WallDivs::Intercept *leftDivFirst, uint leftDivCount, - de::WallDivs::Intercept *rightDivFirst, uint rightDivCount, + SectionEdge const &leftEdge, SectionEdge const &rightEdge, float bL, float tL, float bR, float tR); #endif // DENG_RENDER_RENDPOLY_H diff --git a/doomsday/client/include/render/walldiv.h b/doomsday/client/include/render/walldiv.h index 06b282fdaf..2d863df2e6 100644 --- a/doomsday/client/include/render/walldiv.h +++ b/doomsday/client/include/render/walldiv.h @@ -37,19 +37,23 @@ class WallDivs class Intercept { protected: - Intercept() : _wallDivs(0), _distance(0) {} + Intercept(ddouble distance = 0); public: - ddouble operator - (Intercept const &other) const - { - return distance() - other.distance(); + bool operator < (Intercept const &other) const { + return _distance < other._distance; } - bool operator < (Intercept const &other) const - { - return distance() < other.distance(); + /** + * Determine the distance between "this" and the @a other intercept. + */ + ddouble operator - (Intercept const &other) const { + return _distance - other._distance; } + /** + * Returns distance along the half-plane relative to the origin. + */ ddouble distance() const { return _distance; } bool hasNext() const @@ -84,11 +88,17 @@ class WallDivs throw WallDivs::MissingInterceptError("WallDivs::Intercept", "No previous neighbor"); } +#ifdef DENG_DEBUG + void debugPrint() const; +#endif + friend class WallDivs; private: - WallDivs *_wallDivs; + /// Distance along the half-plane relative to the origin. ddouble _distance; + + WallDivs *_wallDivs; }; typedef Intercept Intercepts[WALLDIVS_MAX_INTERCEPTS]; @@ -121,80 +131,27 @@ class WallDivs throw MissingInterceptError("WallDivs::last", "Intercepts list is empty"); } - void append(ddouble distance) - { - Intercept *node = &_intercepts[_interceptCount++]; - node->_wallDivs = this; - node->_distance = distance; - } + bool intercept(ddouble distance); - Intercept *find(ddouble distance) const - { - for(int i = 0; i < _interceptCount; ++i) - { - Intercept *icpt = const_cast(&_intercepts[i]); - if(icpt->distance() == distance) - return icpt; - } - return 0; - } - - static int compareIntercepts(void const *e1, void const *e2) - { - ddouble const delta = (*reinterpret_cast(e1)) - (*reinterpret_cast(e2)); - if(delta > 0) return 1; - if(delta < 0) return -1; - return 0; - } - - void sort() - { - if(count() < 2) return; - - // Sorting is required. This shouldn't take too long... - // There seldom are more than two or three intercepts. - qsort(_intercepts, _interceptCount, sizeof(*_intercepts), compareIntercepts); - assertSorted(); - } + void sort(); #ifdef DENG_DEBUG - void debugPrint() const - { - LOG_DEBUG("WallDivs [%p]:") << de::dintptr(this); - for(int i = 0; i < _interceptCount; ++i) - { - Intercept const *node = &_intercepts[i]; - LOG_DEBUG(" %i: %f") << i << node->distance(); - } - } + void printIntercepts() const; #endif - Intercepts const &intercepts() const - { - return _intercepts; - } - -private: /** - * Ensure the intercepts are sorted (in ascending distance order). + * Returns the list of intercepts for the half-plane for efficient traversal. + * + * @note This list may or may not yet be sorted. If a sorted list is desired + * then sortAndMergeIntercepts() should first be called. + * + * @see interceptLineSegment(), intercepts() */ - void assertSorted() const - { -#ifdef DENG_DEBUG - if(isEmpty()) return; - - WallDivs::Intercept *node = &first(); - ddouble farthest = node->distance(); - forever - { - DENG2_ASSERT(node->distance() >= farthest); - farthest = node->distance(); + Intercepts const &intercepts() const; - if(!node->hasNext()) break; - node = &node->next(); - } -#endif - } +private: + Intercept *find(ddouble distance) const; + void assertSorted() const; int _interceptCount; Intercepts _intercepts; diff --git a/doomsday/client/src/map/hedge.cpp b/doomsday/client/src/map/hedge.cpp index 12fa37cb96..8dc4e7a87d 100644 --- a/doomsday/client/src/map/hedge.cpp +++ b/doomsday/client/src/map/hedge.cpp @@ -243,3 +243,294 @@ int HEdge::property(setargs_t &args) const return false; // Continue iteration. } + +// --------------------------------------------------------------------- + +#include "map/r_world.h" // R_GetVtxLineOwner +#include "map/lineowner.h" + +static int compareIntercepts(void const *e1, void const *e2) +{ + ddouble const delta = (*reinterpret_cast(e1)) - (*reinterpret_cast(e2)); + if(delta > 0) return 1; + if(delta < 0) return -1; + return 0; +} + +WallDivs::Intercept *WallDivs::find(ddouble distance) const +{ + for(int i = 0; i < _interceptCount; ++i) + { + Intercept *icpt = const_cast(&_intercepts[i]); + if(icpt->distance() == distance) + return icpt; + } + return 0; +} + +/** + * Ensure the intercepts are sorted (in ascending distance order). + */ +void WallDivs::assertSorted() const +{ +#ifdef DENG_DEBUG + if(isEmpty()) return; + + WallDivs::Intercept *node = &first(); + ddouble farthest = node->distance(); + forever + { + DENG2_ASSERT(node->distance() >= farthest); + farthest = node->distance(); + + if(!node->hasNext()) break; + node = &node->next(); + } +#endif +} + +WallDivs::Intercept::Intercept(ddouble distance) + : _distance(distance), _wallDivs(0) +{} + +bool WallDivs::intercept(ddouble distance) +{ + if(find(distance)) + return false; + + Intercept *icpt = &_intercepts[_interceptCount++]; + icpt->_wallDivs = this; + icpt->_distance = distance; + return true; +} + +void WallDivs::sort() +{ + if(count() < 2) return; + + // Sorting is required. This shouldn't take too long... + // There seldom are more than two or three intercepts. + qsort(_intercepts, _interceptCount, sizeof(*_intercepts), compareIntercepts); + assertSorted(); +} + +#ifdef DENG_DEBUG +void WallDivs::printIntercepts() const +{ + // Stub. +} +#endif + +WallDivs::Intercepts const &WallDivs::intercepts() const +{ + return _intercepts; +} + +SectionEdge::SectionEdge(HEdge &hedge, int section, int right) + : _hedge(&hedge), + _section(section), + _right(right), + _interceptCount(0), + _firstIntercept(0), + _lastIntercept(0) +{ + DENG_ASSERT(_hedge->hasLineSide() && _hedge->lineSide().hasSections()); +} + +WallDivs::Intercept &SectionEdge::firstDivision() const +{ + return _firstIntercept->next(); +} + +WallDivs::Intercept &SectionEdge::lastDivision() const +{ + return _lastIntercept->prev(); +} + +WallDivs::Intercept &SectionEdge::bottom() const +{ + return *_firstIntercept; +} + +WallDivs::Intercept &SectionEdge::top() const +{ + return *_lastIntercept; +} + +HEdge &SectionEdge::hedge() const +{ + return *_hedge; +} + +int SectionEdge::section() const +{ + return _section; +} + +Vector2d const &SectionEdge::origin() const +{ + return _hedge->vertex(_right).origin(); +} + +coord_t SectionEdge::offset() const +{ + return _hedge->lineOffset() + (_right? _hedge->length() : 0); +} + +void SectionEdge::addPlaneIntercepts(coord_t bottom, coord_t top) +{ + if(!_hedge->hasLineSide()) return; + + Line::Side const &side = _hedge->lineSide(); + if(side.line().isFromPolyobj()) return; + + // Check for neighborhood division? + if(_section == Line::Side::Middle && side.hasSections() && side.back().hasSections()) + return; + + // Only sections at line side edges can/should be split. + if(!((_hedge == side.leftHEdge() && !_right) || + (_hedge == side.rightHEdge() && _right))) + return; + + if(bottom >= top) return; // Obviously no division. + + Sector const *frontSec = side.sectorPtr(); + + LineOwner::Direction direction(_right? LineOwner::Previous : LineOwner::Next); + // Retrieve the start owner node. + LineOwner *base = R_GetVtxLineOwner(&side.line().vertex(_right), &side.line()); + LineOwner *own = base; + bool stopScan = false; + do + { + own = &own->navigate(direction); + + if(own == base) + { + stopScan = true; + } + else + { + Line *iter = &own->line(); + + if(iter->isSelfReferencing()) + continue; + + uint i = 0; + do + { + // First front, then back. + Sector *scanSec = 0; + if(!i && iter->hasFrontSections() && iter->frontSectorPtr() != frontSec) + scanSec = iter->frontSectorPtr(); + else if(i && iter->hasBackSections() && iter->backSectorPtr() != frontSec) + scanSec = iter->backSectorPtr(); + + if(scanSec) + { + if(scanSec->ceiling().visHeight() - scanSec->floor().visHeight() > 0) + { + for(int j = 0; j < scanSec->planeCount() && !stopScan; ++j) + { + Plane const &plane = scanSec->plane(j); + + if(plane.visHeight() > bottom && plane.visHeight() < top) + { + if(wallDivs.intercept(plane.visHeight())) + { + // Have we reached the div limit? + if(wallDivs.count() == WALLDIVS_MAX_INTERCEPTS) + stopScan = true; + } + } + + if(!stopScan) + { + // Clip a range bound to this height? + if(plane.type() == Plane::Floor && plane.visHeight() > bottom) + bottom = plane.visHeight(); + else if(plane.type() == Plane::Ceiling && plane.visHeight() < top) + top = plane.visHeight(); + + // All clipped away? + if(bottom >= top) + stopScan = true; + } + } + } + else + { + /** + * A zero height sector is a special case. In this + * instance, the potential division is at the height + * of the back ceiling. This is because elsewhere + * we automatically fix the case of a floor above a + * ceiling by lowering the floor. + */ + coord_t z = scanSec->ceiling().visHeight(); + + if(z > bottom && z < top) + { + if(wallDivs.intercept(z)) + { + // All clipped away. + stopScan = true; + } + } + } + } + } while(!stopScan && ++i < 2); + + // Stop the scan when a single sided line is reached. + if(!iter->hasFrontSections() || !iter->hasBackSections()) + stopScan = true; + } + } while(!stopScan); +} + +/** + * Ensure the divisions do not exceed the specified range. + */ +void SectionEdge::assertDivisionsInRange(coord_t low, coord_t hi) +{ +#ifdef DENG_DEBUG + if(wallDivs.isEmpty()) return; + + WallDivs::Intercept *node = &wallDivs.first(); + forever + { + DENG2_ASSERT(node->distance() >= low && node->distance() <= hi); + + if(!node->hasNext()) break; + node = &node->next(); + } +#else + DENG2_UNUSED2(low, hi); +#endif +} + +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. + wallDivs.intercept(bottom); + + // Add nodes for intercepts. + addPlaneIntercepts(bottom, top); + + // The last node is the top. + wallDivs.intercept(top); + + if(wallDivs.count() > 2) + { + wallDivs.sort(); + assertDivisionsInRange(bottom, top); + } + + _firstIntercept = &wallDivs.first(); + _lastIntercept = &wallDivs.last(); + _interceptCount = wallDivs.count(); +} diff --git a/doomsday/client/src/render/rend_dynlight.cpp b/doomsday/client/src/render/rend_dynlight.cpp index 65e16d139a..5d180cac47 100644 --- a/doomsday/client/src/render/rend_dynlight.cpp +++ b/doomsday/client/src/render/rend_dynlight.cpp @@ -33,6 +33,7 @@ static void drawDynlight(dynlight_t const &dyn, renderlightprojectionparams_t &p rvertex_t *rvertices = R_AllocRendVertices(parm.realNumVertices); rtexcoord_t *rtexcoords = R_AllocRendTexCoords(parm.realNumVertices); ColorRawf *rcolors = R_AllocRendColors(parm.realNumVertices); + bool const mustSubdivide = (parm.isWall && (parm.wall.leftEdge->divisionCount() || parm.wall.rightEdge->divisionCount() )); for(uint i = 0; i < parm.numVertices; ++i) { @@ -43,15 +44,16 @@ static void drawDynlight(dynlight_t const &dyn, renderlightprojectionparams_t &p if(parm.isWall) { + SectionEdge const &leftEdge = *parm.wall.leftEdge; + SectionEdge const &rightEdge = *parm.wall.rightEdge; + rtexcoords[1].st[0] = rtexcoords[0].st[0] = dyn.s[0]; rtexcoords[1].st[1] = rtexcoords[3].st[1] = dyn.t[0]; rtexcoords[3].st[0] = rtexcoords[2].st[0] = dyn.s[1]; rtexcoords[2].st[1] = rtexcoords[0].st[1] = dyn.t[1]; - if(parm.wall.left.divCount || parm.wall.right.divCount) + if(mustSubdivide) { - // We need to subdivide the projection quad. - /* * Need to swap indices around into fans set the position * of the division vertices, interpolate texcoords and @@ -67,9 +69,9 @@ static void drawDynlight(dynlight_t const &dyn, renderlightprojectionparams_t &p float bR = parm.rvertices[2].pos[VZ]; float tR = parm.rvertices[3].pos[VZ]; - R_DivVerts(rvertices, origVerts, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount); - R_DivTexCoords(rtexcoords, origTexCoords, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount, bL, tL, bR, tR); - R_DivVertColors(rcolors, origColors, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount, bL, tL, bR, tR); + R_DivVerts(rvertices, origVerts, leftEdge, rightEdge); + R_DivTexCoords(rtexcoords, origTexCoords, leftEdge, rightEdge, bL, tL, bR, tR); + R_DivVertColors(rcolors, origColors, leftEdge, rightEdge, bL, tL, bR, tR); } else { @@ -98,18 +100,27 @@ static void drawDynlight(dynlight_t const &dyn, renderlightprojectionparams_t &p RL_Rtu_SetTextureUnmanaged(RTU_PRIMARY, dyn.texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); - if(parm.isWall && (parm.wall.left.divCount || parm.wall.right.divCount)) + if(mustSubdivide) { + SectionEdge const &leftEdge = *parm.wall.leftEdge; + SectionEdge const &rightEdge = *parm.wall.rightEdge; + int const leftInterceptCount = leftEdge.divisionCount(); + int const rightInterceptCount = rightEdge.divisionCount(); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_LIGHT, - 3 + parm.wall.right.divCount, rvertices + 3 + parm.wall.left.divCount, - rcolors + 3 + parm.wall.left.divCount, rtexcoords + 3 + parm.wall.left.divCount, NULL); + 3 + rightInterceptCount, + rvertices + 3 + leftInterceptCount, + rcolors + 3 + leftInterceptCount, + rtexcoords + 3 + leftInterceptCount, 0); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_LIGHT, - 3 + parm.wall.left.divCount, rvertices, rcolors, rtexcoords, NULL); + 3 + leftInterceptCount, + rvertices, rcolors, rtexcoords, 0); } else { RL_AddPolyWithCoords(parm.isWall? PT_TRIANGLE_STRIP : PT_FAN, RPF_DEFAULT|RPF_LIGHT, - parm.numVertices, rvertices, rcolors, rtexcoords, NULL); + parm.numVertices, rvertices, rcolors, rtexcoords, 0); } R_FreeRendVertices(rvertices); diff --git a/doomsday/client/src/render/rend_fakeradio.cpp b/doomsday/client/src/render/rend_fakeradio.cpp index 2e67d3a34f..8422f541bd 100644 --- a/doomsday/client/src/render/rend_fakeradio.cpp +++ b/doomsday/client/src/render/rend_fakeradio.cpp @@ -981,18 +981,20 @@ static void drawWallSectionShadow(rvertex_t const *origVertices, rendershadowseg_params_t const &wsParms, RendRadioWallSectionParms const &parms) { DENG_ASSERT(origVertices); + SectionEdge const &leftEdge = *parms.leftEdge; + SectionEdge const &rightEdge = *parms.rightEdge; + int const leftInterceptCount = leftEdge.divisionCount(); + int const rightInterceptCount = rightEdge.divisionCount(); + bool const mustSubdivide = (leftEdge.divisionCount() || rightEdge.divisionCount()); - float texOrigin[2][3]; - ColorRawf *rcolors; - rtexcoord_t *rtexcoords; uint realNumVertices = 4; - - if(parms.wall.left.divCount || parms.wall.right.divCount) - realNumVertices = 3 + parms.wall.left.divCount + 3 + parms.wall.right.divCount; + if(mustSubdivide) + realNumVertices = 3 + leftInterceptCount + 3 + rightInterceptCount; else realNumVertices = 4; // Top left. + float texOrigin[2][3]; texOrigin[0][VX] = origVertices[1].pos[VX]; texOrigin[0][VY] = origVertices[1].pos[VY]; texOrigin[0][VZ] = origVertices[1].pos[VZ]; @@ -1003,8 +1005,8 @@ static void drawWallSectionShadow(rvertex_t const *origVertices, texOrigin[1][VZ] = origVertices[2].pos[VZ]; // Allocate enough for the divisions too. - rtexcoords = R_AllocRendTexCoords(realNumVertices); - rcolors = R_AllocRendColors(realNumVertices); + rtexcoord_t *rtexcoords = R_AllocRendTexCoords(realNumVertices); + ColorRawf *rcolors = R_AllocRendColors(realNumVertices); quadTexCoords(rtexcoords, origVertices, wsParms.wallLength, wsParms.texWidth, wsParms.texHeight, texOrigin, wsParms.texOffset, @@ -1019,7 +1021,7 @@ static void drawWallSectionShadow(rvertex_t const *origVertices, RL_Rtu_SetTextureUnmanaged(RTU_PRIMARY, GL_PrepareLSTexture(wsParms.texture), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); - if(parms.wall.left.divCount || parms.wall.right.divCount) + if(mustSubdivide) { /* * Need to swap indices around into fans set the position @@ -1040,22 +1042,26 @@ static void drawWallSectionShadow(rvertex_t const *origVertices, float const bR = origVertices[2].pos[VZ]; float const tR = origVertices[3].pos[VZ]; - R_DivVerts(rvertices, origVertices, parms.wall.left.firstDiv, parms.wall.left.divCount, parms.wall.right.firstDiv, parms.wall.right.divCount); - R_DivTexCoords(rtexcoords, origTexCoords, parms.wall.left.firstDiv, parms.wall.left.divCount, parms.wall.right.firstDiv, parms.wall.right.divCount, bL, tL, bR, tR); - R_DivVertColors(rcolors, origColors, parms.wall.left.firstDiv, parms.wall.left.divCount, parms.wall.right.firstDiv, parms.wall.right.divCount, bL, tL, bR, tR); + R_DivVerts(rvertices, origVertices, leftEdge, rightEdge); + R_DivTexCoords(rtexcoords, origTexCoords, leftEdge, rightEdge, bL, tL, bR, tR); + R_DivVertColors(rcolors, origColors, leftEdge, rightEdge, bL, tL, bR, tR); RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, - 3 + parms.wall.right.divCount, rvertices + 3 + parms.wall.left.divCount, rcolors + 3 + parms.wall.left.divCount, - rtexcoords + 3 + parms.wall.left.divCount, NULL); + 3 + rightInterceptCount, + rvertices + 3 + leftInterceptCount, + rcolors + 3 + leftInterceptCount, + rtexcoords + 3 + leftInterceptCount, + 0); RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, - 3 + parms.wall.left.divCount, rvertices, rcolors, rtexcoords, NULL); + 3 + leftInterceptCount, + rvertices, rcolors, rtexcoords, 0); R_FreeRendVertices(rvertices); } else { RL_AddPolyWithCoords(PT_TRIANGLE_STRIP, RPF_DEFAULT|RPF_SHADOW, - 4, origVertices, rcolors, rtexcoords, NULL); + 4, origVertices, rcolors, rtexcoords, 0); } } diff --git a/doomsday/client/src/render/rend_main.cpp b/doomsday/client/src/render/rend_main.cpp index 0cb7dd59ea..a23714bf0e 100644 --- a/doomsday/client/src/render/rend_main.cpp +++ b/doomsday/client/src/render/rend_main.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include #include "de_base.h" @@ -701,16 +703,10 @@ struct rendworldpoly_params_t // Wall only: struct { - coord_t segLength; + coord_t sectionWidth; Vector3f const *surfaceColor2; // Secondary color. - struct { - WallDivs::Intercept *firstDiv; - uint divCount; - } left; - struct { - WallDivs::Intercept *firstDiv; - uint divCount; - } right; + SectionEdge const *leftEdge; + SectionEdge const *rightEdge; } wall; }; @@ -719,7 +715,8 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, { DENG_ASSERT(rvertices != 0); - uint const realNumVertices = ((p.isWall && (p.wall.left.divCount || p.wall.right.divCount))? 3 + p.wall.left.divCount + 3 + p.wall.right.divCount : numVertices); + uint const realNumVertices = (p.isWall? 3 + p.wall.leftEdge->divisionCount() + 3 + p.wall.rightEdge->divisionCount() : numVertices); + bool const mustSubdivide = (p.isWall && (p.wall.leftEdge->divisionCount() || p.wall.rightEdge->divisionCount())); bool const skyMaskedMaterial = ((p.flags & RPF_SKYMASK) || (ms.material().isSkyMasked())); bool const drawAsVisSprite = (!p.forceOpaque && !(p.flags & RPF_SKYMASK) && (!ms.isOpaque() || p.alpha < 1 || p.blendMode > 0)); @@ -790,15 +787,15 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, if(p.isWall) { // Primary texture coordinates. - quadTexCoords(primaryCoords, rvertices, p.wall.segLength, *p.texTL); + quadTexCoords(primaryCoords, rvertices, p.wall.sectionWidth, *p.texTL); // Blend texture coordinates. if(interRTU && !drawAsVisSprite) - quadTexCoords(interCoords, rvertices, p.wall.segLength, *p.texTL); + quadTexCoords(interCoords, rvertices, p.wall.sectionWidth, *p.texTL); // Shiny texture coordinates. if(shinyRTU && !drawAsVisSprite) - quadShinyTexCoords(shinyTexCoords, &rvertices[1], &rvertices[2], p.wall.segLength); + quadShinyTexCoords(shinyTexCoords, &rvertices[1], &rvertices[2], p.wall.sectionWidth); // First light texture coordinates. if(modTex && RL_IsMTexLights()) @@ -989,7 +986,7 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, * This is needed because all masked polys must be sorted (sprites * are masked polys). Otherwise there will be artifacts. */ - Rend_AddMaskedPoly(rvertices, rcolors, p.wall.segLength, &ms.materialVariant(), + Rend_AddMaskedPoly(rvertices, rcolors, p.wall.sectionWidth, &ms.materialVariant(), *p.materialOrigin, p.blendMode, p.lightListIdx, p.glowing); R_FreeRendTexCoords(primaryCoords); @@ -1007,6 +1004,7 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, // Render all lights projected onto this surface. renderlightprojectionparams_t parm; + zap(parm); parm.rvertices = rvertices; parm.numVertices = numVertices; parm.realNumVertices = realNumVertices; @@ -1016,10 +1014,8 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, parm.isWall = p.isWall; if(p.isWall) { - parm.wall.left.firstDiv = p.wall.left.firstDiv; - parm.wall.left.divCount = p.wall.left.divCount; - parm.wall.right.firstDiv = p.wall.right.firstDiv; - parm.wall.right.divCount = p.wall.right.divCount; + parm.wall.leftEdge = p.wall.leftEdge; + parm.wall.rightEdge = p.wall.rightEdge; } hasDynlights = (0 != Rend_RenderLightProjections(p.lightListIdx, parm)); @@ -1030,6 +1026,7 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, // Render all shadows projected onto this surface. rendershadowprojectionparams_t parm; + zap(parm); parm.rvertices = rvertices; parm.numVertices = numVertices; parm.realNumVertices = realNumVertices; @@ -1038,10 +1035,8 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, parm.isWall = p.isWall; if(p.isWall) { - parm.wall.left.firstDiv = p.wall.left.firstDiv; - parm.wall.left.divCount = p.wall.left.divCount; - parm.wall.right.firstDiv = p.wall.right.firstDiv; - parm.wall.right.divCount = p.wall.right.divCount; + parm.wall.leftEdge = p.wall.leftEdge; + parm.wall.rightEdge = p.wall.rightEdge; } Rend_RenderShadowProjections(p.shadowListIdx, parm); @@ -1085,8 +1080,13 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, } // Write multiple polys depending on rend params. - if(p.isWall && (p.wall.left.divCount || p.wall.right.divCount)) + if(mustSubdivide) { + SectionEdge const &leftEdge = *p.wall.leftEdge; + SectionEdge const &rightEdge = *p.wall.rightEdge; + int const leftInterceptCount = leftEdge.divisionCount(); + int const rightInterceptCount = rightEdge.divisionCount(); + /* * Need to swap indices around into fans set the position * of the division vertices, interpolate texcoords and @@ -1110,62 +1110,74 @@ static bool renderWorldPoly(rvertex_t *rvertices, uint numVertices, float const bR = origVerts[2].pos[VZ]; float const tR = origVerts[3].pos[VZ]; - R_DivVerts(rvertices, origVerts, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount); - R_DivTexCoords(primaryCoords, origTexCoords, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivVerts(rvertices, origVerts, leftEdge, rightEdge); + R_DivTexCoords(primaryCoords, origTexCoords, leftEdge, rightEdge, + bL, tL, bR, tR); if(rcolors) { - R_DivVertColors(rcolors, origColors, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivVertColors(rcolors, origColors, leftEdge, rightEdge, + bL, tL, bR, tR); } if(interCoords) { rtexcoord_t origTexCoords2[4]; std::memcpy(origTexCoords2, interCoords, sizeof(origTexCoords2)); - R_DivTexCoords(interCoords, origTexCoords2, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivTexCoords(interCoords, origTexCoords2, leftEdge, rightEdge, + bL, tL, bR, tR); } if(modCoords) { rtexcoord_t origTexCoords5[4]; std::memcpy(origTexCoords5, modCoords, sizeof(origTexCoords5)); - R_DivTexCoords(modCoords, origTexCoords5, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivTexCoords(modCoords, origTexCoords5, leftEdge, rightEdge, + bL, tL, bR, tR); } if(shinyTexCoords) { rtexcoord_t origShinyTexCoords[4]; std::memcpy(origShinyTexCoords, shinyTexCoords, sizeof(origShinyTexCoords)); - R_DivTexCoords(shinyTexCoords, origShinyTexCoords, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivTexCoords(shinyTexCoords, origShinyTexCoords, leftEdge, rightEdge, + bL, tL, bR, tR); } if(shinyColors) { ColorRawf origShinyColors[4]; std::memcpy(origShinyColors, shinyColors, sizeof(origShinyColors)); - R_DivVertColors(shinyColors, origShinyColors, p.wall.left.firstDiv, p.wall.left.divCount, p.wall.right.firstDiv, p.wall.right.divCount, bL, tL, bR, tR); + R_DivVertColors(shinyColors, origShinyColors, leftEdge, rightEdge, + bL, tL, bR, tR); } RL_AddPolyWithCoordsModulationReflection(PT_FAN, p.flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), - 3 + p.wall.right.divCount, rvertices + 3 + p.wall.left.divCount, rcolors? rcolors + 3 + p.wall.left.divCount : NULL, - primaryCoords + 3 + p.wall.left.divCount, interCoords? interCoords + 3 + p.wall.left.divCount : NULL, - modTex, &modColor, modCoords? modCoords + 3 + p.wall.left.divCount : NULL, - shinyColors + 3 + p.wall.left.divCount, shinyTexCoords? shinyTexCoords + 3 + p.wall.left.divCount : NULL, - shinyMaskRTU? primaryCoords + 3 + p.wall.left.divCount : NULL); + 3 + rightInterceptCount, + rvertices + 3 + leftInterceptCount, + rcolors? rcolors + 3 + leftInterceptCount : 0, + primaryCoords + 3 + leftInterceptCount, + interCoords? interCoords + 3 + leftInterceptCount : 0, + modTex, &modColor, modCoords? modCoords + 3 + leftInterceptCount : 0, + shinyColors + 3 + leftInterceptCount, + shinyTexCoords? shinyTexCoords + 3 + leftInterceptCount : 0, + shinyMaskRTU? primaryCoords + 3 + leftInterceptCount : 0); RL_AddPolyWithCoordsModulationReflection(PT_FAN, p.flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), - 3 + p.wall.left.divCount, rvertices, rcolors, - primaryCoords, interCoords, - modTex, &modColor, modCoords, - shinyColors, shinyTexCoords, shinyMaskRTU? primaryCoords : NULL); + 3 + leftInterceptCount, + rvertices, rcolors, primaryCoords, interCoords, + modTex, &modColor, modCoords, + shinyColors, shinyTexCoords, + shinyMaskRTU? primaryCoords : 0); } else { - RL_AddPolyWithCoordsModulationReflection(p.isWall? PT_TRIANGLE_STRIP : PT_FAN, p.flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), - numVertices, rvertices, rcolors, - primaryCoords, interCoords, - modTex, &modColor, modCoords, - shinyColors, shinyTexCoords, shinyMaskRTU? primaryCoords : NULL); + RL_AddPolyWithCoordsModulationReflection(p.isWall? PT_TRIANGLE_STRIP : PT_FAN, + p.flags | (hasDynlights? RPF_HAS_DYNLIGHTS : 0), + numVertices, rvertices, rcolors, + primaryCoords, interCoords, + modTex, &modColor, modCoords, + shinyColors, shinyTexCoords, shinyMaskRTU? primaryCoords : 0); } R_FreeRendTexCoords(primaryCoords); @@ -1538,6 +1550,7 @@ static uint projectSurfaceShadows(Surface &surface, float glowStrength, 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(); } @@ -1552,37 +1565,37 @@ static inline float wallSectionOpacity(Line::Side &side, int section) #define WSF_ADD_RADIO 0x04 ///< Write geometry for faked radiosity. #define WSF_VIEWER_NEAR_BLEND 0x08 ///< Alpha-blend geometry when viewer is near. #define WSF_FORCE_OPAQUE 0x10 ///< Force the geometry to be opaque. + +#define DEFAULT_WRITE_WALL_SECTION_FLAGS (WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO) ///@} /** * @param flags @ref writeWallSectionFlags */ -static bool writeWallSection(HEdge &hedge, int section, - int flags, WallDivs *leftWallDivs, WallDivs *rightWallDivs, - Vector2f const &materialOrigin) +static bool writeWallSection(SectionEdge const &leftEdge, SectionEdge const &rightEdge, + Vector2f const &materialOrigin, MapElement &mapElement, biassurface_t &biasSurface, + int flags = DEFAULT_WRITE_WALL_SECTION_FLAGS) { - BspLeaf *leaf = currentBspLeaf; - DENG_ASSERT(!isNullLeaf(leaf)); + BspLeaf *bspLeaf = currentBspLeaf; + DENG_ASSERT(!isNullLeaf(bspLeaf)); - Surface &surface = hedge.lineSide().surface(section); + Line::Side &side = leftEdge.hedge().lineSide(); + int const section = leftEdge.section(); + Surface &surface = side.surface(section); // Surfaces without a drawable material are never rendered. if(!(surface.hasMaterial() && surface.material().isDrawable())) return false; - if(leftWallDivs->first().distance() >= - rightWallDivs->last().distance()) return true; + if(leftEdge.bottom().distance() >= rightEdge.top().distance()) + return true; - float opacity = wallSectionOpacity(hedge.lineSide(), section); + coord_t width = de::abs(Vector2d(rightEdge.origin() - leftEdge.origin()).length()); + float opacity = wallSectionOpacity(side, section); bool didNearBlend = false; if(flags & WSF_VIEWER_NEAR_BLEND) { - DENG_ASSERT(section == Line::Side::Middle); - - mobj_t *mo = viewPlayer->shared.mo; - viewdata_t const *viewData = R_ViewData(viewPlayer - ddPlayers); - /* * Can the player walk through this surface? * If the player is close enough we should NOT add a solid hedge @@ -1590,10 +1603,15 @@ static bool writeWallSection(HEdge &hedge, int section, * (e.g., passing through an opaque waterfall). */ - if(viewData->current.origin[VZ] > leftWallDivs->first().distance() && - viewData->current.origin[VZ] < rightWallDivs->last().distance()) + DENG_ASSERT(section == Line::Side::Middle); + + mobj_t *mo = viewPlayer->shared.mo; + viewdata_t const *viewData = R_ViewData(viewPlayer - ddPlayers); + + if(viewData->current.origin[VZ] > leftEdge.bottom().distance() && + viewData->current.origin[VZ] < rightEdge.top().distance()) { - Line const &line = hedge.line(); + 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 }; @@ -1622,14 +1640,13 @@ static bool writeWallSection(HEdge &hedge, int section, if(opacity <= 0) return false; - bool const isTwoSided = (hedge.hasLineSide() && hedge.line().hasFrontSections() && hedge.line().hasBackSections())? true:false; + bool const isTwoSided = (side.hasSections() && side.back().hasSections()); Vector2f materialScale((surface.flags() & DDSUF_MATERIAL_FLIPH)? -1 : 1, (surface.flags() & DDSUF_MATERIAL_FLIPV)? -1 : 1); - Vector3d texTL(hedge.fromOrigin(), leftWallDivs->last().distance()); - - Vector3d texBR(hedge.toOrigin(), rightWallDivs->first().distance()); + Vector3d texTL(leftEdge.origin(), leftEdge.top().distance()); + Vector3d texBR(rightEdge.origin(), rightEdge.bottom().distance()); // Determine which Material to use. Material *material = 0; @@ -1637,7 +1654,7 @@ static bool writeWallSection(HEdge &hedge, int section, /// @todo Geometry tests here should use the same sectors as used when /// deciding the z-heights for the wall divs. At least in the case of /// selfreferencing lines, this logic is probably incorrect. -ds - if(devRendSkyMode && hedge.hasTwin() && + /*if(devRendSkyMode && hedge.hasTwin() && ((section == Line::Side::Bottom && hedge.bspLeafSector().floorSurface().hasSkyMaskedMaterial() && hedge.twin().bspLeafSector().floorSurface().hasSkyMaskedMaterial()) || (section == Line::Side::Top && hedge.bspLeafSector().ceilingSurface().hasSkyMaskedMaterial() && @@ -1646,7 +1663,7 @@ static bool writeWallSection(HEdge &hedge, int section, // Geometry not normally rendered however we do so in dev sky mode. material = currentBspLeaf->sector().planeSurface(section == Line::Side::Top? Plane::Ceiling : Plane::Floor).materialPtr(); } - else + else*/ { material = chooseSurfaceMaterialForTexturingMode(surface); @@ -1690,7 +1707,7 @@ static bool writeWallSection(HEdge &hedge, int section, } // Polyobj surfaces never shadow. - if(hedge.line().isFromPolyobj()) + if(side.line().isFromPolyobj()) flags &= ~WSF_ADD_RADIO; float glowStrength = 0; @@ -1700,59 +1717,59 @@ static bool writeWallSection(HEdge &hedge, int section, // Dynamic Lights? if(flags & WSF_ADD_DYNLIGHTS) { - lightListIdx = projectSurfaceLights(hedge.lineSide().middle(), glowStrength, texTL, texBR, + lightListIdx = projectSurfaceLights(side.middle(), glowStrength, texTL, texBR, (section == Line::Side::Middle && isTwoSided)); } // Dynamic shadows? if(flags & WSF_ADD_DYNSHADOWS) { - shadowListIdx = projectSurfaceShadows(hedge.lineSide().middle(), glowStrength, texTL, texBR); + shadowListIdx = projectSurfaceShadows(side.middle(), glowStrength, texTL, texBR); } if(glowStrength > 0) flags &= ~WSF_ADD_RADIO; - hedge.lineSide().chooseSurfaceTintColors(section, &topColor, &bottomColor); + side.chooseSurfaceTintColors(section, &topColor, &bottomColor); } // Calculate the light level deltas for this wall section. /// @todo Cache these values somewhere. -ds float deltaL, deltaR; - wallSectionLightLevelDeltas(hedge.lineSide(), section, 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 = hedge.line().length(); - coord_t const sectionLength = hedge.length(); - coord_t const sectionOffset = hedge.lineOffset(); + coord_t const lineLength = side.line().length(); + coord_t const sectionOffset = leftEdge.offset(); float deltaDiff = deltaR - deltaL; - deltaR = deltaL + ((sectionOffset + sectionLength) / lineLength) * deltaDiff; + deltaR = deltaL + ((sectionOffset + width) / lineLength) * deltaDiff; deltaL += (sectionOffset / lineLength) * deltaDiff; } if(section == Line::Side::Middle && isTwoSided) { // Temporarily modify the draw state. - currentSectorLightColor = R_GetSectorLightColor(hedge.lineSide().sector()); - currentSectorLightLevel = hedge.lineSide().sector().lightLevel(); + currentSectorLightColor = R_GetSectorLightColor(side.sector()); + currentSectorLightLevel = side.sector().lightLevel(); } - bool const skyMask = (rpFlags & RPF_SKYMASK) != 0; - bool const addFakeRadio = (flags & WSF_ADD_RADIO) != 0; + bool const skyMask = (rpFlags & RPF_SKYMASK) != 0; + bool const addFakeRadio = (flags & WSF_ADD_RADIO) != 0; + bool const mustSubdivide = (leftEdge.divisionCount() || rightEdge.divisionCount()); rendworldpoly_params_t parm; - std::memset(&parm, 0, sizeof(parm)); + zap(parm); parm.flags = RPF_DEFAULT | (skyMask? RPF_SKYMASK : 0); parm.forceOpaque = (flags & WSF_FORCE_OPAQUE)? true : false; parm.alpha = (flags & WSF_FORCE_OPAQUE)? 1 : opacity; - parm.mapElement = &hedge; + parm.mapElement = &mapElement; parm.elmIdx = section; - parm.bsuf = &hedge.biasSurfaceForGeometryGroup(section); + parm.bsuf = &biasSurface; parm.normal = &surface.normal(); parm.texTL = &texTL; parm.texBR = &texBR; @@ -1768,18 +1785,17 @@ static bool writeWallSection(HEdge &hedge, int section, parm.isWall = true; parm.wall.surfaceColor2 = bottomColor; - parm.wall.segLength = hedge.length(); - parm.wall.left.firstDiv = &leftWallDivs->first().next(); // Step over first node. - parm.wall.left.divCount = leftWallDivs->count()-2; - parm.wall.right.firstDiv = &rightWallDivs->last().prev(); // Step over last node. - parm.wall.right.divCount = rightWallDivs->count()-2; + parm.wall.sectionWidth = width; + parm.wall.leftEdge = &leftEdge; + parm.wall.rightEdge = &rightEdge; rvertex_t *rvertices; // Allocate enough vertices for the divisions too. - if(leftWallDivs->count() > 2 || rightWallDivs->count() > 2) + if(mustSubdivide) { // Use two fans. - rvertices = R_AllocRendVertices(1 + leftWallDivs->count() + 1 + rightWallDivs->count()); + rvertices = R_AllocRendVertices(3 + leftEdge.divisionCount() + + 3 + rightEdge.divisionCount()); } else { @@ -1789,21 +1805,21 @@ static bool writeWallSection(HEdge &hedge, int section, // Vertex coords. // Bottom Left. - V3f_Set(rvertices[0].pos, hedge.fromOrigin().x, - hedge.fromOrigin().y, - leftWallDivs->first().distance()); + V3f_Set(rvertices[0].pos, leftEdge.origin().x, + leftEdge.origin().y, + leftEdge.bottom().distance()); // Top Left. - V3f_Set(rvertices[1].pos, hedge.fromOrigin().x, - hedge.fromOrigin().y, - leftWallDivs->last().distance()); + V3f_Set(rvertices[1].pos, leftEdge.origin().x, + leftEdge.origin().y, + leftEdge.top().distance()); // Bottom Right. - V3f_Set(rvertices[2].pos, hedge.toOrigin().x, - hedge.toOrigin().y, - rightWallDivs->first().distance()); + V3f_Set(rvertices[2].pos, rightEdge.origin().x, + rightEdge.origin().y, + rightEdge.bottom().distance()); // Top Right. - V3f_Set(rvertices[3].pos, hedge.toOrigin().x, - hedge.toOrigin().y, - rightWallDivs->last().distance()); + V3f_Set(rvertices[3].pos, rightEdge.origin().x, + rightEdge.origin().y, + rightEdge.top().distance()); // Draw this section. bool opaque = renderWorldPoly(rvertices, 4, parm, ms); @@ -1812,52 +1828,54 @@ static bool writeWallSection(HEdge &hedge, int section, // Render FakeRadio for this section? if(!(parm.flags & RPF_SKYMASK) && addFakeRadio) { + Rend_RadioUpdateForLineSide(side); + LineSideRadioData &frData = Rend_RadioDataForLineSide(side); + RendRadioWallSectionParms radioParms; std::memset(&radioParms, 0, sizeof(radioParms)); - radioParms.line = &hedge.line(); - - LineSideRadioData &frData = Rend_RadioDataForLineSide(hedge.lineSide()); + radioParms.line = &side.line(); radioParms.botCn = frData.bottomCorners; radioParms.topCn = frData.topCorners; radioParms.sideCn = frData.sideCorners; radioParms.spans = frData.spans; - radioParms.segOffset = hedge.lineOffset(); - radioParms.segLength = hedge.length(); - radioParms.frontSec = hedge.bspLeafSectorPtr(); + radioParms.segOffset = leftEdge.offset(); + radioParms.segLength = width; + radioParms.frontSec = bspLeaf->sectorPtr(); - radioParms.wall.left.firstDiv = parm.wall.left.firstDiv; - radioParms.wall.left.divCount = parm.wall.left.divCount; - radioParms.wall.right.firstDiv = parm.wall.right.firstDiv; - radioParms.wall.right.divCount = parm.wall.right.divCount; + radioParms.leftEdge = parm.wall.leftEdge; + radioParms.rightEdge = parm.wall.rightEdge; - if(!(section == Line::Side::Middle && isTwoSided) && - !(hedge.hasTwin() && !(hedge.twin().hasLineSide() && hedge.twin().lineSide().hasSections()))) + if(!(section == Line::Side::Middle && isTwoSided)) { - if(hedge.hasTwin()) - radioParms.backSec = hedge.twin().bspLeafSectorPtr(); + HEdge &hedge = *mapElement.castTo(); + if(!(hedge.hasTwin() && !(hedge.twin().hasLineSide() && hedge.twin().lineSide().hasSections()))) + { + if(hedge.hasTwin()) + radioParms.backSec = hedge.twin().bspLeafSectorPtr(); + } } /// @todo kludge: Revert the vertex coords as they may have been changed /// due to height divisions. // Bottom Left. - V3f_Set(rvertices[0].pos, hedge.fromOrigin().x, - hedge.fromOrigin().y, - leftWallDivs->first().distance()); + V3f_Set(rvertices[0].pos, leftEdge.origin().x, + leftEdge.origin().y, + leftEdge.bottom().distance()); // Top Left. - V3f_Set(rvertices[1].pos, hedge.fromOrigin().x, - hedge.fromOrigin().y, - leftWallDivs->last().distance()); + V3f_Set(rvertices[1].pos, leftEdge.origin().x, + leftEdge.origin().y, + leftEdge.top().distance()); // Bottom Right. - V3f_Set(rvertices[2].pos, hedge.toOrigin().x, - hedge.toOrigin().y, - rightWallDivs->first().distance()); + V3f_Set(rvertices[2].pos, rightEdge.origin().x, + rightEdge.origin().y, + rightEdge.bottom().distance()); // Top Right. - V3f_Set(rvertices[3].pos, hedge.toOrigin().x, - hedge.toOrigin().y, - rightWallDivs->last().distance()); + V3f_Set(rvertices[3].pos, rightEdge.origin().x, + rightEdge.origin().y, + rightEdge.top().distance()); // kludge end. @@ -1895,207 +1913,63 @@ static bool writeWallSection(HEdge &hedge, int section, return opaque && !didNearBlend; } -static void addWallDivNodesForPlaneIntercepts(HEdge const &hedge, WallDivs *wallDivs, - int section, coord_t bottomZ, coord_t topZ, bool doRight) -{ - bool const clockwise = !doRight; - - if(!hedge.hasLineSide()) return; - - Line::Side const &side = hedge.lineSide(); - if(side.line().isFromPolyobj()) return; - - // Check for neighborhood division? - if(section == Line::Side::Middle && side.hasSections() && side.back().hasSections()) - return; - - // Only sections at line side edges can/should be split. - if(!((&hedge == side.leftHEdge() && !doRight) || - (&hedge == side.rightHEdge() && doRight))) - return; - - if(bottomZ >= topZ) return; // Obviously no division. - - Sector const *frontSec = side.sectorPtr(); - - // Retrieve the start owner node. - LineOwner *base = R_GetVtxLineOwner(&side.line().vertex(doRight), &side.line()); - LineOwner *own = base; - bool stopScan = false; - do - { - own = own->_link[clockwise]; - - if(own == base) - { - stopScan = true; - } - else - { - Line *iter = &own->line(); - - if(iter->isSelfReferencing()) - continue; - - uint i = 0; - do - { - // First front, then back. - Sector *scanSec = NULL; - if(!i && iter->hasFrontSections() && iter->frontSectorPtr() != frontSec) - scanSec = iter->frontSectorPtr(); - else if(i && iter->hasBackSections() && iter->backSectorPtr() != frontSec) - scanSec = iter->backSectorPtr(); - - if(scanSec) - { - if(scanSec->ceiling().visHeight() - scanSec->floor().visHeight() > 0) - { - for(int j = 0; j < scanSec->planeCount() && !stopScan; ++j) - { - Plane const &plane = scanSec->plane(j); - - if(plane.visHeight() > bottomZ && plane.visHeight() < topZ) - { - if(!wallDivs->find(plane.visHeight())) - { - wallDivs->append(plane.visHeight()); - - // Have we reached the div limit? - if(wallDivs->count() == WALLDIVS_MAX_INTERCEPTS) - stopScan = true; - } - } - - if(!stopScan) - { - // Clip a range bound to this height? - if(plane.type() == Plane::Floor && plane.visHeight() > bottomZ) - bottomZ = plane.visHeight(); - else if(plane.type() == Plane::Ceiling && plane.visHeight() < topZ) - topZ = plane.visHeight(); - - // All clipped away? - if(bottomZ >= topZ) - stopScan = true; - } - } - } - else - { - /** - * A zero height sector is a special case. In this - * instance, the potential division is at the height - * of the back ceiling. This is because elsewhere - * we automatically fix the case of a floor above a - * ceiling by lowering the floor. - */ - coord_t z = scanSec->ceiling().visHeight(); - - if(z > bottomZ && z < topZ) - { - if(!wallDivs->find(z)) - { - wallDivs->append(z); - - // All clipped away. - stopScan = true; - } - } - } - } - } while(!stopScan && ++i < 2); - - // Stop the scan when a single sided line is reached. - if(!iter->hasFrontSections() || !iter->hasBackSections()) - stopScan = true; - } - } while(!stopScan); -} - /** - * Ensure the divisions do not exceed the specified range. + * Determines the side relative sectors for producing wall section geometry. + * + * @pre @a hedge has an attributed map line side. + * + * @param hedge Half-edge describing the map line segment. + * + * Return values: + * @param frontSec Front sector for the wall section is written here. Can be @c 0. + * @param backSec Back sector for the wall section is written here. Can be @c 0. */ -static void assertWallDivsInRange(WallDivs *wd, coord_t low, coord_t hi) +static void wallSectionSectors(HEdge &hedge, Sector **frontSec, Sector **backSec) { -#ifdef DENG_DEBUG - if(wd->isEmpty()) return; + DENG_ASSERT(hedge.hasLineSide()); - WallDivs::Intercept *node = &wd->first(); - forever + if(!hedge.line().isSelfReferencing()) { - DENG2_ASSERT(node->distance() >= low && node->distance() <= hi); + if(frontSec) *frontSec = hedge.bspLeafSectorPtr(); + if(backSec) *backSec = hedge.hasTwin()? hedge.twin().bspLeafSectorPtr() : 0; - if(!node->hasNext()) break; - node = &node->next(); + return; } -#else - DENG2_UNUSED3(wd, low, hi); -#endif -} - -static void buildWallDiv(WallDivs *wallDivs, HEdge const &hedge, - int section, coord_t bottomZ, coord_t topZ, boolean doRight) -{ - DENG_ASSERT(wallDivs->isEmpty()); - - // Nodes are arranged according to their Z axis height in ascending order. - // The first node is the bottom. - wallDivs->append(bottomZ); - - // Add nodes for intercepts. - addWallDivNodesForPlaneIntercepts(hedge, wallDivs, section, bottomZ, topZ, doRight); - // The last node is the top. - wallDivs->append(topZ); - - if(!(wallDivs->count() > 2)) return; - - wallDivs->sort(); - assertWallDivsInRange(wallDivs, bottomZ, topZ); + // Special case: so called "self-referencing" lines use the sector's of the map line. + if(frontSec) *frontSec = hedge.lineSide().sectorPtr(); + if(backSec) *backSec = hedge.lineSide().sectorPtr(); } /** - * Prepare wall division data for a section of the HEdge. + * Prepare wall section edge data for a map line segment. * - * @param section Line::Side section to prepare divisions for. - * @param leftWallDivs Division data for the left edge is written here. - * @param rightWallDivs Division data for the right edge is written here. - * @param materialOrigin Material origin offset data is written here. Can be @c 0. + * Return values: + * @param leftEdge Edge data the left of the wall section is written here. + * @param rightEdge Edge data the right of the wall section is written here. + * @param materialOrigin Material origin offset data is written here. * - * @return @c true if divisions were prepared (the specified @a section has a - * non-zero Z axis height). + * @return @c true iff the resultant edges describe a polygon with a positive area. */ -static bool prepareWallDivs(HEdge &hedge, int section, WallDivs *leftWallDivs, - WallDivs *rightWallDivs, Vector2f *materialOrigin) +static bool prepareWallSectionEdges(SectionEdge &leftEdge, SectionEdge &rightEdge, + Vector2f &materialOrigin) { - DENG_ASSERT(hedge.hasLineSide()); - - Sector const *frontSec, *backSec; + HEdge &hedge = leftEdge.hedge(); + int const section = leftEdge.section(); - if(!hedge.line().isSelfReferencing()) - { - frontSec = hedge.bspLeafSectorPtr(); - backSec = hedge.hasTwin()? hedge.twin().bspLeafSectorPtr() : 0; - } - else - { - frontSec = backSec = hedge.lineSide().sectorPtr(); - } + Sector *frontSec, *backSec; + wallSectionSectors(hedge, &frontSec, &backSec); coord_t bottom, top; bool visible = R_SideSectionCoords(hedge.lineSide(), section, frontSec, backSec, - &bottom, &top, materialOrigin); - - if(materialOrigin) - { - materialOrigin->x += float(hedge.lineOffset()); - } + &bottom, &top, &materialOrigin); if(!visible) return false; - buildWallDiv(leftWallDivs, hedge, section, bottom, top, false /* left-edge */); - buildWallDiv(rightWallDivs, hedge, section, bottom, top, true /* right-edge */); + leftEdge.prepare(bottom, top); + rightEdge.prepare(bottom, top); + + materialOrigin.x += float(leftEdge.offset()); return true; } @@ -2103,6 +1977,10 @@ static bool prepareWallDivs(HEdge &hedge, int section, WallDivs *leftWallDivs, /** * Prepare and write wall sections for a "one-sided" line to the render lists. * + * @pre currentBspLeaf is set to the BSP leaf which "contains" the half-edge. + * @pre @a hedge has an attributed map line side with sections. + * @pre @a hedge is front facing. + * * @param hedge HEdge to draw wall sections for. * @param sections @ref sideSectionFlags */ @@ -2118,42 +1996,45 @@ static bool writeWallSections2(HEdge &hedge, int sections) // Only a "middle" section. if(!(sections & Line::Side::MiddleFlag)) return false; - WallDivs leftWallDivs, rightWallDivs; + int const section = Line::Side::Middle; + SectionEdge leftEdge(hedge, section, false /* left edge */); + SectionEdge rightEdge(hedge, section, true /* right edge */); Vector2f materialOrigin; bool opaque = false; - if(prepareWallDivs(hedge, Line::Side::Middle, &leftWallDivs, &rightWallDivs, - &materialOrigin)) + if(prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin)) { - Rend_RadioUpdateForLineSide(hedge.lineSide()); - - int wsFlags = WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO; - - opaque = writeWallSection(hedge, Line::Side::Middle, wsFlags, - &leftWallDivs, &rightWallDivs, materialOrigin); + opaque = writeWallSection(leftEdge, rightEdge, materialOrigin, + hedge, hedge.biasSurfaceForGeometryGroup(section)); } reportWallSectionDrawn(hedge.line()); return opaque; } -static bool prepareWallDivsPolyobj(Line::Side const &side, int section, - WallDivs *leftWallDivs, WallDivs *rightWallDivs, Vector2f *materialOrigin = 0) +static void prepareSectionEdgePolyobj(SectionEdge &edge, HEdge &hedge, int section, + coord_t bottom, coord_t top, int right) +{ + DENG2_UNUSED3(hedge, section, right); + edge.wallDivs.intercept(bottom); // First node. + edge.wallDivs.intercept(top); // Last node. + edge.configure(); +} + +static bool prepareSectionEdgesPolyobj(HEdge &hedge, int section, + SectionEdge &leftEdge, SectionEdge &rightEdge, Vector2f &materialOrigin) { BspLeaf *leaf = currentBspLeaf; DENG_ASSERT(!isNullLeaf(leaf)); coord_t bottom, top; - bool visible = R_SideSectionCoords(side, section, leaf->sectorPtr(), 0, - &bottom, &top, materialOrigin); + bool visible = R_SideSectionCoords(hedge.lineSide(), section, leaf->sectorPtr(), 0, + &bottom, &top, &materialOrigin); if(!visible) return false; - leftWallDivs->append(bottom); // First node. - leftWallDivs->append(top); // Last node. - - rightWallDivs->append(bottom); // First node. - rightWallDivs->append(top); // Last node. + prepareSectionEdgePolyobj(leftEdge, hedge, section, bottom, top, false /*left edge */); + prepareSectionEdgePolyobj(rightEdge, hedge, section, bottom, top, true /*right edge */); return true; } @@ -2170,19 +2051,16 @@ static bool writeWallSections2Polyobj(HEdge &hedge, int sections) // Only a "middle" section. if(!(sections & Line::Side::MiddleFlag)) return false; - WallDivs leftWallDivs, rightWallDivs; + int const section = Line::Side::Middle; + SectionEdge leftEdge(hedge, section, false /* left edge */); + SectionEdge rightEdge(hedge, section, true /* right edge */); Vector2f materialOrigin; bool opaque = false; - if(prepareWallDivsPolyobj(hedge.lineSide(), Line::Side::Middle, - &leftWallDivs, &rightWallDivs, &materialOrigin)) + if(prepareSectionEdgesPolyobj(hedge, section, leftEdge, rightEdge, materialOrigin)) { - Rend_RadioUpdateForLineSide(hedge.lineSide()); - - int wsFlags = WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO; - - opaque = writeWallSection(hedge, Line::Side::Middle, wsFlags, - &leftWallDivs, &rightWallDivs, materialOrigin); + opaque = writeWallSection(leftEdge, rightEdge, materialOrigin, + hedge, hedge.biasSurfaceForGeometryGroup(section)); } reportWallSectionDrawn(hedge.line()); @@ -2227,22 +2105,22 @@ static bool writeWallSections2Twosided(HEdge &hedge, int sections) // Middle section? if(sections & Line::Side::MiddleFlag) { - WallDivs leftWallDivs, rightWallDivs; + int const section = Line::Side::Middle; + SectionEdge leftEdge(hedge, section, false /* left edge */); + SectionEdge rightEdge(hedge, section, true /* right edge */); Vector2f materialOrigin; - if(prepareWallDivs(hedge, Line::Side::Middle, &leftWallDivs, &rightWallDivs, - &materialOrigin)) + if(prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin)) { - int rhFlags = WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO; + int wsFlags = DEFAULT_WRITE_WALL_SECTION_FLAGS; if((viewPlayer->shared.flags & (DDPF_NOCLIP|DDPF_CAMERA)) || !(line.isFlagged(DDLF_BLOCKING))) - rhFlags |= WSF_VIEWER_NEAR_BLEND; + wsFlags |= WSF_VIEWER_NEAR_BLEND; - Rend_RadioUpdateForLineSide(hedge.lineSide()); - - opaque = writeWallSection(hedge, Line::Side::Middle, rhFlags, - &leftWallDivs, &rightWallDivs, materialOrigin); + opaque = writeWallSection(leftEdge, rightEdge, materialOrigin, + hedge, hedge.biasSurfaceForGeometryGroup(section), + wsFlags); if(opaque) { Surface &surface = front.middle(); @@ -2263,8 +2141,8 @@ static bool writeWallSections2Twosided(HEdge &hedge, int sections) xtop += surface.visMaterialOrigin()[VY]; // Can we make this a solid segment? - if(!(rightWallDivs.last().distance() >= xtop && - leftWallDivs.first().distance() <= xbottom)) + if(!(rightEdge.top().distance() >= xtop && + leftEdge.bottom().distance() <= xbottom)) opaque = false; } } @@ -2273,32 +2151,30 @@ static bool writeWallSections2Twosided(HEdge &hedge, int sections) // Upper section? if(sections & Line::Side::TopFlag) { - WallDivs leftWallDivs, rightWallDivs; + int const section = Line::Side::Top; + SectionEdge leftEdge(hedge, section, false /* left edge */); + SectionEdge rightEdge(hedge, section, true /* right edge */); Vector2f materialOrigin; - if(prepareWallDivs(hedge, Line::Side::Top, &leftWallDivs, &rightWallDivs, - &materialOrigin)) + if(prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin)) { - Rend_RadioUpdateForLineSide(hedge.lineSide()); - - writeWallSection(hedge, Line::Side::Top, WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO, - &leftWallDivs, &rightWallDivs, materialOrigin); + writeWallSection(leftEdge, rightEdge, materialOrigin, + hedge, hedge.biasSurfaceForGeometryGroup(section)); } } // Lower section? if(sections & Line::Side::BottomFlag) { - WallDivs leftWallDivs, rightWallDivs; + int const section = Line::Side::Bottom; + SectionEdge leftEdge(hedge, section, false /* left edge */); + SectionEdge rightEdge(hedge, section, true /* right edge */); Vector2f materialOrigin; - if(prepareWallDivs(hedge, Line::Side::Bottom, &leftWallDivs, &rightWallDivs, - &materialOrigin)) + if(prepareWallSectionEdges(leftEdge, rightEdge, materialOrigin)) { - Rend_RadioUpdateForLineSide(hedge.lineSide()); - - writeWallSection(hedge, Line::Side::Bottom, WSF_ADD_DYNLIGHTS|WSF_ADD_DYNSHADOWS|WSF_ADD_RADIO, - &leftWallDivs, &rightWallDivs, materialOrigin); + writeWallSection(leftEdge, rightEdge, materialOrigin, + hedge, hedge.biasSurfaceForGeometryGroup(section)); } } diff --git a/doomsday/client/src/render/rend_shadow.cpp b/doomsday/client/src/render/rend_shadow.cpp index c485a4429f..c99fa29b74 100644 --- a/doomsday/client/src/render/rend_shadow.cpp +++ b/doomsday/client/src/render/rend_shadow.cpp @@ -203,6 +203,7 @@ static void drawShadow(shadowprojection_t const &sp, rendershadowprojectionparam rvertex_t *rvertices = R_AllocRendVertices(parm.realNumVertices); rtexcoord_t *rtexcoords = R_AllocRendTexCoords(parm.realNumVertices); ColorRawf *rcolors = R_AllocRendColors(parm.realNumVertices); + bool const mustSubdivide = (parm.isWall && (parm.wall.leftEdge->divisionCount() || parm.wall.rightEdge->divisionCount() )); for(uint i = 0; i < parm.numVertices; ++i) { @@ -217,12 +218,15 @@ static void drawShadow(shadowprojection_t const &sp, rendershadowprojectionparam if(parm.isWall) { + SectionEdge const &leftEdge = *parm.wall.leftEdge; + SectionEdge const &rightEdge = *parm.wall.rightEdge; + rtexcoords[1].st[0] = rtexcoords[0].st[0] = sp.s[0]; rtexcoords[1].st[1] = rtexcoords[3].st[1] = sp.t[0]; rtexcoords[3].st[0] = rtexcoords[2].st[0] = sp.s[1]; rtexcoords[2].st[1] = rtexcoords[0].st[1] = sp.t[1]; - if(parm.wall.left.divCount || parm.wall.right.divCount) + if(mustSubdivide) { // We need to subdivide the projection quad. @@ -241,9 +245,9 @@ static void drawShadow(shadowprojection_t const &sp, rendershadowprojectionparam float bR = parm.rvertices[2].pos[VZ]; float tR = parm.rvertices[3].pos[VZ]; - R_DivVerts(rvertices, origVerts, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount); - R_DivTexCoords(rtexcoords, origTexCoords, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount, bL, tL, bR, tR); - R_DivVertColors(rcolors, origColors, parm.wall.left.firstDiv, parm.wall.left.divCount, parm.wall.right.firstDiv, parm.wall.right.divCount, bL, tL, bR, tR); + R_DivVerts(rvertices, origVerts, leftEdge, rightEdge); + R_DivTexCoords(rtexcoords, origTexCoords, leftEdge, rightEdge, bL, tL, bR, tR); + R_DivVertColors(rcolors, origColors, leftEdge, rightEdge, bL, tL, bR, tR); } else { @@ -268,18 +272,27 @@ static void drawShadow(shadowprojection_t const &sp, rendershadowprojectionparam std::memcpy(rvertices, parm.rvertices, sizeof(rvertex_t) * parm.numVertices); } - if(parm.isWall && (parm.wall.left.divCount || parm.wall.right.divCount)) + if(mustSubdivide) { + SectionEdge const &leftEdge = *parm.wall.leftEdge; + SectionEdge const &rightEdge = *parm.wall.rightEdge; + int const leftInterceptCount = leftEdge.divisionCount(); + int const rightInterceptCount = rightEdge.divisionCount(); + RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, - 3 + parm.wall.right.divCount, rvertices + 3 + parm.wall.left.divCount, - rcolors + 3 + parm.wall.left.divCount, rtexcoords + 3 + parm.wall.left.divCount, NULL); + 3 + rightInterceptCount, + rvertices + 3 + leftInterceptCount, + rcolors + 3 + leftInterceptCount, + rtexcoords + 3 + leftInterceptCount, + 0); RL_AddPolyWithCoords(PT_FAN, RPF_DEFAULT|RPF_SHADOW, - 3 + parm.wall.left.divCount, rvertices, rcolors, rtexcoords, NULL); + 3 + leftInterceptCount, + rvertices, rcolors, rtexcoords, 0); } else { RL_AddPolyWithCoords(parm.isWall? PT_TRIANGLE_STRIP : PT_FAN, RPF_DEFAULT|RPF_SHADOW, - parm.numVertices, rvertices, rcolors, rtexcoords, NULL); + parm.numVertices, rvertices, rcolors, rtexcoords, 0); } R_FreeRendVertices(rvertices); diff --git a/doomsday/client/src/render/rendpoly.cpp b/doomsday/client/src/render/rendpoly.cpp index 2b56d61949..b1acc05dbd 100644 --- a/doomsday/client/src/render/rendpoly.cpp +++ b/doomsday/client/src/render/rendpoly.cpp @@ -371,15 +371,15 @@ void Rtu_TranslateOffset(rtexmapunit_t *rtu, Vector2f const &st) rtu->offset[1] += st.y; } -void R_DivVerts(rvertex_t *dst, rvertex_t const *src, WallDivs::Intercept *leftDivFirst, - uint leftDivCount, WallDivs::Intercept *rightDivFirst, uint rightDivCount) +void R_DivVerts(rvertex_t *dst, rvertex_t const *src, + SectionEdge const &leftEdge, SectionEdge const &rightEdge) { #define COPYVERT(d, s) (d)->pos[VX] = (s)->pos[VX]; \ (d)->pos[VY] = (s)->pos[VY]; \ (d)->pos[VZ] = (s)->pos[VZ]; - uint const numR = 3 + (rightDivFirst && rightDivCount? rightDivCount : 0); - uint const numL = 3 + (leftDivFirst && leftDivCount ? leftDivCount : 0); + int const numR = 3 + rightEdge.divisionCount(); + int const numL = 3 + leftEdge.divisionCount(); if(numR + numL == 6) return; // Nothing to do. @@ -388,10 +388,10 @@ void R_DivVerts(rvertex_t *dst, rvertex_t const *src, WallDivs::Intercept *leftD COPYVERT(&dst[numL + 1], &src[3]); COPYVERT(&dst[numL + numR - 1], &src[2]); - if(numR > 3) + if(rightEdge.divisionCount()) { - WallDivs::Intercept *wdn = rightDivFirst; - for(uint n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) + WallDivs::Intercept const *wdn = &rightEdge.lastDivision(); + for(int n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) { dst[numL + 2 + n].pos[VX] = src[2].pos[VX]; dst[numL + 2 + n].pos[VY] = src[2].pos[VY]; @@ -404,10 +404,10 @@ void R_DivVerts(rvertex_t *dst, rvertex_t const *src, WallDivs::Intercept *leftD COPYVERT(&dst[1], &src[0]); COPYVERT(&dst[numL - 1], &src[1]); - if(numL > 3) + if(leftEdge.divisionCount()) { - WallDivs::Intercept *wdn = leftDivFirst; - for(uint n = 0; n < numL - 3; ++n, wdn = &wdn->next()) + WallDivs::Intercept const *wdn = &leftEdge.firstDivision(); + for(int n = 0; n < numL - 3; ++n, wdn = &wdn->next()) { dst[2 + n].pos[VX] = src[0].pos[VX]; dst[2 + n].pos[VY] = src[0].pos[VY]; @@ -418,15 +418,15 @@ void R_DivVerts(rvertex_t *dst, rvertex_t const *src, WallDivs::Intercept *leftD #undef COPYVERT } -void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, WallDivs::Intercept *leftDivFirst, - uint leftDivCount, WallDivs::Intercept *rightDivFirst, uint rightDivCount, +void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, + SectionEdge const &leftEdge, SectionEdge const &rightEdge, float bL, float tL, float bR, float tR) { #define COPYTEXCOORD(d, s) (d)->st[0] = (s)->st[0]; \ (d)->st[1] = (s)->st[1]; - uint const numR = 3 + (rightDivFirst && rightDivCount? rightDivCount : 0); - uint const numL = 3 + (leftDivFirst && leftDivCount ? leftDivCount : 0); + int const numR = 3 + rightEdge.divisionCount(); + int const numL = 3 + leftEdge.divisionCount(); if(numR + numL == 6) return; // Nothing to do. @@ -435,12 +435,12 @@ void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, WallDivs::Intercep COPYTEXCOORD(&dst[numL + 1], &src[3]); COPYTEXCOORD(&dst[numL + numR-1], &src[2]); - if(numR > 3) + if(rightEdge.divisionCount()) { - WallDivs::Intercept *wdn = rightDivFirst; + WallDivs::Intercept const *wdn = &rightEdge.lastDivision(); float const height = tR - bR; float inter; - for(uint n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) + for(int n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) { inter = (float( wdn->distance() ) - bR) / height; dst[numL + 2 + n].st[0] = src[3].st[0]; @@ -453,12 +453,12 @@ void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, WallDivs::Intercep COPYTEXCOORD(&dst[1], &src[0]); COPYTEXCOORD(&dst[numL - 1], &src[1]); - if(numL > 3) + if(leftEdge.divisionCount()) { - WallDivs::Intercept *wdn = leftDivFirst; + WallDivs::Intercept const *wdn = &leftEdge.firstDivision(); float const height = tL - bL; float inter; - for(uint n = 0; n < numL - 3; ++n, wdn = &wdn->next()) + for(int n = 0; n < numL - 3; ++n, wdn = &wdn->next()) { inter = (float( wdn->distance() ) - bL) / height; dst[2 + n].st[0] = src[0].st[0]; @@ -468,8 +468,8 @@ void R_DivTexCoords(rtexcoord_t *dst, rtexcoord_t const *src, WallDivs::Intercep #undef COPYTEXCOORD } -void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, WallDivs::Intercept *leftDivFirst, - uint leftDivCount, WallDivs::Intercept *rightDivFirst, uint rightDivCount, +void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, + SectionEdge const &leftEdge, SectionEdge const &rightEdge, float bL, float tL, float bR, float tR) { #define COPYVCOLOR(d, s) (d)->rgba[CR] = (s)->rgba[CR]; \ @@ -477,8 +477,8 @@ void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, WallDivs::Intercept * (d)->rgba[CB] = (s)->rgba[CB]; \ (d)->rgba[CA] = (s)->rgba[CA]; - uint const numR = 3 + (rightDivFirst && rightDivCount? rightDivCount : 0); - uint const numL = 3 + (leftDivFirst && leftDivCount ? leftDivCount : 0); + int const numR = 3 + rightEdge.divisionCount(); + int const numL = 3 + leftEdge.divisionCount(); if(numR + numL == 6) return; // Nothing to do. @@ -487,15 +487,15 @@ void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, WallDivs::Intercept * COPYVCOLOR(&dst[numL + 1], &src[3]); COPYVCOLOR(&dst[numL + numR-1], &src[2]); - if(numR > 3) + if(rightEdge.divisionCount()) { - WallDivs::Intercept *wdn = rightDivFirst; + WallDivs::Intercept const *wdn = &rightEdge.lastDivision(); float const height = tR - bR; float inter; - for(uint n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) + for(int n = 0; n < numR - 3; ++n, wdn = &wdn->prev()) { inter = (float( wdn->distance() ) - bR) / height; - for(uint c = 0; c < 4; ++c) + for(int c = 0; c < 4; ++c) { dst[numL + 2 + n].rgba[c] = src[2].rgba[c] + (src[3].rgba[c] - src[2].rgba[c]) * inter; } @@ -507,15 +507,15 @@ void R_DivVertColors(ColorRawf *dst, ColorRawf const *src, WallDivs::Intercept * COPYVCOLOR(&dst[1], &src[0]); COPYVCOLOR(&dst[numL - 1], &src[1]); - if(numL > 3) + if(leftEdge.divisionCount()) { - WallDivs::Intercept *wdn = leftDivFirst; + WallDivs::Intercept const *wdn = &leftEdge.firstDivision(); float const height = tL - bL; float inter; - for(uint n = 0; n < numL - 3; ++n, wdn = &wdn->next()) + for(int n = 0; n < numL - 3; ++n, wdn = &wdn->next()) { inter = (float( wdn->distance() ) - bL) / height; - for(uint c = 0; c < 4; ++c) + for(int c = 0; c < 4; ++c) { dst[2 + n].rgba[c] = src[0].rgba[c] + (src[1].rgba[c] - src[0].rgba[c]) * inter; }