From a1c34382190d13afbbdcb1f03ca419c5d5df6d60 Mon Sep 17 00:00:00 2001 From: danij Date: Mon, 16 Sep 2013 23:37:49 +0100 Subject: [PATCH] World|Line|Sector: Relocated missing material fixing to Line::Side When a missing material fix is applied, automatically mark reverb data for the adjoining sector cluster dirty. Also applied the fluent interface pattern to Surface as typically one configures several properties at once. --- doomsday/client/include/world/line.h | 10 + doomsday/client/include/world/sector.h | 10 - doomsday/client/include/world/surface.h | 38 ++-- doomsday/client/src/dd_main.cpp | 7 +- doomsday/client/src/world/api_mapedit.cpp | 34 ++-- doomsday/client/src/world/line.cpp | 195 ++++++++++++++++++++ doomsday/client/src/world/sector.cpp | 183 ------------------ doomsday/client/src/world/sectorcluster.cpp | 7 +- doomsday/client/src/world/surface.cpp | 89 +++++---- doomsday/client/src/world/world.cpp | 7 +- 10 files changed, 306 insertions(+), 274 deletions(-) diff --git a/doomsday/client/include/world/line.h b/doomsday/client/include/world/line.h index 9fc926b1ef..8962a2e017 100644 --- a/doomsday/client/include/world/line.h +++ b/doomsday/client/include/world/line.h @@ -534,6 +534,16 @@ class Line : public de::MapElement */ void setShadowVisCount(int newCount); +#ifdef __CLIENT__ + + /** + * Do as in the original DOOM if the texture has not been defined - + * extend the floor/ceiling to fill the space (unless it is skymasked). + */ + void fixMissingMaterials(); + +#endif // __CLIENT__ + protected: int property(DmuArgs &args) const; int setProperty(DmuArgs const &args); diff --git a/doomsday/client/include/world/sector.h b/doomsday/client/include/world/sector.h index 85f48022b4..84d3793e1a 100644 --- a/doomsday/client/include/world/sector.h +++ b/doomsday/client/include/world/sector.h @@ -453,11 +453,6 @@ class Sector : public de::MapElement */ void setLightColor(de::Vector3f const &newLightColor); - /// @copydoc setLightColor() - inline void setLightColor(float red, float green, float blue) { - setLightColor(de::Vector3f(red, green, blue)); - } - /** * Change the strength of the specified @a component of the ambient light * color in the sector. The LightColorChange audience is notified whenever @@ -559,11 +554,6 @@ class Sector : public de::MapElement */ LightGridData &lightGridData(); - /** - * Perform missing material fixes again for all line sides in the sector. - */ - void fixMissingMaterialsForSides(); - #endif // __CLIENT__ protected: diff --git a/doomsday/client/include/world/surface.h b/doomsday/client/include/world/surface.h index 2d858f856f..d39987ff6c 100644 --- a/doomsday/client/include/world/surface.h +++ b/doomsday/client/include/world/surface.h @@ -131,7 +131,7 @@ class Surface : public de::MapElement * * @param newNormal New normal vector (will be normalized if needed). */ - void setNormal(de::Vector3f const &newNormal); + Surface &setNormal(de::Vector3f const &newNormal); /** * Returns a copy of the current @ref surfaceFlags of the surface. @@ -144,7 +144,7 @@ class Surface : public de::MapElement * @param flagsToChange Flags to change the value of. * @param operation Logical operation to perform on the flags. */ - void setFlags(int flagsToChange, de::FlagOp operation = de::SetFlags); + Surface &setFlags(int flagsToChange, de::FlagOp operation = de::SetFlags); /** * Returns @c true iff the surface is flagged @a flagsToTest. @@ -200,7 +200,7 @@ class Surface : public de::MapElement * @param newMaterial New material to apply. Use @c 0 to clear. * @param isMissingFix @c true= this is a fix for a "missing" material. */ - bool setMaterial(Material *newMaterial, bool isMissingFix = false); + Surface &setMaterial(Material *newMaterial, bool isMissingFix = false); /** * Returns the material origin offset of the surface. @@ -212,7 +212,7 @@ class Surface : public de::MapElement * * @param newOrigin New origin offset in map coordinate space units. */ - void setMaterialOrigin(de::Vector2f const &newOrigin); + Surface &setMaterialOrigin(de::Vector2f const &newOrigin); /** * Change the specified @a component of the material origin for the surface. @@ -224,7 +224,7 @@ class Surface : public de::MapElement * * @see setMaterialorigin(), setMaterialOriginX(), setMaterialOriginY() */ - void setMaterialOriginComponent(int component, float newPosition); + Surface &setMaterialOriginComponent(int component, float newPosition); /** * Change the position of the X axis component of the material origin for the @@ -235,7 +235,9 @@ class Surface : public de::MapElement * * @see setMaterialOriginComponent(), setMaterialOriginY() */ - inline void setMaterialOriginX(float newPosition) { setMaterialOriginComponent(0, newPosition); } + inline Surface &setMaterialOriginX(float newPosition) { + return setMaterialOriginComponent(0, newPosition); + } /** * Change the position of the Y axis component of the material origin for the @@ -246,7 +248,9 @@ class Surface : public de::MapElement * * @see setMaterialOriginComponent(), setMaterialOriginX() */ - inline void setMaterialOriginY(float newPosition) { setMaterialOriginComponent(1, newPosition); } + inline Surface &setMaterialOriginY(float newPosition) { + return setMaterialOriginComponent(1, newPosition); + } /** * Compose a URI for the surface's material. If no material is bound then a @@ -272,7 +276,7 @@ class Surface : public de::MapElement * * @see opacity() */ - void setOpacity(float newOpacity); + Surface &setOpacity(float newOpacity); /** * Returns the tint color of the surface. The TintColorChange audience is notified @@ -324,7 +328,7 @@ class Surface : public de::MapElement * * @see tintColor(), setTintColorComponent(), setTintRed(), setTintGreen(), setTintBlue() */ - void setTintColor(de::Vector3f const &newTintColor); + Surface &setTintColor(de::Vector3f const &newTintColor); /** * Change the strength of the specified @a component of the tint color for the @@ -335,7 +339,7 @@ class Surface : public de::MapElement * * @see setTintColor(), setTintRed(), setTintGreen(), setTintBlue() */ - void setTintColorComponent(int component, float newStrength); + Surface &setTintColorComponent(int component, float newStrength); /** * Change the strength of the red component of the tint color for the surface. @@ -345,7 +349,9 @@ class Surface : public de::MapElement * * @see setTintColorComponent(), setTintGreen(), setTintBlue() */ - inline void setTintRed(float newStrength) { setTintColorComponent(0, newStrength); } + inline Surface &setTintRed(float newStrength) { + return setTintColorComponent(0, newStrength); + } /** * Change the strength of the green component of the tint color for the surface. @@ -355,7 +361,9 @@ class Surface : public de::MapElement * * @see setTintColorComponent(), setTintRed(), setTintBlue() */ - inline void setTintGreen(float newStrength) { setTintColorComponent(1, newStrength); } + inline Surface &setTintGreen(float newStrength) { + return setTintColorComponent(1, newStrength); + } /** * Change the strength of the blue component of the tint color for the surface. @@ -365,7 +373,9 @@ class Surface : public de::MapElement * * @see setTintColorComponent(), setTintRed(), setTintGreen() */ - inline void setTintBlue(float newStrength) { setTintColorComponent(2, newStrength); } + inline Surface &setTintBlue(float newStrength) { + return setTintColorComponent(2, newStrength); + } /** * Returns the blendmode for the surface. @@ -377,7 +387,7 @@ class Surface : public de::MapElement * * @param newBlendMode New blendmode. */ - void setBlendMode(blendmode_t newBlendMode); + Surface &setBlendMode(blendmode_t newBlendMode); #ifdef __CLIENT__ diff --git a/doomsday/client/src/dd_main.cpp b/doomsday/client/src/dd_main.cpp index 089710d166..9541680634 100644 --- a/doomsday/client/src/dd_main.cpp +++ b/doomsday/client/src/dd_main.cpp @@ -3001,12 +3001,9 @@ DENG_EXTERN_C void R_SetupMap(int mode, int flags) // Update all sectors. /// @todo Refactor away. foreach(Sector *sector, map.sectors()) + foreach(LineSide *side, sector->sides()) { - sector->fixMissingMaterialsForSides(); - foreach(SectorCluster *cluster, sector->clusters()) - { - cluster->markReverbDirty(); - } + side->fixMissingMaterials(); } #endif diff --git a/doomsday/client/src/world/api_mapedit.cpp b/doomsday/client/src/world/api_mapedit.cpp index 1588f44f87..05cc70e766 100644 --- a/doomsday/client/src/world/api_mapedit.cpp +++ b/doomsday/client/src/world/api_mapedit.cpp @@ -313,18 +313,21 @@ void MPE_LineAddSide(int lineIdx, int sideId, short flags, ddstring_t const *top side.addSections(); // Assign the resolved material if found. - side.top().setMaterial(findMaterialInDict(topMaterialUri)); - side.top().setMaterialOrigin(Vector2f(topOffsetX, topOffsetY)); - side.top().setTintColor(Vector3f(topRed, topGreen, topBlue)); - - side.middle().setMaterial(findMaterialInDict(middleMaterialUri)); - side.middle().setMaterialOrigin(Vector2f(middleOffsetX, middleOffsetY)); - side.middle().setTintColor(Vector3f(middleRed, middleGreen, middleBlue)); - side.middle().setOpacity(middleOpacity); - - side.bottom().setMaterial(findMaterialInDict(bottomMaterialUri)); - side.bottom().setMaterialOrigin(Vector2f(bottomOffsetX, bottomOffsetY)); - side.bottom().setTintColor(Vector3f(bottomRed, bottomGreen, bottomBlue)); + side.top() + .setMaterial(findMaterialInDict(topMaterialUri)) + .setMaterialOrigin(Vector2f(topOffsetX, topOffsetY)) + .setTintColor(Vector3f(topRed, topGreen, topBlue)); + + side.middle() + .setMaterial(findMaterialInDict(middleMaterialUri)) + .setMaterialOrigin(Vector2f(middleOffsetX, middleOffsetY)) + .setTintColor(Vector3f(middleRed, middleGreen, middleBlue)) + .setOpacity(middleOpacity); + + side.bottom() + .setMaterial(findMaterialInDict(bottomMaterialUri)) + .setMaterialOrigin(Vector2f(bottomOffsetX, bottomOffsetY)) + .setTintColor(Vector3f(bottomRed, bottomGreen, bottomBlue)); } #undef MPE_PlaneCreate @@ -341,9 +344,10 @@ int MPE_PlaneCreate(int sectorIdx, coord_t height, ddstring_t const *materialUri plane->setIndexInArchive(archiveIndex); - plane->surface().setMaterial(findMaterialInDict(materialUri)); - plane->surface().setTintColor(Vector3f(tintRed, tintGreen, tintBlue)); - plane->surface().setMaterialOrigin(Vector2f(matOffsetX, matOffsetY)); + plane->surface() + .setMaterial(findMaterialInDict(materialUri)) + .setTintColor(Vector3f(tintRed, tintGreen, tintBlue)) + .setMaterialOrigin(Vector2f(matOffsetX, matOffsetY)); if(!plane->isSectorFloor() && !plane->isSectorCeiling()) { diff --git a/doomsday/client/src/world/line.cpp b/doomsday/client/src/world/line.cpp index bef0a11de6..2ba5f3f1ef 100644 --- a/doomsday/client/src/world/line.cpp +++ b/doomsday/client/src/world/line.cpp @@ -21,6 +21,7 @@ #include #include +#include "dd_main.h" // App_Materials(), verbose #include "m_misc.h" #include "Face" @@ -30,9 +31,11 @@ #include "Sector" #include "Surface" #include "Vertex" +#include "world/maputil.h" #ifdef __CLIENT__ # include "world/map.h" + # include "BiasDigest" # include "BiasIllum" # include "BiasSource" @@ -668,6 +671,198 @@ void Line::Side::setShadowVisCount(int newCount) d->shadowVisCount = newCount; } +#ifdef __CLIENT__ + +/** + * Given a side section, look at the neighbouring surfaces and pick the + * best choice of material used on those surfaces to be applied to "this" + * surface. + * + * Material on back neighbour plane has priority. + * Non-animated materials are preferred. + * Sky materials are ignored. + */ +static Material *chooseFixMaterial(LineSide &side, int section) +{ + Material *choice1 = 0, *choice2 = 0; + + Sector *frontSec = side.sectorPtr(); + Sector *backSec = side.back().sectorPtr(); + + if(backSec) + { + // Our first choice is a material in the other sector. + if(section == LineSide::Bottom) + { + if(frontSec->floor().height() < backSec->floor().height()) + { + choice1 = backSec->floorSurface().materialPtr(); + } + } + else if(section == LineSide::Top) + { + if(frontSec->ceiling().height() > backSec->ceiling().height()) + { + choice1 = backSec->ceilingSurface().materialPtr(); + } + } + + // In the special case of sky mask on the back plane, our best + // choice is always this material. + if(choice1 && choice1->isSkyMasked()) + { + return choice1; + } + } + else + { + // Our first choice is a material on an adjacent wall section. + // Try the left neighbor first. + Line *other = R_FindLineNeighbor(frontSec, &side.line(), side.line().vertexOwner(side.sideId()), + false /*next clockwise*/); + if(!other) + // Try the right neighbor. + other = R_FindLineNeighbor(frontSec, &side.line(), side.line().vertexOwner(side.sideId()^1), + true /*next anti-clockwise*/); + + if(other) + { + if(!other->hasBackSector()) + { + // Our choice is clear - the middle material. + choice1 = other->front().middle().materialPtr(); + } + else + { + // Compare the relative heights to decide. + LineSide &otherSide = other->side(&other->frontSector() == frontSec? Line::Front : Line::Back); + Sector &otherSec = other->side(&other->frontSector() == frontSec? Line::Back : Line::Front).sector(); + + if(otherSec.ceiling().height() <= frontSec->floor().height()) + choice1 = otherSide.top().materialPtr(); + else if(otherSec.floor().height() >= frontSec->ceiling().height()) + choice1 = otherSide.bottom().materialPtr(); + else if(otherSec.ceiling().height() < frontSec->ceiling().height()) + choice1 = otherSide.top().materialPtr(); + else if(otherSec.floor().height() > frontSec->floor().height()) + choice1 = otherSide.bottom().materialPtr(); + // else we'll settle for a plane material. + } + } + } + + // Our second choice is a material from this sector. + choice2 = frontSec->planeSurface(section == LineSide::Bottom? Sector::Floor : Sector::Ceiling).materialPtr(); + + // Prefer a non-animated, non-masked material. + if(choice1 && !choice1->isAnimated() && !choice1->isSkyMasked()) + return choice1; + if(choice2 && !choice2->isAnimated() && !choice2->isSkyMasked()) + return choice2; + + // Prefer a non-masked material. + if(choice1 && !choice1->isSkyMasked()) + return choice1; + if(choice2 && !choice2->isSkyMasked()) + return choice2; + + // At this point we'll accept anything if it means avoiding HOM. + if(choice1) return choice1; + if(choice2) return choice2; + + // We'll assign the special "missing" material... + return &App_Materials().find(de::Uri("System", Path("missing"))).material(); +} + +static void addMissingMaterial(LineSide &side, int section) +{ + // Sides without sections need no fixing. + if(!side.hasSections()) return; + // ...nor those of self-referencing lines. + if(side.line().isSelfReferencing()) return; + // ...nor those of "one-way window" lines. + if(!side.back().hasSections() && side.back().hasSector()) return; + + // A material must actually be missing to qualify for fixing. + Surface &surface = side.surface(section); + if(surface.hasMaterial()) return; + + // Look for and apply a suitable replacement if found. + surface.setMaterial(chooseFixMaterial(side, section), true/* is missing fix */); + + // During map setup we log missing materials. + if(ddMapSetup && verbose) + { + String path = surface.hasMaterial()? surface.material().manifest().composeUri().asText() : ""; + + LOG_WARNING("%s of Line #%d is missing a material for the %s section.\n" + " %s was chosen to complete the definition.") + << (side.isBack()? "Back" : "Front") << side.line().indexInMap() + << (section == LineSide::Middle? "middle" : section == LineSide::Top? "top" : "bottom") + << path; + } + + if(surface.hasMaterial()) + { + // We'll need to recalculate reverb. + if(HEdge *hedge = side.leftHEdge()) + { + if(hedge->hasFace()) + { + BspLeaf &bspLeaf = hedge->face().mapElement()->as(); + if(bspLeaf.hasCluster()) + { + bspLeaf.cluster().markReverbDirty(); + } + } + } + } +} + +void Line::Side::fixMissingMaterials() +{ + if(hasSector() && back().hasSector()) + { + Sector const &frontSec = sector(); + Sector const &backSec = back().sector(); + + // A potential bottom section fix? + if(!(frontSec.floorSurface().hasSkyMaskedMaterial() && + backSec.floorSurface().hasSkyMaskedMaterial())) + { + if(frontSec.floor().height() < backSec.floor().height()) + { + addMissingMaterial(*this, LineSide::Bottom); + } + /*else if(frontSec.floor().height() > backSec.floor().height()) + { + addMissingMaterial(&back(), LineSide::Bottom); + }*/ + } + + // A potential top section fix? + if(!(frontSec.ceilingSurface().hasSkyMaskedMaterial() && + backSec.ceilingSurface().hasSkyMaskedMaterial())) + { + if(backSec.ceiling().height() < frontSec.ceiling().height()) + { + addMissingMaterial(*this, LineSide::Top); + } + /*else if(backSec.ceiling().height() > frontSec.ceiling().height()) + { + addMissingMaterial(back(), LineSide::Top); + }*/ + } + } + else + { + // A potential middle section fix. + addMissingMaterial(*this, LineSide::Middle); + } +} + +#endif // __CLIENT__ + int Line::Side::property(DmuArgs &args) const { switch(args.prop) diff --git a/doomsday/client/src/world/sector.cpp b/doomsday/client/src/world/sector.cpp index 1fbb5f1363..38fd91536a 100644 --- a/doomsday/client/src/world/sector.cpp +++ b/doomsday/client/src/world/sector.cpp @@ -23,8 +23,6 @@ #include -#include "dd_main.h" // App_Materials(), verbose - #include "Face" #include "BspLeaf" @@ -32,7 +30,6 @@ #include "Plane" #include "Surface" #include "world/map.h" -#include "world/maputil.h" #include "world/p_object.h" #include "world/sector.h" @@ -561,186 +558,6 @@ Sector::LightGridData &Sector::lightGridData() return d->lightGridData; } -/** - * Given a side section, look at the neighbouring surfaces and pick the - * best choice of material used on those surfaces to be applied to "this" - * surface. - * - * Material on back neighbour plane has priority. - * Non-animated materials are preferred. - * Sky materials are ignored. - */ -static Material *chooseFixMaterial(LineSide &side, int section) -{ - Material *choice1 = 0, *choice2 = 0; - - Sector *frontSec = side.sectorPtr(); - Sector *backSec = side.back().sectorPtr(); - - if(backSec) - { - // Our first choice is a material in the other sector. - if(section == LineSide::Bottom) - { - if(frontSec->floor().height() < backSec->floor().height()) - { - choice1 = backSec->floorSurface().materialPtr(); - } - } - else if(section == LineSide::Top) - { - if(frontSec->ceiling().height() > backSec->ceiling().height()) - { - choice1 = backSec->ceilingSurface().materialPtr(); - } - } - - // In the special case of sky mask on the back plane, our best - // choice is always this material. - if(choice1 && choice1->isSkyMasked()) - { - return choice1; - } - } - else - { - // Our first choice is a material on an adjacent wall section. - // Try the left neighbor first. - Line *other = R_FindLineNeighbor(frontSec, &side.line(), side.line().vertexOwner(side.sideId()), - false /*next clockwise*/); - if(!other) - // Try the right neighbor. - other = R_FindLineNeighbor(frontSec, &side.line(), side.line().vertexOwner(side.sideId()^1), - true /*next anti-clockwise*/); - - if(other) - { - if(!other->hasBackSector()) - { - // Our choice is clear - the middle material. - choice1 = other->front().middle().materialPtr(); - } - else - { - // Compare the relative heights to decide. - LineSide &otherSide = other->side(&other->frontSector() == frontSec? Line::Front : Line::Back); - Sector &otherSec = other->side(&other->frontSector() == frontSec? Line::Back : Line::Front).sector(); - - if(otherSec.ceiling().height() <= frontSec->floor().height()) - choice1 = otherSide.top().materialPtr(); - else if(otherSec.floor().height() >= frontSec->ceiling().height()) - choice1 = otherSide.bottom().materialPtr(); - else if(otherSec.ceiling().height() < frontSec->ceiling().height()) - choice1 = otherSide.top().materialPtr(); - else if(otherSec.floor().height() > frontSec->floor().height()) - choice1 = otherSide.bottom().materialPtr(); - // else we'll settle for a plane material. - } - } - } - - // Our second choice is a material from this sector. - choice2 = frontSec->planeSurface(section == LineSide::Bottom? Sector::Floor : Sector::Ceiling).materialPtr(); - - // Prefer a non-animated, non-masked material. - if(choice1 && !choice1->isAnimated() && !choice1->isSkyMasked()) - return choice1; - if(choice2 && !choice2->isAnimated() && !choice2->isSkyMasked()) - return choice2; - - // Prefer a non-masked material. - if(choice1 && !choice1->isSkyMasked()) - return choice1; - if(choice2 && !choice2->isSkyMasked()) - return choice2; - - // At this point we'll accept anything if it means avoiding HOM. - if(choice1) return choice1; - if(choice2) return choice2; - - // We'll assign the special "missing" material... - return &App_Materials().find(de::Uri("System", Path("missing"))).material(); -} - -static void addMissingMaterial(LineSide &side, int section) -{ - // Sides without sections need no fixing. - if(!side.hasSections()) return; - // ...nor those of self-referencing lines. - if(side.line().isSelfReferencing()) return; - // ...nor those of "one-way window" lines. - if(!side.back().hasSections() && side.back().hasSector()) return; - - // A material must actually be missing to qualify for fixing. - Surface &surface = side.surface(section); - if(surface.hasMaterial()) return; - - // Look for and apply a suitable replacement if found. - surface.setMaterial(chooseFixMaterial(side, section), true/* is missing fix */); - - // During map setup we log missing materials. - if(ddMapSetup && verbose) - { - String path = surface.hasMaterial()? surface.material().manifest().composeUri().asText() : ""; - - LOG_WARNING("%s of Line #%d is missing a material for the %s section.\n" - " %s was chosen to complete the definition.") - << (side.isBack()? "Back" : "Front") << side.line().indexInMap() - << (section == LineSide::Middle? "middle" : section == LineSide::Top? "top" : "bottom") - << path; - } -} - -void Sector::fixMissingMaterialsForSides() -{ - foreach(LineSide *side, d->sides) - { - /* - * Do as in the original Doom if the texture has not been defined - - * extend the floor/ceiling to fill the space (unless it is skymasked), - * or if there is a midtexture use that instead. - */ - if(side->hasSector() && side->back().hasSector()) - { - Sector const &frontSec = side->sector(); - Sector const &backSec = side->back().sector(); - - // A potential bottom section fix? - if(!(frontSec.floorSurface().hasSkyMaskedMaterial() && - backSec.floorSurface().hasSkyMaskedMaterial())) - { - if(frontSec.floor().height() < backSec.floor().height()) - { - addMissingMaterial(*side, LineSide::Bottom); - } - /*else if(frontSec.floor().height() > backSec.floor().height()) - { - addMissingMaterial(side->back(), LineSide::Bottom); - }*/ - } - - // A potential top section fix? - if(!(frontSec.ceilingSurface().hasSkyMaskedMaterial() && - backSec.ceilingSurface().hasSkyMaskedMaterial())) - { - if(backSec.ceiling().height() < frontSec.ceiling().height()) - { - addMissingMaterial(*side, LineSide::Top); - } - /*else if(backSec.ceiling().height() > frontSec.ceiling().height()) - { - addMissingMaterial(side->back(), LineSide::Top); - }*/ - } - } - else - { - // A potential middle section fix. - addMissingMaterial(*side, LineSide::Middle); - } - } -} - #endif // __CLIENT__ int Sector::property(DmuArgs &args) const diff --git a/doomsday/client/src/world/sectorcluster.cpp b/doomsday/client/src/world/sectorcluster.cpp index e51bdfadaf..47e19ba424 100644 --- a/doomsday/client/src/world/sectorcluster.cpp +++ b/doomsday/client/src/world/sectorcluster.cpp @@ -519,7 +519,7 @@ DENG2_OBSERVES(Plane, HeightChange) if(!ddpl->inGame || !ddpl->mo) continue; - if(!ddpl->mo->bspLeaf || !ddpl->mo->bspLeaf->isDegenerate()) + if(!ddpl->mo->bspLeaf || ddpl->mo->bspLeaf->isDegenerate()) continue; if(&ddpl->mo->bspLeaf->cluster() != thisPublic) continue; @@ -535,7 +535,10 @@ DENG2_OBSERVES(Plane, HeightChange) #ifdef __CLIENT__ // A plane move means we must re-apply missing material fixes. /// @todo optimize: Defer until actually necessary. - self.sector().fixMissingMaterialsForSides(); + foreach(LineSide *side, self.sector().sides()) + { + side->fixMissingMaterials(); + } // We'll need to recalculate environmental audio characteristics. needReverbUpdate = true; diff --git a/doomsday/client/src/world/surface.cpp b/doomsday/client/src/world/surface.cpp index 76d499cd3c..7e7889262c 100644 --- a/doomsday/client/src/world/surface.cpp +++ b/doomsday/client/src/world/surface.cpp @@ -212,7 +212,7 @@ Matrix3f const &Surface::tangentMatrix() const return d->tangentMatrix; } -void Surface::setNormal(Vector3f const &newNormal) +Surface &Surface::setNormal(Vector3f const &newNormal) { Vector3f oldNormal = normal(); Vector3f newNormalNormalized = newNormal.normalize(); @@ -228,6 +228,7 @@ void Surface::setNormal(Vector3f const &newNormal) // Notify interested parties of the change. d->notifyNormalChanged(oldNormal); } + return *this; } int Surface::flags() const @@ -235,9 +236,10 @@ int Surface::flags() const return d->flags; } -void Surface::setFlags(int flagsToChange, FlagOp operation) +Surface &Surface::setFlags(int flagsToChange, FlagOp operation) { applyFlagOperation(d->flags, flagsToChange, operation); + return *this; } bool Surface::hasMaterial() const @@ -260,53 +262,54 @@ Material &Surface::material() const throw MissingMaterialError("Surface::material", "No material is bound"); } -bool Surface::setMaterial(Material *newMaterial, bool isMissingFix) +Surface &Surface::setMaterial(Material *newMaterial, bool isMissingFix) { - if(d->material != newMaterial) + if(d->material == newMaterial) + return *this; + + // Update the missing-material-fix state. + if(!d->material) { - // Update the missing-material-fix state. - if(!d->material) + if(newMaterial && isMissingFix) { - if(newMaterial && isMissingFix) - { - d->materialIsMissingFix = true; + d->materialIsMissingFix = true; - // Sides of selfreferencing map lines should never receive fix materials. - DENG_ASSERT(!(parent().type() == DMU_SIDE && parent().as().line().isSelfReferencing())); - } - } - else if(newMaterial && d->materialIsMissingFix) - { - d->materialIsMissingFix = false; + // Sides of selfreferencing map lines should never receive fix materials. + DENG_ASSERT(!(parent().type() == DMU_SIDE && parent().as().line().isSelfReferencing())); } + } + else if(newMaterial && d->materialIsMissingFix) + { + d->materialIsMissingFix = false; + } - d->material = newMaterial; + d->material = newMaterial; #ifdef __CLIENT__ - // When the material changes any existing decorations are cleared. - clearDecorations(); - _needDecorationUpdate = true; + // When the material changes any existing decorations are cleared. + clearDecorations(); + _needDecorationUpdate = true; - if(!ddMapSetup) + if(!ddMapSetup) + { + map().unlinkInMaterialLists(this); + + if(d->material) { - map().unlinkInMaterialLists(this); + map().linkInMaterialLists(this); - if(d->material) + if(parent().type() == DMU_PLANE) { - map().linkInMaterialLists(this); - - if(parent().type() == DMU_PLANE) - { - de::Uri uri = d->material->manifest().composeUri(); - ded_ptcgen_t const *def = Def_GetGenerator(reinterpret_cast(&uri)); - P_SpawnPlaneParticleGen(def, &parent().as()); - } - + de::Uri uri = d->material->manifest().composeUri(); + ded_ptcgen_t const *def = Def_GetGenerator(reinterpret_cast(&uri)); + P_SpawnPlaneParticleGen(def, &parent().as()); } + } -#endif // __CLIENT__ } - return true; +#endif // __CLIENT__ + + return *this; } Vector2f const &Surface::materialOrigin() const @@ -314,7 +317,7 @@ Vector2f const &Surface::materialOrigin() const return d->materialOrigin; } -void Surface::setMaterialOrigin(Vector2f const &newOrigin) +Surface &Surface::setMaterialOrigin(Vector2f const &newOrigin) { if(d->materialOrigin != newOrigin) { @@ -336,9 +339,10 @@ void Surface::setMaterialOrigin(Vector2f const &newOrigin) // Notify interested parties of the change. d->notifyMaterialOriginChanged(oldMaterialOrigin); } + return *this; } -void Surface::setMaterialOriginComponent(int component, float newPosition) +Surface &Surface::setMaterialOriginComponent(int component, float newPosition) { if(!de::fequal(d->materialOrigin[component], newPosition)) { @@ -362,6 +366,7 @@ void Surface::setMaterialOriginComponent(int component, float newPosition) // Notify interested parties of the change. d->notifyMaterialOriginChanged(oldMaterialOrigin, (1 << component)); } + return *this; } de::Uri Surface::composeMaterialUri() const @@ -432,7 +437,7 @@ float Surface::opacity() const return d->opacity; } -void Surface::setOpacity(float newOpacity) +Surface &Surface::setOpacity(float newOpacity) { DENG_ASSERT(d->isSideMiddle() || d->isSectorExtraPlane()); // sanity check @@ -445,6 +450,7 @@ void Surface::setOpacity(float newOpacity) // Notify interested parties of the change. d->notifyOpacityChanged(oldOpacity); } + return *this; } Vector3f const &Surface::tintColor() const @@ -452,7 +458,7 @@ Vector3f const &Surface::tintColor() const return d->tintColor; } -void Surface::setTintColor(Vector3f const &newTintColor) +Surface &Surface::setTintColor(Vector3f const &newTintColor) { Vector3f newColorClamped(de::clamp(0.f, newTintColor.x, 1.f), de::clamp(0.f, newTintColor.y, 1.f), @@ -466,9 +472,10 @@ void Surface::setTintColor(Vector3f const &newTintColor) // Notify interested parties of the change. d->notifyTintColorChanged(oldTintColor); } + return *this; } -void Surface::setTintColorComponent(int component, float newStrength) +Surface &Surface::setTintColorComponent(int component, float newStrength) { DENG_ASSERT(component >= 0 && component < 3); newStrength = de::clamp(0.f, newStrength, 1.f); @@ -480,6 +487,7 @@ void Surface::setTintColorComponent(int component, float newStrength) // Notify interested parties of the change. d->notifyTintColorChanged(oldTintColor, (1 << component)); } + return *this; } blendmode_t Surface::blendMode() const @@ -487,9 +495,10 @@ blendmode_t Surface::blendMode() const return d->blendMode; } -void Surface::setBlendMode(blendmode_t newBlendMode) +Surface &Surface::setBlendMode(blendmode_t newBlendMode) { d->blendMode = newBlendMode; + return *this; } #ifdef __CLIENT__ diff --git a/doomsday/client/src/world/world.cpp b/doomsday/client/src/world/world.cpp index 20f8c31bcf..9e16efced4 100644 --- a/doomsday/client/src/world/world.cpp +++ b/doomsday/client/src/world/world.cpp @@ -608,12 +608,9 @@ DENG2_PIMPL(World) #ifdef __CLIENT__ /// @todo Refactor away: foreach(Sector *sector, map->sectors()) + foreach(LineSide *side, sector->sides()) { - sector->fixMissingMaterialsForSides(); - foreach(SectorCluster *cluster, sector->clusters()) - { - cluster->markReverbDirty(); - } + side->fixMissingMaterials(); } #endif