diff --git a/doomsday/client/src/render/walledge.cpp b/doomsday/client/src/render/walledge.cpp index 5a15ea44ec..764dcb67af 100644 --- a/doomsday/client/src/render/walledge.cpp +++ b/doomsday/client/src/render/walledge.cpp @@ -90,273 +90,241 @@ static inline coord_t lineSideOffset(LineSideSegment &seg, int edge) return seg.lineSideOffset() + (edge? seg.length() : 0); } -/** - * Determine the map space Z coordinates of a wall section. - * - * @param side Map line side to determine Z heights for. - * @param section LineSide section to determine coordinates for. - * @param skyClip Perform sky plane clipping to line section. - * - * Return values: - * @param bottom Z map space coordinate at the bottom of the wall section. Can be @c 0. - * @param top Z map space coordinate at the top of the wall section. Can be @c 0. - * @param materialOrigin Surface space material coordinate offset. Can be @c 0. - * - * @todo fixme: Should use the visual plane heights of sector clusters. - */ -static void sideSectionCoords(LineSide const &side, int section, bool skyClip = true, - coord_t *retBottom = 0, coord_t *retTop = 0, de::Vector2f *retMaterialOrigin = 0) +DENG2_PIMPL(WallEdge), public IHPlane { - DENG_ASSERT(side.hasSector()); - DENG_ASSERT(side.hasSections()); + WallSpec spec; + int edge; + + HEdge *hedge; - Line const &line = side.line(); + /// The half-plane which partitions the surface coordinate space. + Partition hplane; + + Vector3d pOrigin; + Vector3d pDirection; + + coord_t lo, hi; + + /// Events for the special termination points are allocated with "this". + Event bottom; + Event top; - Sector const *frontSec = line.definesPolyobj()? line.polyobj().sectorPtr() : side.sectorPtr(); - Sector const *backSec = side.back().sectorPtr(); + /// All events along the partition line. + Events *events; + bool needSortEvents; - bool const unpegBottom = (line.flags() & DDLF_DONTPEGBOTTOM) != 0; - bool const unpegTop = (line.flags() & DDLF_DONTPEGTOP) != 0; + Vector2f materialOrigin; - coord_t bottom = 0, top = 0; // Shutup compiler. + Vector3f normal; + bool needUpdateNormal; - if(side.considerOneSided()) + Instance(Public *i, WallSpec const &spec, HEdge &wallHEdge, int edge) + : Base(i), + spec(spec), + edge(edge), + hedge(&wallHEdge), + lo(0), + hi(0), + bottom(*i, 0), + top(*i, 1), + events(0), + needSortEvents(false), + needUpdateNormal(true) { - if(section == LineSide::Middle) - { - bottom = frontSec->floor().visHeight(); - top = frontSec->ceiling().visHeight(); - } - else - { - bottom = top = frontSec->floor().visHeight(); - } + // Determine the map space Z coordinates of the wall section. + LineSideSegment &seg = lineSideSegment(); + Line const &line = seg.line(); + bool const unpegBottom = (line.flags() & DDLF_DONTPEGBOTTOM) != 0; + bool const unpegTop = (line.flags() & DDLF_DONTPEGTOP) != 0; + + BspLeaf const *leaf = + line.definesPolyobj()? &line.polyobj().bspLeaf() + : &hedge->face().mapElement()->as(); - if(retMaterialOrigin) + if(seg.lineSide().considerOneSided()) { - *retMaterialOrigin = side.middle().visMaterialOrigin(); + if(spec.section == LineSide::Middle) + { + lo = leaf->visFloorHeight(); + hi = leaf->visCeilingHeight(); + } + else + { + lo = hi = leaf->visFloorHeight(); + } + + materialOrigin = seg.lineSide().middle().visMaterialOrigin(); if(unpegBottom) { - retMaterialOrigin->y -= top - bottom; + materialOrigin.y -= hi - lo; } } - } - else - { - // Two sided. - bool const stretchMiddle = side.isFlagged(SDF_MIDDLE_STRETCH); - Surface const *surface = &side.surface(section); - Plane const *ffloor = &frontSec->floor(); - Plane const *fceil = &frontSec->ceiling(); - Plane const *bfloor = &backSec->floor(); - Plane const *bceil = &backSec->ceiling(); - - switch(section) + else { - case LineSide::Top: - // Self-referencing lines only ever get a middle. - if(!side.line().isSelfReferencing()) - { - // Can't go over front ceiling (would induce geometry flaws). - if(bceil->visHeight() < ffloor->visHeight()) - bottom = ffloor->visHeight(); - else - bottom = bceil->visHeight(); - top = fceil->visHeight(); + // Two sided. + BspLeaf const *backLeaf = + line.definesPolyobj()? leaf + : &hedge->twin().face().mapElement()->as(); - if(skyClip && fceil->surface().hasSkyMaskedMaterial() && bceil->surface().hasSkyMaskedMaterial()) - { - top = bottom; - } + Plane const *ffloor = &leaf->visFloor(); + Plane const *fceil = &leaf->visCeiling(); + Plane const *bfloor = &backLeaf->visFloor(); + Plane const *bceil = &backLeaf->visCeiling(); - if(retMaterialOrigin) + switch(spec.section) + { + case LineSide::Top: + // Self-referencing lines only ever get a middle. + if(!line.isSelfReferencing()) { - *retMaterialOrigin = surface->visMaterialOrigin(); + // Can't go over front ceiling (would induce geometry flaws). + if(bceil->visHeight() < ffloor->visHeight()) + lo = ffloor->visHeight(); + else + lo = bceil->visHeight(); + + hi = fceil->visHeight(); + + if(spec.flags.testFlag(WallSpec::SkyClip) + && fceil->surface().hasSkyMaskedMaterial() + && bceil->surface().hasSkyMaskedMaterial()) + { + hi = lo; + } + + materialOrigin = seg.lineSide().middle().visMaterialOrigin(); if(!unpegTop) { // Align with normal middle texture. - retMaterialOrigin->y -= fceil->visHeight() - bceil->visHeight(); + materialOrigin.y -= fceil->visHeight() - bceil->visHeight(); } } - } - break; + break; - case LineSide::Bottom: - // Self-referencing lines only ever get a middle. - if(!side.line().isSelfReferencing()) - { - bool const raiseToBackFloor = (fceil->surface().hasSkyMaskedMaterial() && bceil->surface().hasSkyMaskedMaterial() && - fceil->visHeight() < bceil->visHeight() && - bfloor->visHeight() > fceil->visHeight()); - coord_t t = bfloor->visHeight(); - - bottom = ffloor->visHeight(); - // Can't go over the back ceiling, would induce polygon flaws. - if(bfloor->visHeight() > bceil->visHeight()) - t = bceil->visHeight(); - - // Can't go over front ceiling, would induce polygon flaws. - // In the special case of a sky masked upper we must extend the bottom - // section up to the height of the back floor. - if(t > fceil->visHeight() && !raiseToBackFloor) - t = fceil->visHeight(); - top = t; - - if(skyClip && ffloor->surface().hasSkyMaskedMaterial() && bfloor->surface().hasSkyMaskedMaterial()) + case LineSide::Bottom: + // Self-referencing lines only ever get a middle. + if(!line.isSelfReferencing()) { - bottom = top; - } + bool const raiseToBackFloor = + (fceil->surface().hasSkyMaskedMaterial() + && bceil->surface().hasSkyMaskedMaterial() + && fceil->visHeight() < bceil->visHeight() + && bfloor->visHeight() > fceil->visHeight()); - if(retMaterialOrigin) - { - *retMaterialOrigin = surface->visMaterialOrigin(); + coord_t t = bfloor->visHeight(); + + lo = ffloor->visHeight(); + + // Can't go over the back ceiling, would induce polygon flaws. + if(bfloor->visHeight() > bceil->visHeight()) + t = bceil->visHeight(); + + // Can't go over front ceiling, would induce polygon flaws. + // In the special case of a sky masked upper we must extend the bottom + // section up to the height of the back floor. + if(t > fceil->visHeight() && !raiseToBackFloor) + t = fceil->visHeight(); + + hi = t; + + if(spec.flags.testFlag(WallSpec::SkyClip) + && ffloor->surface().hasSkyMaskedMaterial() + && bfloor->surface().hasSkyMaskedMaterial()) + { + lo = hi; + } + + materialOrigin = seg.lineSide().bottom().visMaterialOrigin(); if(bfloor->visHeight() > fceil->visHeight()) { - retMaterialOrigin->y -= (raiseToBackFloor? t : fceil->visHeight()) - bfloor->visHeight(); + materialOrigin.y -= (raiseToBackFloor? t : fceil->visHeight()) + - bfloor->visHeight(); } if(unpegBottom) { // Align with normal middle texture. - retMaterialOrigin->y += (raiseToBackFloor? t : fceil->visHeight()) - bfloor->visHeight(); + materialOrigin.y += (raiseToBackFloor? t : fceil->visHeight()) + - bfloor->visHeight(); } } - } - break; - - case LineSide::Middle: - if(!side.line().isSelfReferencing()) - { - bottom = de::max(bfloor->visHeight(), ffloor->visHeight()); - top = de::min(bceil->visHeight(), fceil->visHeight()); - } - else - { - bottom = ffloor->visHeight(); - top = bceil->visHeight(); - } + break; - if(retMaterialOrigin) - { - retMaterialOrigin->x = surface->visMaterialOrigin().x; - retMaterialOrigin->y = 0; - } + case LineSide::Middle: { + Surface const &middle = seg.lineSide().middle(); - // Perform clipping. - if(surface->hasMaterial() && !stretchMiddle) - { - bool const clipBottom = !(!(devRendSkyMode || P_IsInVoid(viewPlayer)) && ffloor->surface().hasSkyMaskedMaterial() && bfloor->surface().hasSkyMaskedMaterial()); - bool const clipTop = !(!(devRendSkyMode || P_IsInVoid(viewPlayer)) && fceil->surface().hasSkyMaskedMaterial() && bceil->surface().hasSkyMaskedMaterial()); - - coord_t openBottom, openTop; - if(!side.line().isSelfReferencing()) + if(!line.isSelfReferencing()) { - openBottom = bottom; - openTop = top; + lo = de::max(bfloor->visHeight(), ffloor->visHeight()); + hi = de::min(bceil->visHeight(), fceil->visHeight()); } else { - BspLeaf const &bspLeaf = side.leftHEdge()->face().mapElement()->as(); - openBottom = bspLeaf.visFloorHeight(); - openTop = bspLeaf.visCeilingHeight(); + lo = ffloor->visHeight(); + hi = bceil->visHeight(); } - int const matHeight = surface->material().height(); - coord_t const matYOffset = surface->visMaterialOrigin().y; + materialOrigin = Vector2f(middle.visMaterialOrigin().x, 0); - if(openTop > openBottom) + // Perform clipping. + if(middle.hasMaterial() + && !seg.lineSide().isFlagged(SDF_MIDDLE_STRETCH)) { - if(unpegBottom) + coord_t openBottom, openTop; + if(!line.isSelfReferencing()) { - bottom += matYOffset; - top = bottom + matHeight; + openBottom = lo; + openTop = hi; } else { - top += matYOffset; - bottom = top - matHeight; + openBottom = ffloor->visHeight(); + openTop = fceil->visHeight(); } - if(retMaterialOrigin && top > openTop) + if(openTop > openBottom) { - retMaterialOrigin->y = top - openTop; - } + if(unpegBottom) + { + lo += middle.visMaterialOrigin().y; + hi = lo + middle.material().height(); + } + else + { + hi += middle.visMaterialOrigin().y; + lo = hi - middle.material().height(); + } - // Clip it? - if(clipTop || clipBottom) - { - if(clipBottom && bottom < openBottom) - bottom = openBottom; + if(hi > openTop) + { + materialOrigin.y = hi - openTop; + } - if(clipTop && top > openTop) - top = openTop; - } + // Clip it? + bool const clipBottom = !(!(devRendSkyMode || P_IsInVoid(viewPlayer)) && ffloor->surface().hasSkyMaskedMaterial() && bfloor->surface().hasSkyMaskedMaterial()); + bool const clipTop = !(!(devRendSkyMode || P_IsInVoid(viewPlayer)) && fceil->surface().hasSkyMaskedMaterial() && bceil->surface().hasSkyMaskedMaterial()); + if(clipTop || clipBottom) + { + if(clipBottom && lo < openBottom) + lo = openBottom; - if(retMaterialOrigin && !clipTop) - { - retMaterialOrigin->y = 0; + if(clipTop && hi > openTop) + hi = openTop; + } + + if(!clipTop) + { + materialOrigin.y = 0; + } } } + break; } } - break; } - } - - if(retBottom) *retBottom = bottom; - if(retTop) *retTop = top; -} - -DENG2_PIMPL(WallEdge), public IHPlane -{ - WallSpec spec; - int edge; - - HEdge *hedge; - - /// The half-plane which partitions the surface coordinate space. - Partition hplane; - - Vector3d pOrigin; - Vector3d pDirection; - - coord_t lo, hi; - - /// Events for the special termination points are allocated with "this". - Event bottom; - Event top; - - /// All events along the partition line. - Events *events; - bool needSortEvents; - - Vector2f materialOrigin; - - Vector3f normal; - bool needUpdateNormal; - - Instance(Public *i, WallSpec const &spec, HEdge &wallHEdge, int edge) - : Base(i), - spec(spec), - edge(edge), - hedge(&wallHEdge), - lo(0), - hi(0), - bottom(*i, 0), - top(*i, 1), - events(0), - needSortEvents(false), - needUpdateNormal(true) - { - LineSideSegment &seg = lineSideSegment(); - - Vector2f materialOffset; - sideSectionCoords(seg.lineSide(), spec.section, spec.flags.testFlag(WallSpec::SkyClip), - &lo, &hi, &materialOffset); + materialOrigin += Vector2f(lineSideOffset(seg, edge), 0); pOrigin = Vector3d(self.origin(), lo); pDirection = Vector3d(0, 0, hi - lo); - - materialOrigin = Vector2f(lineSideOffset(seg, edge), 0) + materialOffset; } ~Instance()