diff --git a/doomsday/client/include/render/walledge.h b/doomsday/client/include/render/walledge.h index d2e00b2f18..931f5c9ae2 100644 --- a/doomsday/client/include/render/walledge.h +++ b/doomsday/client/include/render/walledge.h @@ -36,6 +36,44 @@ class Surface; namespace de { +class WallSpec +{ +public: + enum Flag + { + /// Force the geometry to be opaque, irrespective of material opacity. + ForceOpaque = 0x01, + + /// Do not generate geometry for dynamic lights. + NoDynLights = 0x02, + + /// Do not generate geometry for dynamic (mobj) shadows. + NoDynShadows = 0x04, + + /// Do not generate geometry for faked radiosity. + NoFakeRadio = 0x08, + + /// Do not apply angle based light level deltas. + NoLightDeltas = 0x10, + + /// Do not smooth edge normals. + NoEdgeNormalSmoothing = 0x20, + + DefaultFlags = ForceOpaque + }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags flags; + + /// Wall section identifier. + int section; + + WallSpec(int section, Flags = DefaultFlags) : flags(flags), section(section) + {} +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(WallSpec::Flags) + /** * Helper/utility class intended to simplify the process of generating * sections of wall geometry from a map line segment. @@ -64,16 +102,11 @@ class WallEdge typedef QList Intercepts; - enum Flag - { - SmoothNormal = 0x1, - - DefaultFlags = SmoothNormal - }; - Q_DECLARE_FLAGS(Flags, Flag) - public: - WallEdge(HEdge &hedge, int section, int edge, Flags flags = DefaultFlags); + /** + * @param spec Wall section spec. A copy is made. + */ + WallEdge(WallSpec const &spec, HEdge &hedge, int edge); WallEdge(WallEdge const &other); @@ -92,6 +125,8 @@ class WallEdge void prepare(); + WallSpec const &spec() const; + bool isValid() const; de::Vector2d const &origin() const; @@ -124,9 +159,7 @@ class WallEdge DENG2_PRIVATE(d) }; -Q_DECLARE_OPERATORS_FOR_FLAGS(WallEdge::Flags) - -} +} // namespace de namespace std { // std::swap specialization for WallEdge diff --git a/doomsday/client/src/render/rend_main.cpp b/doomsday/client/src/render/rend_main.cpp index 221326245f..199a06f893 100644 --- a/doomsday/client/src/render/rend_main.cpp +++ b/doomsday/client/src/render/rend_main.cpp @@ -1333,30 +1333,22 @@ static uint projectSurfaceShadows(Surface &surface, float glowStrength, surface.tangent(), surface.bitangent(), surface.normal()); } -/** - * @defgroup writeWallSectionFlags Write Wall Section Flags - * Flags for writeWallSection() - * @ingroup flags - */ -///@{ -#define WSF_ADD_DYNLIGHTS 0x01 ///< Write geometry for dynamic lights. -#define WSF_ADD_DYNSHADOWS 0x02 ///< Write geometry for dynamic (mobj) shadows. -#define WSF_ADD_RADIO 0x04 ///< Write geometry for faked radiosity. -#define WSF_FORCE_OPAQUE 0x08 ///< Force the geometry to be opaque. -#define WSF_NO_LIGHTDELTAS 0x10 ///< Do not apply angle based light level deltas. +typedef WallEdge WallEdges[2]; -#define ALL_WRITE_WALL_SECTION_FLAGS WSF_ADD_DYNLIGHTS | WSF_ADD_DYNSHADOWS | WSF_ADD_RADIO | WSF_FORCE_OPAQUE +static bool writeWallSection(WallEdges const edges, BiasSurface &biasSurface, + MapElement &mapElement, coord_t *bottomZ = 0, coord_t *topZ = 0) +{ + WallEdge const &leftEdge = edges[0]; + WallEdge const &rightEdge = edges[1]; + WallSpec const &spec = leftEdge.spec(); -#define DEFAULT_WRITE_WALL_SECTION_FLAGS ALL_WRITE_WALL_SECTION_FLAGS -///@} + if(!leftEdge.isValid() || !rightEdge.isValid() || + de::fequal(leftEdge.bottom().distance(), rightEdge.top().distance())) + return false; + + if(bottomZ) *bottomZ = leftEdge.bottom().distance(); + if(topZ) *topZ = rightEdge.top().distance(); -/** - * @param flags @ref writeWallSectionFlags - */ -static bool writeWallSection(WallEdge const &leftEdge, WallEdge const &rightEdge, - MapElement &mapElement, BiasSurface &biasSurface, - int flags = DEFAULT_WRITE_WALL_SECTION_FLAGS) -{ BspLeaf *bspLeaf = currentBspLeaf; DENG_ASSERT(!isNullLeaf(bspLeaf)); DENG_ASSERT(rightEdge.top().distance() > leftEdge.bottom().distance()); @@ -1430,7 +1422,7 @@ static bool writeWallSection(WallEdge const &leftEdge, WallEdge const &rightEdge // Calculate the light level deltas for this wall section? float leftLightLevelDelta = 0, rightLightLevelDelta = 0; - if(!(flags & WSF_NO_LIGHTDELTAS)) + if(!spec.flags.testFlag(WallSpec::NoLightDeltas)) { wallSectionLightLevelDeltas(leftEdge, rightEdge, leftLightLevelDelta, rightLightLevelDelta); } @@ -1438,8 +1430,8 @@ static bool writeWallSection(WallEdge const &leftEdge, WallEdge const &rightEdge rendworldpoly_params_t parm; zap(parm); parm.flags = RPF_DEFAULT; - parm.forceOpaque = (flags & WSF_FORCE_OPAQUE)? true : false; - parm.alpha = (flags & WSF_FORCE_OPAQUE)? 1 : opacity; + parm.forceOpaque = spec.flags.testFlag(WallSpec::ForceOpaque); + parm.alpha = parm.forceOpaque? 1 : opacity; parm.mapElement = &mapElement; parm.elmIdx = section; parm.bsuf = &biasSurface; @@ -1495,14 +1487,16 @@ static bool writeWallSection(WallEdge const &leftEdge, WallEdge const &rightEdge } // Project dynamic Lights? - if((flags & WSF_ADD_DYNLIGHTS) && !(parm.flags & RPF_SKYMASK)) + if(!spec.flags.testFlag(WallSpec::NoDynLights) && + !(parm.flags & RPF_SKYMASK)) { parm.lightListIdx = projectSurfaceLights(surface, parm.glowing, texTL, texBR, isTwoSidedMiddle); } // Project dynamic shadows? - if((flags & WSF_ADD_DYNSHADOWS) && !(parm.flags & RPF_SKYMASK)) + if(!spec.flags.testFlag(WallSpec::NoDynShadows) && + !(parm.flags & RPF_SKYMASK)) { parm.shadowListIdx = projectSurfaceShadows(surface, parm.glowing, texTL, texBR); } @@ -1555,7 +1549,8 @@ static bool writeWallSection(WallEdge const &leftEdge, WallEdge const &rightEdge if(opaque) { // Render FakeRadio for this section? - if((flags & WSF_ADD_RADIO) && !(parm.flags & RPF_SKYMASK) && + if(!spec.flags.testFlag(WallSpec::NoFakeRadio) && + !(parm.flags & RPF_SKYMASK) && !(parm.glowing > 0) && currentSectorLightLevel > 0 && !line.definesPolyobj()) { @@ -2187,15 +2182,25 @@ static bool useWallSectionLightLevelDeltas(Line::Side &side, int section) return true; } -static WallEdge::Flags wallEdgeSpec(bool usingLightLevelDeltas) +static WallSpec specForWallSection(Line::Side &side, int section, bool twoSidedMiddle = false) { - WallEdge::Flags edgeFlags = WallEdge::DefaultFlags; + WallSpec spec(section); + + if(side.line().definesPolyobj() || twoSidedMiddle) + spec.flags &= ~WallSpec::ForceOpaque; + + if(side.line().definesPolyobj()) + spec.flags |= WallSpec::NoFakeRadio; - // Can normal smoothing be disabled? - if(!usingLightLevelDeltas || !rendLightWallAngleSmooth) - edgeFlags &= ~WallEdge::SmoothNormal; + bool useLightLevelDeltas = useWallSectionLightLevelDeltas(side, section); + if(!useLightLevelDeltas) + spec.flags |= WallSpec::NoLightDeltas; - return edgeFlags; + // We disable normal smoothing if no light angle smoothing will be done. + if(!useLightLevelDeltas || !rendLightWallAngleSmooth) + spec.flags |= WallSpec::NoEdgeNormalSmoothing; + + return spec; } static void writeLeafWallSections() @@ -2220,48 +2225,24 @@ static void writeLeafWallSections() if(pvisSections & Line::Side::BottomFlag) { - bool useLightLevelDeltas = useWallSectionLightLevelDeltas(hedge.lineSide(), Line::Side::Bottom); - WallEdge::Flags edgeFlags = wallEdgeSpec(useLightLevelDeltas); - - WallEdge leftEdge(hedge, Line::Side::Bottom, Line::From, edgeFlags); - WallEdge rightEdge(hedge, Line::Side::Bottom, Line::To, edgeFlags); + WallSpec const spec = specForWallSection(hedge.lineSide(), Line::Side::Bottom); + BiasSurface &biasSurface = hedge.biasSurfaceForGeometryGroup(Line::Side::Bottom); - leftEdge.prepare(); - rightEdge.prepare(); - - if(leftEdge.isValid() && rightEdge.isValid() && - rightEdge.top().distance() > leftEdge.bottom().distance()) - { - int wsFlags = DEFAULT_WRITE_WALL_SECTION_FLAGS - | (!useLightLevelDeltas? WSF_NO_LIGHTDELTAS : 0); + WallEdge edges[] = { WallEdge(spec, hedge, Line::From), + WallEdge(spec, hedge, Line::To) }; - writeWallSection(leftEdge, rightEdge, - hedge, hedge.biasSurfaceForGeometryGroup(Line::Side::Bottom), - wsFlags); - } + writeWallSection(edges, biasSurface, hedge); } if(pvisSections & Line::Side::TopFlag) { - bool useLightLevelDeltas = useWallSectionLightLevelDeltas(hedge.lineSide(), Line::Side::Top); - WallEdge::Flags edgeFlags = wallEdgeSpec(useLightLevelDeltas); - - WallEdge leftEdge(hedge, Line::Side::Top, Line::From, edgeFlags); - WallEdge rightEdge(hedge, Line::Side::Top, Line::To, edgeFlags); + WallSpec const spec = specForWallSection(hedge.lineSide(), Line::Side::Top); + BiasSurface &biasSurface = hedge.biasSurfaceForGeometryGroup(Line::Side::Top); - leftEdge.prepare(); - rightEdge.prepare(); - - if(leftEdge.isValid() && rightEdge.isValid() && - rightEdge.top().distance() > leftEdge.bottom().distance()) - { - int wsFlags = DEFAULT_WRITE_WALL_SECTION_FLAGS - | (!useLightLevelDeltas? WSF_NO_LIGHTDELTAS : 0); + WallEdge edges[] = { WallEdge(spec, hedge, Line::From), + WallEdge(spec, hedge, Line::To) }; - writeWallSection(leftEdge, rightEdge, - hedge, hedge.biasSurfaceForGeometryGroup(Line::Side::Top), - wsFlags); - } + writeWallSection(edges, biasSurface, hedge); } bool wroteOpaqueMiddle = false; @@ -2269,32 +2250,14 @@ static void writeLeafWallSections() if(pvisSections & Line::Side::MiddleFlag) { - bool useLightLevelDeltas = useWallSectionLightLevelDeltas(hedge.lineSide(), Line::Side::Middle); - WallEdge::Flags edgeFlags = wallEdgeSpec(useLightLevelDeltas); - - WallEdge leftEdge(hedge, Line::Side::Middle, Line::From, edgeFlags); - WallEdge rightEdge(hedge, Line::Side::Middle, Line::To, edgeFlags); - - leftEdge.prepare(); - rightEdge.prepare(); - - if(leftEdge.isValid() && rightEdge.isValid() && - rightEdge.top().distance() > leftEdge.bottom().distance()) - { - middleBottomZ = leftEdge.bottom().distance(); - middleTopZ = rightEdge.top().distance(); - - int wsFlags = DEFAULT_WRITE_WALL_SECTION_FLAGS - | (!useLightLevelDeltas? WSF_NO_LIGHTDELTAS : 0); + WallSpec const spec = specForWallSection(hedge.lineSide(), Line::Side::Middle, twoSided); + BiasSurface &biasSurface = hedge.biasSurfaceForGeometryGroup(Line::Side::Middle); - if(twoSided) - wsFlags &= ~WSF_FORCE_OPAQUE; + WallEdge edges[] = { WallEdge(spec, hedge, Line::From), + WallEdge(spec, hedge, Line::To) }; - wroteOpaqueMiddle = - writeWallSection(leftEdge, rightEdge, - hedge, hedge.biasSurfaceForGeometryGroup(Line::Side::Middle), - wsFlags); - } + wroteOpaqueMiddle = + writeWallSection(edges, biasSurface, hedge, &middleBottomZ, &middleTopZ); } bool coveredOpenRange = @@ -2332,24 +2295,18 @@ static void writeLeafPolyobjs() // Done here because of the logic of doom.exe wrt the automap. reportWallSectionDrawn(hedge.line()); - WallEdge leftEdge(hedge, Line::Side::Middle, Line::From); - WallEdge rightEdge(hedge, Line::Side::Middle, Line::To); + WallSpec const spec = specForWallSection(hedge.lineSide(), Line::Side::Middle); + BiasSurface &biasSurface = hedge.biasSurfaceForGeometryGroup(Line::Side::Middle); - leftEdge.prepare(); - rightEdge.prepare(); + WallEdge edges[] = { WallEdge(spec, hedge, Line::From), + WallEdge(spec, hedge, Line::To) }; - if(leftEdge.isValid() && rightEdge.isValid() && - rightEdge.top().distance() > leftEdge.bottom().distance()) - { - bool opaque = writeWallSection(leftEdge, rightEdge, - hedge, hedge.biasSurfaceForGeometryGroup(Line::Side::Middle), - WSF_ADD_DYNLIGHTS | WSF_ADD_DYNSHADOWS); + bool opaque = writeWallSection(edges, biasSurface, hedge); - // We can occlude the wall range if the opening is filled (when the viewer is not in the void). - if(opaque && !P_IsInVoid(viewPlayer)) - { - C_AddRangeFromViewRelPoints(hedge.origin(), hedge.twin().origin()); - } + // We can occlude the wall range if the opening is filled (when the viewer is not in the void). + if(opaque && !P_IsInVoid(viewPlayer)) + { + C_AddRangeFromViewRelPoints(hedge.origin(), hedge.twin().origin()); } } } diff --git a/doomsday/client/src/render/walledge.cpp b/doomsday/client/src/render/walledge.cpp index 04e9828935..c8bd83294c 100644 --- a/doomsday/client/src/render/walledge.cpp +++ b/doomsday/client/src/render/walledge.cpp @@ -50,10 +50,9 @@ Vector3d WallEdge::Intercept::origin() const DENG2_PIMPL(WallEdge), public IHPlane { + WallSpec spec; Line::Side *mapSide; - int section; int edge; - Flags flags; coord_t lineOffset; Vertex *lineVertex; @@ -83,13 +82,12 @@ DENG2_PIMPL(WallEdge), public IHPlane {} } hplane; - Instance(Public *i, Line::Side *mapSide, int section, int edge, - Flags flags, coord_t lineOffset, Vertex *lineVertex) + Instance(Public *i, WallSpec const &spec, Line::Side *mapSide, int edge, + coord_t lineOffset, Vertex *lineVertex) : Base(i), + spec(spec), mapSide(mapSide), - section(section), edge(edge), - flags(flags), lineOffset(lineOffset), lineVertex(lineVertex), isValid(false) @@ -97,10 +95,9 @@ DENG2_PIMPL(WallEdge), public IHPlane Instance(Public *i, Instance const &other) : Base(i), + spec (other.spec), mapSide (other.mapSide), - section (other.section), edge (other.edge), - flags (other.flags), lineOffset (other.lineOffset), lineVertex (other.lineVertex), isValid (other.isValid), @@ -228,7 +225,7 @@ DENG2_PIMPL(WallEdge), public IHPlane if(!base) return; // Check for neighborhood division? - if(section == Line::Side::Middle && mapSide->back().hasSector()) + if(spec.section == Line::Side::Middle && mapSide->back().hasSector()) return; Sector const *frontSec = mapSide->sectorPtr(); @@ -332,7 +329,7 @@ DENG2_PIMPL(WallEdge), public IHPlane diff = 0; // Are we not blending? - if(!(flags & SmoothNormal)) + if(spec.flags.testFlag(WallSpec::NoEdgeNormalSmoothing)) return 0; // Polyobj lines have no owner rings. @@ -373,8 +370,8 @@ DENG2_PIMPL(WallEdge), public IHPlane Instance &operator = (Instance const &); // no assignment }; -WallEdge::WallEdge(HEdge &hedge, int section, int edge, Flags flags) - : d(new Instance(this, &hedge.lineSide(), section, edge, flags, +WallEdge::WallEdge(WallSpec const &spec, HEdge &hedge, int edge) + : d(new Instance(this, spec, &hedge.lineSide(), edge, hedge.lineOffset() + (edge? hedge.length() : 0), edge? &hedge.twin().vertex() : &hedge.vertex())) { @@ -397,12 +394,12 @@ Line::Side &WallEdge::mapSide() const Surface &WallEdge::surface() const { - return d->mapSide->surface(d->section); + return d->mapSide->surface(d->spec.section); } int WallEdge::section() const { - return d->section; + return d->spec.section; } Vector2d const &WallEdge::origin() const @@ -477,7 +474,7 @@ static bool shouldSmoothNormals(Surface &sufA, Surface &sufB, binangle_t angleDi void WallEdge::prepare() { coord_t bottom, top; - R_SideSectionCoords(*d->mapSide, d->section, &bottom, &top, &d->materialOrigin); + R_SideSectionCoords(*d->mapSide, d->spec.section, &bottom, &top, &d->materialOrigin); d->isValid = (top >= bottom); if(!d->isValid) return; @@ -512,7 +509,7 @@ void WallEdge::prepare() // Determine the edge normal. /// @todo Cache the smoothed normal value somewhere. - Surface &surface = d->mapSide->surface(d->section); + Surface &surface = d->mapSide->surface(d->spec.section); binangle_t angleDiff; Surface *blendSurface = d->findBlendNeighbor(angleDiff); @@ -527,6 +524,11 @@ void WallEdge::prepare() } } +WallSpec const &WallEdge::spec() const +{ + return d->spec; +} + Vector2f const &WallEdge::materialOrigin() const { d->verifyValid();