From 90eff1172a6b50cd65a7623762465cb365dbcf2e Mon Sep 17 00:00:00 2001 From: danij Date: Sun, 22 Sep 2013 20:24:21 +0100 Subject: [PATCH] World|Sector: Extend dynamic plane mapping to those with sky-masked materials With the plane mapping algorithm now finalized and the map renderer updated accordingly we can extend support to planes with a sky-masked material, also. Back to Saturn X: Episode 1 uses such constructs frequently. --- doomsday/client/include/render/rend_main.h | 8 +++ doomsday/client/include/world/bspleaf.h | 14 ---- doomsday/client/include/world/sector.h | 25 ++++--- doomsday/client/src/render/lightgrid.cpp | 3 +- doomsday/client/src/render/r_things.cpp | 9 +-- doomsday/client/src/render/rend_fakeradio.cpp | 6 +- doomsday/client/src/render/rend_main.cpp | 63 +++++++++++++--- doomsday/client/src/render/rend_particle.cpp | 6 +- doomsday/client/src/render/sprite.cpp | 12 ++-- doomsday/client/src/world/bspleaf.cpp | 14 ---- doomsday/client/src/world/sector.cpp | 10 --- doomsday/client/src/world/sectorcluster.cpp | 72 ++++++++++--------- 12 files changed, 139 insertions(+), 103 deletions(-) diff --git a/doomsday/client/include/render/rend_main.h b/doomsday/client/include/render/rend_main.h index dd3f4695cc..5be4dfbea6 100644 --- a/doomsday/client/include/render/rend_main.h +++ b/doomsday/client/include/render/rend_main.h @@ -28,6 +28,8 @@ #include "dd_types.h" +#include "Sector" + #include "MaterialVariantSpec" #include "WallEdge" @@ -156,6 +158,12 @@ void Rend_DrawLightModMatrix(); /** * Sector light color may be affected by the sky light color. */ +de::Vector3f const &Rend_SectorLightColor(SectorCluster const &cluster); + +/** + * @copydoc Rend_SectorLightColor() + * @deprecated Caller should work at cluster level. + */ de::Vector3f const &Rend_SectorLightColor(Sector const §or); /** diff --git a/doomsday/client/include/world/bspleaf.h b/doomsday/client/include/world/bspleaf.h index 17292852ff..f1d8485a79 100644 --- a/doomsday/client/include/world/bspleaf.h +++ b/doomsday/client/include/world/bspleaf.h @@ -361,20 +361,6 @@ class BspLeaf : public de::MapElement #ifdef __CLIENT__ - /** - * Determines whether the BSP leaf has a positive world volume. For this - * to be true the following criteria must be met: - * - * - The polygon geometry is @em not degenerate (see @ref isDegenerate()). - * - A sector is attributed (see @ref hasSector()) - * - The height of floor is lower than that of the ceiling plane for the - * attributed sector. - * - * @param useSmoothedHeights @c true= use the @em smoothed plane heights - * instead of the @em sharp heights. - */ - bool hasWorldVolume(bool useSmoothedHeights = true) const; - /** * Returns a pointer to the face geometry half-edge which has been chosen * for use as the base for a triangle fan GL primitive. May return @c 0 if diff --git a/doomsday/client/include/world/sector.h b/doomsday/client/include/world/sector.h index cd55f6fd00..3a8216e20f 100644 --- a/doomsday/client/include/world/sector.h +++ b/doomsday/client/include/world/sector.h @@ -154,6 +154,14 @@ class Sector : public de::MapElement */ void markVisPlanesDirty(); + /** + * Returns @c true iff at least one of the mapped visual planes of the + * cluster presently has a sky-masked material bound. + * + * @see Surface::hasSkyMaskedMaterial() + */ + bool hasSkyMaskedPlane() const; + /** * Provides access to the list of all BSP leafs in the cluster, for * efficient traversal. @@ -180,6 +188,15 @@ class Sector : public de::MapElement #ifdef __CLIENT__ + /** + * Determines whether the cluster has a positive world volume, i.e., the + * height of floor is lower than that of the ceiling plane. + * + * @param useSmoothedHeights @c true= use the @em smoothed plane heights + * instead of the @em sharp heights. + */ + bool hasWorldVolume(bool useSmoothedHeights = true) const; + /** * Returns a rough approximation of the total combined area of the geometry * for all BSP leafs which define the cluster (map units squared). @@ -284,14 +301,6 @@ class Sector : public de::MapElement */ inline int planeCount() const { return planes().count(); } - /** - * Returns @c true iff at least one of the surfaces of a plane in/owned - * by the sector presently has a sky-masked material bound. - * - * @see Surface::hasSkyMaskedMaterial() - */ - bool hasSkyMaskedPlane() const; - /** * Convenient accessor method for returning the surface of the specified * plane of the sector. diff --git a/doomsday/client/src/render/lightgrid.cpp b/doomsday/client/src/render/lightgrid.cpp index f21aea0896..1650d7aef1 100644 --- a/doomsday/client/src/render/lightgrid.cpp +++ b/doomsday/client/src/render/lightgrid.cpp @@ -923,7 +923,8 @@ void LightGrid::update() continue; // Determine the ambient light properties of the sector at this block. - Sector §or = block.sector(); + /// @todo fixme: Should work with sector clusters instead. + Sector §or = block.sector(); Vector3f const &color = Rend_SectorLightColor(sector); float const level = sector.lightLevel(); int const bias = biasForSector(sector); diff --git a/doomsday/client/src/render/r_things.cpp b/doomsday/client/src/render/r_things.cpp index 0630998cb7..78b80494d5 100644 --- a/doomsday/client/src/render/r_things.cpp +++ b/doomsday/client/src/render/r_things.cpp @@ -60,10 +60,10 @@ static void evaluateLighting(Vector3d const &origin, BspLeaf *bspLeafAtOrigin, } else { - Sector const &sec = bspLeafAtOrigin->sector(); - Vector3f const &secColor = Rend_SectorLightColor(sec); + SectorCluster const &cluster = bspLeafAtOrigin->cluster(); + Vector3f const &secColor = Rend_SectorLightColor(cluster); - float lightLevel = sec.lightLevel(); + float lightLevel = cluster.sector().lightLevel(); /* if(spr->type == VSPR_DECORATION) { // Wall decorations receive an additional light delta. @@ -186,7 +186,8 @@ void R_ProjectSprite(mobj_t *mo) float const alpha = Mobj_Alpha(mo); if(alpha <= 0) return; // ...origin lies in a sector with no volume? - if(!mo->bspLeaf->hasWorldVolume()) return; + if(!mo->bspLeaf->hasCluster()) return; + if(!mo->bspLeaf->cluster().hasWorldVolume()) return; // Determine distance to object. Vector3d const moPos = mobjOriginSmoothed(mo); diff --git a/doomsday/client/src/render/rend_fakeradio.cpp b/doomsday/client/src/render/rend_fakeradio.cpp index 1ac3f00568..72240ca4ec 100644 --- a/doomsday/client/src/render/rend_fakeradio.cpp +++ b/doomsday/client/src/render/rend_fakeradio.cpp @@ -1262,8 +1262,10 @@ static void writeShadowSection(int planeIndex, LineSide &side, float shadowDark) // If the sector containing the shadowing line section is fully closed (i.e., volume // is not positive) then skip shadow drawing entirely. /// @todo Encapsulate this logic in ShadowEdge -ds - if(!leftHEdge->hasFace() || - !leftHEdge->face().mapElement()->as().hasWorldVolume()) + if(!leftHEdge->hasFace()) return; + + BspLeaf &frontLeaf = leftHEdge->face().mapElement()->as(); + if(!frontLeaf.hasCluster() || !frontLeaf.cluster().hasWorldVolume()) return; ShadowEdge leftEdge(*leftHEdge, Line::From); diff --git a/doomsday/client/src/render/rend_main.cpp b/doomsday/client/src/render/rend_main.cpp index fa28375aae..1593c63227 100644 --- a/doomsday/client/src/render/rend_main.cpp +++ b/doomsday/client/src/render/rend_main.cpp @@ -329,7 +329,7 @@ static void reportWallSectionDrawn(Line &line) static inline bool isNullLeaf(BspLeaf const *leaf) { - return !leaf || !leaf->hasWorldVolume(); + return !leaf || !leaf->hasCluster() || !leaf->cluster().hasWorldVolume(); } void Rend_Init() @@ -483,13 +483,58 @@ float Rend_ShadowAttenuationFactor(coord_t distance) return 1; } -Vector3f const &Rend_SectorLightColor(Sector const §or) +static Vector3f skyLightColor; +static Vector3f oldSkyAmbientColor(-1.f, -1.f, -1.f); +static float oldRendSkyLight = -1; + +Vector3f const &Rend_SectorLightColor(SectorCluster const &cluster) { - static Vector3f skyLightColor; - static Vector3f oldSkyAmbientColor(-1.f, -1.f, -1.f); - static float oldRendSkyLight = -1; + if(rendSkyLight > .001f && cluster.hasSkyMaskedPlane()) + { + ColorRawf const *ambientColor = Sky_AmbientColor(); + + if(rendSkyLight != oldRendSkyLight || + !INRANGE_OF(ambientColor->red, oldSkyAmbientColor.x, .001f) || + !INRANGE_OF(ambientColor->green, oldSkyAmbientColor.y, .001f) || + !INRANGE_OF(ambientColor->blue, oldSkyAmbientColor.z, .001f)) + { + skyLightColor = Vector3f(ambientColor->rgb); + R_AmplifyColor(skyLightColor); + + // Apply the intensity factor cvar. + for(int i = 0; i < 3; ++i) + { + skyLightColor[i] = skyLightColor[i] + (1 - rendSkyLight) * (1.f - skyLightColor[i]); + } - if(rendSkyLight > .001f && sector.hasSkyMaskedPlane()) + // When the sky light color changes we must update the light grid. + markLightGridForFullUpdate(); + oldSkyAmbientColor = Vector3f(ambientColor->rgb); + } + + oldRendSkyLight = rendSkyLight; + return skyLightColor; + } + + // A non-skylight sector (i.e., everything else!) + // Return the sector's ambient light color. + return cluster.sector().lightColor(); +} + +static bool sectorHasSkyMaskedPlane(Sector const §or) +{ + foreach(Plane *plane, sector.planes()) + { + if(plane->surface().hasSkyMaskedMaterial()) + return true; + } + return false; +} + +/// @todo refactor away. +Vector3f const &Rend_SectorLightColor(Sector const §or) +{ + if(rendSkyLight > .001f && sectorHasSkyMaskedPlane(sector)) { ColorRawf const *ambientColor = Sky_AmbientColor(); @@ -1609,7 +1654,7 @@ static void writeWallSection(HEdge &hedge, int section, if(twoSidedMiddle && side.sectorPtr() != leaf->sectorPtr()) { // Undo temporary draw state changes. - currentSectorLightColor = Rend_SectorLightColor(leaf->sector()); + currentSectorLightColor = Rend_SectorLightColor(leaf->cluster()); currentSectorLightLevel = leaf->sector().lightLevel(); } @@ -1811,7 +1856,7 @@ static void writeLeafPlane(Plane &plane) if(&plane.sector() != leaf->sectorPtr()) { // Undo temporary draw state changes. - currentSectorLightColor = Rend_SectorLightColor(leaf->sector()); + currentSectorLightColor = Rend_SectorLightColor(leaf->cluster()); currentSectorLightLevel = leaf->sector().lightLevel(); } @@ -2529,7 +2574,7 @@ static void makeCurrent(BspLeaf *bspLeaf) // Update draw state. if(sectorChanged) { - currentSectorLightColor = Rend_SectorLightColor(bspLeaf->sector()); + currentSectorLightColor = Rend_SectorLightColor(bspLeaf->cluster()); currentSectorLightLevel = bspLeaf->sector().lightLevel(); } } diff --git a/doomsday/client/src/render/rend_particle.cpp b/doomsday/client/src/render/rend_particle.cpp index 5e5f8fd649..b3a8a738d5 100644 --- a/doomsday/client/src/render/rend_particle.cpp +++ b/doomsday/client/src/render/rend_particle.cpp @@ -471,9 +471,9 @@ static void setupModelParamsForParticle(rendmodelparams_t* params, } else { - Sector §or = pt->bspLeaf->sector(); - float lightLevel = sector.lightLevel(); - Vector3f const &secColor = Rend_SectorLightColor(sector); + SectorCluster &cluster = pt->bspLeaf->cluster(); + float lightLevel = cluster.sector().lightLevel(); + Vector3f const &secColor = Rend_SectorLightColor(cluster); // Apply distance attenuation. lightLevel = Rend_AttenuateLightLevel(params->distance, lightLevel); diff --git a/doomsday/client/src/render/sprite.cpp b/doomsday/client/src/render/sprite.cpp index 0c6edd1666..67d484eee3 100644 --- a/doomsday/client/src/render/sprite.cpp +++ b/doomsday/client/src/render/sprite.cpp @@ -324,11 +324,11 @@ static void setupPSpriteParams(rendpspriteparams_t *params, vispsprite_t *spr) } else { - Sector §or = spr->data.sprite.bspLeaf->sector(); - Vector3f const &secColor = Rend_SectorLightColor(sector); + SectorCluster &cluster = spr->data.sprite.bspLeaf->cluster(); + Vector3f const &secColor = Rend_SectorLightColor(cluster); // No need for distance attentuation. - float lightLevel = sector.lightLevel(); + float lightLevel = cluster.sector().lightLevel(); // Add extra light plus bonus. lightLevel += Rend_ExtraLightDelta(); @@ -711,11 +711,11 @@ static void setupModelParamsForVisPSprite(rendmodelparams_t *params, vispsprite_ } else { - Sector §or = spr->data.model.bspLeaf->sector(); - Vector3f const &secColor = Rend_SectorLightColor(sector); + SectorCluster &cluster = spr->data.model.bspLeaf->cluster(); + Vector3f const &secColor = Rend_SectorLightColor(cluster); // Diminished light (with compression). - float lightLevel = sector.lightLevel(); + float lightLevel = cluster.sector().lightLevel(); // No need for distance attentuation. diff --git a/doomsday/client/src/world/bspleaf.cpp b/doomsday/client/src/world/bspleaf.cpp index 4f275e3a39..bc8977fe85 100644 --- a/doomsday/client/src/world/bspleaf.cpp +++ b/doomsday/client/src/world/bspleaf.cpp @@ -424,20 +424,6 @@ bool BspLeaf::polyContains(Vector2d const &point) const #ifdef __CLIENT__ -bool BspLeaf::hasWorldVolume(bool useSmoothedHeights) const -{ - if(!hasCluster()) return false; - - if(useSmoothedHeights) - { - return visCeilingHeightSmoothed() - visFloorHeightSmoothed() > 0; - } - else - { - return ceilingHeight() - floorHeight() > 0; - } -} - HEdge *BspLeaf::fanBase() const { if(d->needUpdateFanBase) diff --git a/doomsday/client/src/world/sector.cpp b/doomsday/client/src/world/sector.cpp index a95476f8b8..cd79a72656 100644 --- a/doomsday/client/src/world/sector.cpp +++ b/doomsday/client/src/world/sector.cpp @@ -396,16 +396,6 @@ Sector::Planes const &Sector::planes() const return d->planes; } -bool Sector::hasSkyMaskedPlane() const -{ - foreach(Plane *plane, d->planes) - { - if(plane->surface().hasSkyMaskedMaterial()) - return true; - } - return false; -} - Sector::Clusters const &Sector::clusters() const { return d->clusters; diff --git a/doomsday/client/src/world/sectorcluster.cpp b/doomsday/client/src/world/sectorcluster.cpp index 3bd8f2ba69..e2557f1ab4 100644 --- a/doomsday/client/src/world/sectorcluster.cpp +++ b/doomsday/client/src/world/sectorcluster.cpp @@ -362,28 +362,6 @@ DENG2_OBSERVES(Plane, HeightChange) } } - bool suitableForDynamicMapping(int planeIdx) - { - if(planeIdx == Sector::Floor) - { - if(!classification().testFlag(AllMissingBottom)) - return false; - - // The plane must not use a sky-masked material. - if(self.sector().floor().surface().hasSkyMaskedMaterial()) - return false; - } - if(planeIdx == Sector::Ceiling) - { - if(!classification().testFlag(AllMissingTop)) - return false; - - if(self.sector().ceiling().surface().hasSkyMaskedMaterial()) - return false; - } - return true; - } - void remapVisPlanes() { Sector §or = self.sector(); @@ -468,8 +446,8 @@ DENG2_OBSERVES(Plane, HeightChange) if(sector.ceiling().height() <= sector.floor().height()) return; - bool doFloor = !floorIsMapped() && suitableForDynamicMapping(Sector::Floor); - bool doCeiling = !ceilingIsMapped() && suitableForDynamicMapping(Sector::Ceiling); + bool doFloor = !floorIsMapped() && classification().testFlag(AllMissingBottom); + bool doCeiling = !ceilingIsMapped() && classification().testFlag(AllMissingTop); if(!doFloor && !doCeiling) return; @@ -485,18 +463,26 @@ DENG2_OBSERVES(Plane, HeightChange) { Cluster &extCluster = hedge->twin().face().mapElement()->as().cluster(); - if(doFloor && !floorIsMapped() && - extCluster.visFloor().height() > sector.floor().height()) + if(doFloor && !floorIsMapped()) { - map(Sector::Floor, &extCluster); - if(!doCeiling) break; + Plane &extVisPlane = extCluster.visFloor(); + if(!extVisPlane.surface().hasSkyMaskedMaterial() && + extVisPlane.height() > sector.floor().height()) + { + map(Sector::Floor, &extCluster); + if(!doCeiling) break; + } } - if(doCeiling && !ceilingIsMapped() && - extCluster.visCeiling().height() < sector.ceiling().height()) + if(doCeiling && !ceilingIsMapped()) { - map(Sector::Ceiling, &extCluster); - if(!doFloor) break; + Plane &extVisPlane = extCluster.visCeiling(); + if(!extVisPlane.surface().hasSkyMaskedMaterial() && + extCluster.visCeiling().height() < sector.ceiling().height()) + { + map(Sector::Ceiling, &extCluster); + if(!doFloor) break; + } } } @@ -835,6 +821,18 @@ Sector::Cluster::BspLeafs const &Sector::Cluster::bspLeafs() const #ifdef __CLIENT__ +bool Sector::Cluster::hasWorldVolume(bool useSmoothedHeights) const +{ + if(useSmoothedHeights) + { + return visCeiling().heightSmoothed() - visFloor().heightSmoothed() > 0; + } + else + { + return ceiling().height() - floor().height() > 0; + } +} + coord_t Sector::Cluster::roughArea() const { AABoxd const &bounds = aaBox(); @@ -862,4 +860,14 @@ void Sector::Cluster::markVisPlanesDirty() d->maybeInvalidateMapping(Sector::Ceiling); } +bool Sector::Cluster::hasSkyMaskedPlane() const +{ + for(int i = 0; i < sector().planeCount(); ++i) + { + if(visPlane(i).surface().hasSkyMaskedMaterial()) + return true; + } + return false; +} + #endif // __CLIENT__