From 8c8653160d90cb5b37cb164861f3f2ae4f26ba2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 20 Aug 2013 09:52:27 +0200 Subject: [PATCH] Crash fix, material fix --- apps/openmw/mwrender/renderingmanager.cpp | 37 ++++++++++++++++------- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/scene.cpp | 4 +++ components/terrain/material.cpp | 28 +++++++++++------ components/terrain/material.hpp | 5 +++ components/terrain/quadtreenode.cpp | 37 +++++++++++++++++++++-- components/terrain/quadtreenode.hpp | 5 +++ components/terrain/storage.cpp | 2 +- components/terrain/terrain.cpp | 18 +++++++++++ components/terrain/terrain.hpp | 9 +++++- files/materials/terrain.shader | 1 - 11 files changed, 123 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 63de044c8d..2d129a3fbc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -244,16 +244,6 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) mObjects.buildStaticGeometry (*store); sh::Factory::getInstance().unloadUnreferencedMaterials(); mDebugging->cellAdded(store); - if (store->isExterior()) - { - if (!mTerrain) - { - mTerrain = new Terrain::Terrain(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain, - Settings::Manager::getBool("distant land", "Terrain"), - Settings::Manager::getBool("shader", "Terrain")); - mTerrain->update(mRendering.getCamera()->getRealPosition()); - } - } waterAdded(store); } @@ -848,7 +838,12 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mWater->processChangedSettings(settings); if (rebuild) + { mObjects.rebuildStaticGeometry(); + if (mTerrain) + mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), + Settings::Manager::getBool("split", "Shadows")); + } } void RenderingManager::setMenuTransparency(float val) @@ -994,7 +989,7 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con void RenderingManager::frameStarted(float dt, bool paused) { - if (mTerrain) + if (mTerrain && mTerrain->getVisible()) mTerrain->update(mRendering.getCamera()->getRealPosition()); if (!paused) @@ -1012,4 +1007,24 @@ float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) return mTerrain->getHeightAt(worldPos); } +void RenderingManager::enableTerrain(bool enable) +{ + if (enable) + { + if (!mTerrain) + { + mTerrain = new Terrain::Terrain(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain, + Settings::Manager::getBool("distant land", "Terrain"), + Settings::Manager::getBool("shader", "Terrain")); + mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), + Settings::Manager::getBool("split", "Shadows")); + mTerrain->update(mRendering.getCamera()->getRealPosition()); + } + mTerrain->setVisible(true); + } + else + if (mTerrain) + mTerrain->setVisible(false); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ea6e8d409f..45929f0640 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -110,6 +110,8 @@ public: void cellAdded (MWWorld::CellStore *store); void waterAdded(MWWorld::CellStore *store); + void enableTerrain(bool enable); + void removeWater(); void preCellChange (MWWorld::CellStore* store); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 07155d3490..9e96eebf17 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -362,6 +362,8 @@ namespace MWWorld const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + mRendering.enableTerrain(false); + std::string loadingInteriorText; loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); @@ -440,6 +442,8 @@ namespace MWWorld MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); + mRendering.enableTerrain(true); + changeCell (x, y, position, true); } diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index f85326492e..4a91ad99a6 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -34,6 +34,8 @@ namespace Terrain MaterialGenerator::MaterialGenerator(bool shaders) : mShaders(shaders) + , mShadows(false) + , mSplitShadows(false) { } @@ -46,6 +48,11 @@ namespace Terrain // first layer doesn't need blendmap --freeTextureUnits; + if (mSplitShadows) + freeTextureUnits -= 3; + else if (mShadows) + --freeTextureUnits; + // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)) + 1; } @@ -158,7 +165,6 @@ namespace Terrain } else { - sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance (name.str()); material->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); @@ -179,12 +185,14 @@ namespace Terrain tex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); // shadow. TODO: repeated, put in function - for (Ogre::uint i = 0; i < 3; ++i) + if (mShadows) { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + for (Ogre::uint i = 0; i < (mSplitShadows ? 3 : 1); ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( Ogre::StringConverter::toString(1)))); @@ -272,12 +280,14 @@ namespace Terrain } // shadow - for (Ogre::uint i = 0; i < 3; ++i) + if (mShadows) { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + for (Ogre::uint i = 0; i < (mSplitShadows ? 3 : 1); ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass)))); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 068bb7a84c..2788b79c49 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -21,6 +21,9 @@ namespace Terrain const std::vector& getBlendmapList() { return mBlendmapList; } void setCompositeMap (const std::string& name) { mCompositeMap = name; } + void enableShadows(bool shadows) { mShadows = shadows; } + void enableSplitShadows(bool splitShadows) { mSplitShadows = splitShadows; } + /// Creates a material suitable for displaying a chunk of terrain using alpha-blending. /// @param mat Material that will be replaced by the generated material. May be empty as well, in which case /// a new material is created. @@ -48,6 +51,8 @@ namespace Terrain std::vector mBlendmapList; std::string mCompositeMap; bool mShaders; + bool mShadows; + bool mSplitShadows; }; } diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 007977b0cf..ec6a670dca 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -256,6 +256,10 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) mChunk->setVisibilityFlags(mTerrain->getVisiblityFlags()); mChunk->setCastShadows(true); mSceneNode->attachObject(mChunk); + + mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); + mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); + if (mSize == 1) { ensureLayerInfo(); @@ -338,8 +342,11 @@ void QuadTreeNode::destroyChunks() mMaterialGenerator->setCompositeMap(""); } - Ogre::TextureManager::getSingleton().remove(mCompositeMap->getName()); - mCompositeMap.setNull(); + if (!mCompositeMap.isNull()) + { + Ogre::TextureManager::getSingleton().remove(mCompositeMap->getName()); + mCompositeMap.setNull(); + } } else if (hasChildren()) for (int i=0; i<4; ++i) @@ -444,3 +451,29 @@ void QuadTreeNode::ensureCompositeMap() mTerrain->clearCompositeMapSceneManager(); } + +void QuadTreeNode::applyMaterials() +{ + if (mChunk) + { + mMaterialGenerator->enableShadows(mTerrain->getShadowsEnabled()); + mMaterialGenerator->enableSplitShadows(mTerrain->getSplitShadowsEnabled()); + if (mSize <= 1) + mChunk->setMaterial(mMaterialGenerator->generate(Ogre::MaterialPtr())); + else + mChunk->setMaterial(mMaterialGenerator->generateForCompositeMap(Ogre::MaterialPtr())); + } + if (hasChildren()) + for (int i=0; i<4; ++i) + mChildren[i]->applyMaterials(); +} + +void QuadTreeNode::setVisible(bool visible) +{ + if (!visible && mChunk) + mChunk->setVisible(false); + + if (hasChildren()) + for (int i=0; i<4; ++i) + mChildren[i]->setVisible(visible); +} diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 1b7c71b5b4..bccd26642b 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -49,6 +49,11 @@ namespace Terrain QuadTreeNode (Terrain* terrain, ChildDirection dir, float size, const Ogre::Vector2& center, QuadTreeNode* parent); ~QuadTreeNode(); + void setVisible(bool visible); + + /// Rebuild all materials + void applyMaterials(); + /// Initialize neighbours - do this after the quadtree is built void initNeighbours(); /// Initialize bounding boxes of non-leafs by merging children bounding boxes. diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 800af32824..900e536ec6 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -425,7 +425,7 @@ namespace Terrain 0---1 0---1 */ - // Build all 4 positions in terrain space, using point-sampled height + // Build all 4 positions in normalized cell space, using point-sampled height Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); diff --git a/components/terrain/terrain.cpp b/components/terrain/terrain.cpp index d06394acaa..3d65fbfc12 100644 --- a/components/terrain/terrain.cpp +++ b/components/terrain/terrain.cpp @@ -370,5 +370,23 @@ namespace Terrain return mStorage->getHeightAt(worldPos); } + void Terrain::applyMaterials(bool shadows, bool splitShadows) + { + mShadows = shadows; + mSplitShadows = splitShadows; + mRootNode->applyMaterials(); + } + + void Terrain::setVisible(bool visible) + { + mVisible = visible; + mRootNode->setVisible(visible); + } + + bool Terrain::getVisible() + { + return mVisible; + } + } diff --git a/components/terrain/terrain.hpp b/components/terrain/terrain.hpp index 4844e0056b..37ea2742a5 100644 --- a/components/terrain/terrain.hpp +++ b/components/terrain/terrain.hpp @@ -40,6 +40,8 @@ namespace Terrain bool getDistantLandEnabled() { return mDistantLand; } bool getShadersEnabled() { return mShaders; } + bool getShadowsEnabled() { return mShadows; } + bool getSplitShadowsEnabled() { return mSplitShadows; } float getHeightAt (const Ogre::Vector3& worldPos); @@ -56,14 +58,16 @@ namespace Terrain Storage* getStorage() { return mStorage; } /// Show or hide the whole terrain + /// @note this setting will be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden void setVisible(bool visible); + bool getVisible(); /// Recreate materials used by terrain chunks. This should be called whenever settings of /// the material factory are changed. (Relying on the factory to update those materials is not /// enough, since turning a feature on/off can change the number of texture units available for layer/blend /// textures, and to properly respond to this we may need to change the structure of the material, such as /// adding or removing passes. This can only be achieved by a full rebuild.) - void applyMaterials(); + void applyMaterials(bool shadows, bool splitShadows); int getVisiblityFlags() { return mVisibilityFlags; } @@ -74,6 +78,9 @@ namespace Terrain private: bool mDistantLand; bool mShaders; + bool mShadows; + bool mSplitShadows; + bool mVisible; QuadTreeNode* mRootNode; Storage* mStorage; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dd016555f8..80837a2cb0 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -348,7 +348,6 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5; #else shOutputColour(0).a = 1.f-previousAlpha; #endif - } #endif