diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 236e9c5df5..0811d87749 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -120,13 +121,11 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - //ResourceGroupManager::getSingleton ().declareResource ("GlobalMap.png", "Texture", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024); + Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024); ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - // causes light flicker in opengl when moving.. - //mRendering.getScene()->setCameraRelativeRendering(true); - // disable unsupported effects if (!Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); @@ -236,6 +235,7 @@ void RenderingManager::toggleWater() void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) { + sh::Factory::getInstance().unloadUnreferencedMaterials(); mObjects.buildStaticGeometry (*store); mDebugging->cellAdded(store); if (store->mCell->isExterior()) @@ -306,7 +306,6 @@ void RenderingManager::update (float duration, bool paused) int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; mRendering.getFader()->setFactor(1.f-(blind / 100.f)); - setAmbientMode(); // player position diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt index 6eadcc1676..6b6068ba9e 100644 --- a/extern/shiny/CMakeLists.txt +++ b/extern/shiny/CMakeLists.txt @@ -9,8 +9,6 @@ set(SHINY_LIBRARY "shiny") set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") # Sources -file(GLOB SOURCE_FILES Main/*.cpp ) - set(SOURCE_FILES Main/Factory.cpp Main/MaterialInstance.cpp @@ -57,12 +55,20 @@ file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp) add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) +set(SHINY_LIBRARIES ${SHINY_LIBRARY}) + if (SHINY_BUILD_OGRE_PLATFORM) add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) + set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY}) endif() +set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) -link_directories(${CMAKE_CURRENT_BINARY_DIR}) +if (DEFINED SHINY_BUILD_MATERIAL_EDITOR) + add_subdirectory(Editor) -set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) -set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE) + set(SHINY_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE) +endif() + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) +set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE) diff --git a/extern/shiny/Docs/Configurations.dox b/extern/shiny/Docs/Configurations.dox index affd914237..570e81d4af 100644 --- a/extern/shiny/Docs/Configurations.dox +++ b/extern/shiny/Docs/Configurations.dox @@ -21,7 +21,7 @@ } \endcode - \note You may also create configurations using sh::Factory::registerConfiguration. + \note You may also create configurations using sh::Factory::createConfiguration. The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call \code diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 40c695fd4a..780d5eece3 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -51,8 +51,6 @@ namespace sh { assert(mCurrentLanguage != Language_None); - bool removeBinaryCache = false; - if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) { std::ifstream file; @@ -86,8 +84,9 @@ namespace sh break; } - PropertySetGet newConfiguration; + Configuration newConfiguration; newConfiguration.setParent(&mGlobalSettings); + newConfiguration.setSourceFile (it->second->mFileName); std::vector props = it->second->getChildren(); for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) @@ -137,82 +136,7 @@ namespace sh } // load shader sets - { - ScriptLoader shaderSetLoader(".shaderset"); - ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); - std::map nodes = shaderSetLoader.getAllConfigScripts(); - for (std::map ::const_iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(it->second->getName() == "shader_set")) - { - std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; - break; - } - - if (!it->second->findChild("profiles_cg")) - throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); - if (!it->second->findChild("profiles_hlsl")) - throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); - if (!it->second->findChild("source")) - throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); - if (!it->second->findChild("type")) - throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); - - std::vector profiles_cg; - boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); - std::string cg_profile; - for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - cg_profile = *it2; - break; - } - } - - std::vector profiles_hlsl; - boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); - std::string hlsl_profile; - for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) - { - if (mPlatform->isProfileSupported(*it2)) - { - hlsl_profile = *it2; - break; - } - } - - std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); - std::string sourceRelative = it->second->findChild("source")->getValue(); - - ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, - sourceAbsolute, - mPlatform->getBasePath(), - it->first, - &mGlobalSettings); - - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); - mShadersLastModifiedNew[sourceRelative] = lastModified; - if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) - { - if (mShadersLastModified[sourceRelative] != lastModified) - { - // delete any outdated shaders based on this shader set - if (removeCache (it->first)) - removeBinaryCache = true; - } - } - else - { - // if we get here, this is either the first run or a new shader file was added - // in both cases we can safely delete - if (removeCache (it->first)) - removeBinaryCache = true; - } - mShaderSets.insert(std::make_pair(it->first, newSet)); - } - } + bool removeBinaryCache = reloadShaders(); // load materials { @@ -315,6 +239,8 @@ namespace sh Factory::~Factory () { + mShaderSets.clear(); + if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) { std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; @@ -367,15 +293,16 @@ namespace sh while (i>0) { --i; - m->createForConfiguration (configuration, i); - - if (mListener) + if (m->createForConfiguration (configuration, i) && mListener) mListener->materialCreated (m, configuration, i); + else + return NULL; } - m->createForConfiguration (configuration, lodIndex); - if (mListener) + if (m->createForConfiguration (configuration, lodIndex) && mListener) mListener->materialCreated (m, configuration, lodIndex); + else + return NULL; } return m; } @@ -439,6 +366,12 @@ namespace sh ShaderSet* Factory::getShaderSet (const std::string& name) { + if (mShaderSets.find(name) == mShaderSets.end()) + { + std::stringstream msg; + msg << "Shader '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } return &mShaderSets.find(name)->second; } @@ -466,6 +399,14 @@ namespace sh } } + void Factory::notifyConfigurationChanged() + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.destroyAll(); + } + } + MaterialInstance* Factory::getMaterialInstance (const std::string& name) { return findInstance(name); @@ -493,17 +434,21 @@ namespace sh return ""; } - PropertySetGet* Factory::getConfiguration (const std::string& name) + Configuration* Factory::getConfiguration (const std::string& name) { return &mConfigurations[name]; } - void Factory::registerConfiguration (const std::string& name, PropertySetGet configuration) + void Factory::createConfiguration (const std::string& name) { - mConfigurations[name] = configuration; mConfigurations[name].setParent (&mGlobalSettings); } + void Factory::destroyConfiguration(const std::string &name) + { + mConfigurations.erase(name); + } + void Factory::registerLodConfiguration (int index, PropertySetGet configuration) { mLodConfigurations[index] = configuration; @@ -571,17 +516,93 @@ namespace sh return p; } - void Factory::saveMaterials (const std::string& filename) + void Factory::saveAll () { - std::ofstream file; - file.open (filename.c_str ()); + std::map files; + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + if (it->second.getSourceFile().empty()) + continue; + if (files.find(it->second.getSourceFile()) == files.end()) + { + /// \todo check if this is actually the same file, since there can be different paths to the same file + std::ofstream* stream = new std::ofstream(); + stream->open (it->second.getSourceFile().c_str()); + + files[it->second.getSourceFile()] = stream; + } + it->second.save (*files[it->second.getSourceFile()]); + } + + for (std::map::iterator it = files.begin(); it != files.end(); ++it) + { + delete it->second; + } + files.clear(); + + for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) + { + if (it->second.getSourceFile().empty()) + continue; + if (files.find(it->second.getSourceFile()) == files.end()) + { + /// \todo check if this is actually the same file, since there can be different paths to the same file + std::ofstream* stream = new std::ofstream(); + stream->open (it->second.getSourceFile().c_str()); + + files[it->second.getSourceFile()] = stream; + } + it->second.save (it->first, *files[it->second.getSourceFile()]); + } + for (std::map::iterator it = files.begin(); it != files.end(); ++it) + { + delete it->second; + } + } + + void Factory::listMaterials(std::vector &out) + { for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) { - it->second.save(file); + out.push_back(it->first); } + } + + void Factory::listGlobalSettings(std::map &out) + { + const PropertyMap& properties = mGlobalSettings.listProperties(); - file.close(); + for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) + { + out[it->first] = retrieveValue(mGlobalSettings.getProperty(it->first), NULL).get(); + } + } + + void Factory::listConfigurationSettings(const std::string& name, std::map &out) + { + const PropertyMap& properties = mConfigurations[name].listProperties(); + + for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) + { + out[it->first] = retrieveValue(mConfigurations[name].getProperty(it->first), NULL).get(); + } + } + + void Factory::listConfigurationNames(std::vector &out) + { + for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it) + { + out.push_back(it->first); + } + } + + void Factory::listShaderSets(std::vector &out) + { + for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it) + { + out.push_back(it->first); + } } void Factory::_ensureMaterial(const std::string& name, const std::string& configuration) @@ -630,4 +651,146 @@ namespace sh } return ret; } + + bool Factory::reloadShaders() + { + mShaderSets.clear(); + notifyConfigurationChanged(); + + bool removeBinaryCache = false; + ScriptLoader shaderSetLoader(".shaderset"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "shader_set")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; + break; + } + + if (!it->second->findChild("profiles_cg")) + throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); + if (!it->second->findChild("profiles_hlsl")) + throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); + if (!it->second->findChild("source")) + throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); + if (!it->second->findChild("type")) + throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); + + std::vector profiles_cg; + boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); + std::string cg_profile; + for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + cg_profile = *it2; + break; + } + } + + std::vector profiles_hlsl; + boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); + std::string hlsl_profile; + for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + hlsl_profile = *it2; + break; + } + } + + std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceRelative = it->second->findChild("source")->getValue(); + + ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, + sourceAbsolute, + mPlatform->getBasePath(), + it->first, + &mGlobalSettings); + + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); + mShadersLastModifiedNew[sourceRelative] = lastModified; + if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) + { + if (mShadersLastModified[sourceRelative] != lastModified) + { + // delete any outdated shaders based on this shader set + if (removeCache (it->first)) + removeBinaryCache = true; + mShadersLastModified[sourceRelative] = lastModified; + } + } + else + { + // if we get here, this is either the first run or a new shader file was added + // in both cases we can safely delete + if (removeCache (it->first)) + removeBinaryCache = true; + mShadersLastModified[sourceRelative] = lastModified; + } + mShaderSets.insert(std::make_pair(it->first, newSet)); + } + + return removeBinaryCache; + } + + void Factory::doMonitorShaderFiles() + { + bool reload=false; + ScriptLoader shaderSetLoader(".shaderset"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + + std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceRelative = it->second->findChild("source")->getValue(); + + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); + if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) + { + if (mShadersLastModified[sourceRelative] != lastModified) + { + reload=true; + break; + } + } + } + if (reload) + reloadShaders(); + } + + void Factory::logError(const std::string &msg) + { + mErrorLog << msg << '\n'; + } + + std::string Factory::getErrorLog() + { + std::string errors = mErrorLog.str(); + mErrorLog.str(""); + return errors; + } + + void Factory::unloadUnreferencedMaterials() + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + if (it->second.getMaterial()->isUnreferenced()) + it->second.destroyAll(); + } + } + + void Configuration::save(const std::string& name, std::ofstream &stream) + { + stream << "configuration " << name << '\n'; + stream << "{\n"; + PropertySetGet::save(stream, "\t"); + stream << "}\n"; + } } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 846860b89a..97984609ea 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "MaterialInstance.hpp" #include "ShaderSet.hpp" @@ -12,9 +13,21 @@ namespace sh { class Platform; + class Configuration : public PropertySetGet + { + public: + void setSourceFile (const std::string& file) { mSourceFile = file ; } + std::string getSourceFile () { return mSourceFile; } + + void save(const std::string& name, std::ofstream &stream); + + private: + std::string mSourceFile; + }; + typedef std::map MaterialMap; typedef std::map ShaderSetMap; - typedef std::map ConfigurationMap; + typedef std::map ConfigurationMap; typedef std::map LodConfigurationMap; typedef std::map LastModifiedMap; @@ -81,8 +94,8 @@ namespace sh /// Get a MaterialInstance by name MaterialInstance* getMaterialInstance (const std::string& name); - /// Register a configuration, which can then be used by switching the active material scheme - void registerConfiguration (const std::string& name, PropertySetGet configuration); + /// Create a configuration, which can then be altered by using Factory::getConfiguration + void createConfiguration (const std::string& name); /// Register a lod configuration, which can then be used by setting up lod distance values for the material \n /// 0 refers to highest lod, so use 1 or higher as index parameter @@ -125,8 +138,48 @@ namespace sh /// \note The default is off (no cache reading) void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } - /// Saves all the materials that were initially loaded from the file with this name - void saveMaterials (const std::string& filename); + /// Lists all materials currently registered with the factory. Whether they are + /// loaded or not does not matter. + void listMaterials (std::vector& out); + + /// Lists current name & value of all global settings. + void listGlobalSettings (std::map& out); + + /// Lists configuration names. + void listConfigurationNames (std::vector& out); + + /// Lists current name & value of settings for a given configuration. + void listConfigurationSettings (const std::string& name, std::map& out); + + /// Lists shader sets. + void listShaderSets (std::vector& out); + + /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache + /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. + bool reloadShaders(); + + /// Calls reloadShaders() if shader files have been modified since the last reload. + /// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache + /// through the Ogre API. Luckily, this is already fixed in Ogre 1.9. + void doMonitorShaderFiles(); + + /// Unloads all materials that are currently not referenced. This will not unload the textures themselves, + /// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n + /// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period + /// of time should work just fine too. + void unloadUnreferencedMaterials(); + + void destroyConfiguration (const std::string& name); + + void notifyConfigurationChanged(); + + /// Saves all materials and configurations, by default to the file they were loaded from. + /// If you wish to save them elsewhere, use setSourceFile first. + void saveAll (); + + /// Returns the error log as a string, then clears it. + /// Note: Errors are also written to the standard error output, or thrown if they are fatal. + std::string getErrorLog (); static Factory& getInstance(); ///< Return instance of this class. @@ -137,11 +190,13 @@ namespace sh /// You will probably never have to use this. void _ensureMaterial(const std::string& name, const std::string& configuration); + + Configuration* getConfiguration (const std::string& name); + private: MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); ShaderSet* getShaderSet (const std::string& name); - PropertySetGet* getConfiguration (const std::string& name); Platform* getPlatform (); PropertySetGet* getCurrentGlobalSettings(); @@ -163,6 +218,8 @@ namespace sh std::map mTextureAliasInstances; + void logError (const std::string& msg); + friend class Platform; friend class MaterialInstance; friend class ShaderInstance; @@ -179,6 +236,7 @@ namespace sh bool mWriteMicrocodeCache; bool mReadSourceCache; bool mWriteSourceCache; + std::stringstream mErrorLog; MaterialMap mMaterials; ShaderSetMap mShaderSets; diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp index 0f8bcdda78..b8032d681e 100644 --- a/extern/shiny/Main/MaterialInstance.cpp +++ b/extern/shiny/Main/MaterialInstance.cpp @@ -1,6 +1,7 @@ #include "MaterialInstance.hpp" #include +#include #include "Factory.hpp" #include "ShaderSet.hpp" @@ -12,6 +13,7 @@ namespace sh , mShadersEnabled(true) , mFactory(f) , mListener(NULL) + , mFailedToCreate(false) { } @@ -46,6 +48,7 @@ namespace sh return; mMaterial->removeAll(); mTexUnits.clear(); + mFailedToCreate = false; } void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) @@ -54,118 +57,136 @@ namespace sh destroyAll(); // trigger updates } - void MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) + bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) { - bool res = mMaterial->createConfiguration(configuration, lodIndex); - if (!res) - return; // listener was false positive - - if (mListener) - mListener->requestedConfiguration (this, configuration); - - mFactory->setActiveConfiguration (configuration); - mFactory->setActiveLodLevel (lodIndex); - - bool allowFixedFunction = true; - if (!mShadersEnabled && hasProperty("allow_fixed_function")) - { - allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); - } + if (mFailedToCreate) + return false; + try{ + mMaterial->ensureLoaded(); + bool res = mMaterial->createConfiguration(configuration, lodIndex); + if (!res) + return false; // listener was false positive + + if (mListener) + mListener->requestedConfiguration (this, configuration); + + mFactory->setActiveConfiguration (configuration); + mFactory->setActiveLodLevel (lodIndex); + + bool allowFixedFunction = true; + if (!mShadersEnabled && hasProperty("allow_fixed_function")) + { + allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); + } - bool useShaders = mShadersEnabled || !allowFixedFunction; + bool useShaders = mShadersEnabled || !allowFixedFunction; - // get passes of the top-most parent - PassVector passes = getPasses(); - if (passes.size() == 0) - throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); + // get passes of the top-most parent + PassVector* passes = getParentPasses(); + if (passes->empty()) + throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); - for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it) - { - boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); - it->copyAll (pass.get(), this); + for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it) + { + boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); + it->copyAll (pass.get(), this); - // texture samplers used in the shaders - std::vector usedTextureSamplersVertex; - std::vector usedTextureSamplersFragment; + // texture samplers used in the shaders + std::vector usedTextureSamplersVertex; + std::vector usedTextureSamplersFragment; - PropertySetGet* context = this; + PropertySetGet* context = this; - // create or retrieve shaders - bool hasVertex = it->hasProperty("vertex_program"); - bool hasFragment = it->hasProperty("fragment_program"); - if (useShaders) - { - it->setContext(context); - it->mShaderProperties.setContext(context); - if (hasVertex) + // create or retrieve shaders + bool hasVertex = it->hasProperty("vertex_program") + && !retrieveValue(it->getProperty("vertex_program"), context).get().empty(); + bool hasFragment = it->hasProperty("fragment_program") + && !retrieveValue(it->getProperty("fragment_program"), context).get().empty(); + if (useShaders) { - ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); - ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); - if (v) + it->setContext(context); + it->mShaderProperties.setContext(context); + if (hasVertex) { - pass->assignProgram (GPT_Vertex, v->getName()); - v->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = v->getSharedParameters (); - for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); + ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); + if (v) { - pass->addSharedParameter (GPT_Vertex, *it); - } + pass->assignProgram (GPT_Vertex, v->getName()); + v->setUniformParameters (pass, &it->mShaderProperties); + + std::vector sharedParams = v->getSharedParameters (); + for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) + { + pass->addSharedParameter (GPT_Vertex, *it2); + } - std::vector vector = v->getUsedSamplers (); - usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); + std::vector vector = v->getUsedSamplers (); + usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); + } } - } - if (hasFragment) - { - ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); - ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); - if (f) + if (hasFragment) { - pass->assignProgram (GPT_Fragment, f->getName()); - f->setUniformParameters (pass, &it->mShaderProperties); - - std::vector sharedParams = f->getSharedParameters (); - for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); + ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); + if (f) { - pass->addSharedParameter (GPT_Fragment, *it); - } + pass->assignProgram (GPT_Fragment, f->getName()); + f->setUniformParameters (pass, &it->mShaderProperties); - std::vector vector = f->getUsedSamplers (); - usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); + std::vector sharedParams = f->getSharedParameters (); + for (std::vector::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) + { + pass->addSharedParameter (GPT_Fragment, *it2); + } + + std::vector vector = f->getUsedSamplers (); + usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); + } } } - } - // create texture units - std::vector texUnits = it->getTexUnits(); - int i=0; - for (std::vector::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt ) - { - // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled - bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); - bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); - if ( (foundVertex || foundFragment) - || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) + // create texture units + std::vector* texUnits = &it->mTexUnits; + int i=0; + for (std::vector::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt ) { - boost::shared_ptr texUnit = pass->createTextureUnitState (); - texIt->copyAll (texUnit.get(), context); + // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled + bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); + bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); + if ( (foundVertex || foundFragment) + || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) + { + boost::shared_ptr texUnit = pass->createTextureUnitState (texIt->getName()); + texIt->copyAll (texUnit.get(), context); - mTexUnits.push_back(texUnit); + mTexUnits.push_back(texUnit); - // set texture unit indices (required by GLSL) - if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) - { - pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); + // set texture unit indices (required by GLSL) + if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) + { + pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); - ++i; + ++i; + } } } } - } - if (mListener) - mListener->createdConfiguration (this, configuration); + if (mListener) + mListener->createdConfiguration (this, configuration); + return true; + + } catch (std::runtime_error& e) + { + destroyAll(); + mFailedToCreate = true; + std::stringstream msg; + msg << "Error while creating material " << mName << ": " << e.what(); + std::cerr << msg.str() << std::endl; + mFactory->logError(msg.str()); + return false; + } } Material* MaterialInstance::getMaterial () @@ -180,12 +201,23 @@ namespace sh return &mPasses.back(); } - PassVector MaterialInstance::getPasses() + void MaterialInstance::deletePass(unsigned int index) + { + assert(mPasses.size() > index); + mPasses.erase(mPasses.begin()+index); + } + + PassVector* MaterialInstance::getParentPasses() { if (mParent) - return static_cast(mParent)->getPasses(); + return static_cast(mParent)->getParentPasses(); else - return mPasses; + return &mPasses; + } + + PassVector* MaterialInstance::getPasses() + { + return &mPasses; } void MaterialInstance::setShadersEnabled (bool enabled) @@ -206,7 +238,7 @@ namespace sh if (mParent) { - stream << "\t" << static_cast(mParent)->getName() << "\n"; + stream << "\t" << "parent " << static_cast(mParent)->getName() << "\n"; } const PropertyMap& properties = listProperties (); @@ -215,6 +247,14 @@ namespace sh stream << "\t" << it->first << " " << retrieveValue(getProperty(it->first), NULL).get() << "\n"; } + for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it) + { + stream << "\tpass" << '\n'; + stream << "\t{" << '\n'; + it->save(stream); + stream << "\t}" << '\n'; + } + stream << "}\n"; } } diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp index 36ba37ddba..72c78c7b7c 100644 --- a/extern/shiny/Main/MaterialInstance.hpp +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -41,8 +41,12 @@ namespace sh MaterialInstance (const std::string& name, Factory* f); virtual ~MaterialInstance (); + PassVector* getParentPasses(); ///< gets the passes of the top-most parent + + PassVector* getPasses(); ///< get our passes (for derived materials, none) + MaterialInstancePass* createPass (); - PassVector getPasses(); ///< gets the passes of the top-most parent + void deletePass (unsigned int index); /// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet! /// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event! @@ -55,25 +59,25 @@ namespace sh virtual void setProperty (const std::string& name, PropertyValuePtr value); + void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } + + std::string getSourceFile() { return mSourceFile; } + ///< get the name of the file this material was read from, or empty if it was created dynamically by code + private: void setParentInstance (const std::string& name); std::string getParentInstance (); void create (Platform* platform); - void createForConfiguration (const std::string& configuration, unsigned short lodIndex); + bool createForConfiguration (const std::string& configuration, unsigned short lodIndex); void destroyAll (); void setShadersEnabled (bool enabled); - void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } - - std::string getSourceFile() { return mSourceFile; } - ///< get the name of the file this material was read from, or empty if it was created dynamically by code - void save (std::ofstream& stream); - ///< this will only save the properties, not the passes and texture units, and as such - /// is only intended to be used for derived materials + + bool mFailedToCreate; friend class Factory; diff --git a/extern/shiny/Main/MaterialInstancePass.cpp b/extern/shiny/Main/MaterialInstancePass.cpp index b14476f4e7..a628cd64c7 100644 --- a/extern/shiny/Main/MaterialInstancePass.cpp +++ b/extern/shiny/Main/MaterialInstancePass.cpp @@ -1,5 +1,7 @@ #include "MaterialInstancePass.hpp" +#include + namespace sh { @@ -9,8 +11,25 @@ namespace sh return &mTexUnits.back(); } - std::vector MaterialInstancePass::getTexUnits () + void MaterialInstancePass::save(std::ofstream &stream) { - return mTexUnits; + if (mShaderProperties.listProperties().size()) + { + stream << "\t\t" << "shader_properties" << '\n'; + stream << "\t\t{\n"; + mShaderProperties.save(stream, "\t\t\t"); + stream << "\t\t}\n"; + } + + PropertySetGet::save(stream, "\t\t"); + + for (std::vector ::iterator it = mTexUnits.begin(); + it != mTexUnits.end(); ++it) + { + stream << "\t\ttexture_unit " << it->getName() << '\n'; + stream << "\t\t{\n"; + it->save(stream, "\t\t\t"); + stream << "\t\t}\n"; + } } } diff --git a/extern/shiny/Main/MaterialInstancePass.hpp b/extern/shiny/Main/MaterialInstancePass.hpp index 7d7330f705..3d83d8fa35 100644 --- a/extern/shiny/Main/MaterialInstancePass.hpp +++ b/extern/shiny/Main/MaterialInstancePass.hpp @@ -18,10 +18,10 @@ namespace sh public: MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); + void save (std::ofstream& stream); + PropertySetGet mShaderProperties; - std::vector getTexUnits (); - private: std::vector mTexUnits; }; } diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp index ae9f54fd2d..5ca400fd49 100644 --- a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp +++ b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp @@ -18,6 +18,7 @@ namespace sh public: MaterialInstanceTextureUnit (const std::string& name); std::string getName() const; + void setName (const std::string& name) { mName = name; } private: std::string mName; }; diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp index 94b4f872ae..3eb7f4ad34 100644 --- a/extern/shiny/Main/Platform.cpp +++ b/extern/shiny/Main/Platform.cpp @@ -9,7 +9,7 @@ namespace sh Platform::Platform (const std::string& basePath) : mBasePath(basePath) , mCacheFolder("./") - , mShaderCachingEnabled(false) + , mFactory(NULL) { } @@ -57,11 +57,6 @@ namespace sh mCacheFolder = folder; } - void Platform::setShaderCachingEnabled (bool enabled) - { - mShaderCachingEnabled = enabled; - } - std::string Platform::getCacheFolder() const { return mCacheFolder; diff --git a/extern/shiny/Main/Platform.hpp b/extern/shiny/Main/Platform.hpp index 1b095e9576..24afea03ba 100644 --- a/extern/shiny/Main/Platform.hpp +++ b/extern/shiny/Main/Platform.hpp @@ -24,6 +24,7 @@ namespace sh class GpuProgram { public: + virtual ~GpuProgram() {} virtual bool getSupported () = 0; ///< @return true if the compilation was successful /// @param name name of the uniform in the shader @@ -35,8 +36,7 @@ namespace sh class TextureUnitState : public PropertySet { public: - virtual ~TextureUnitState(); - + virtual ~TextureUnitState(); virtual void setTextureName (const std::string& textureName) = 0; protected: @@ -46,7 +46,7 @@ namespace sh class Pass : public PropertySet { public: - virtual boost::shared_ptr createTextureUnitState () = 0; + virtual boost::shared_ptr createTextureUnitState (const std::string& name) = 0; virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; /// @param type gpu program type @@ -68,6 +68,9 @@ namespace sh virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists virtual void removeAll () = 0; ///< remove all configurations + virtual bool isUnreferenced() = 0; + virtual void ensureLoaded() = 0; + virtual void setLodLevels (const std::string& lodLevels) = 0; virtual void setShadowCasterMaterial (const std::string& name) = 0; @@ -79,8 +82,6 @@ namespace sh Platform (const std::string& basePath); virtual ~Platform (); - void setShaderCachingEnabled (bool enabled); - /// set the folder to use for shader caching void setCacheFolder (const std::string& folder); @@ -93,6 +94,8 @@ namespace sh const std::string& name, const std::string& profile, const std::string& source, Language lang) = 0; + virtual void destroyGpuProgram (const std::string& name) = 0; + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0; virtual bool isProfileSupported (const std::string& profile) = 0; @@ -105,6 +108,7 @@ namespace sh friend class Factory; friend class MaterialInstance; friend class ShaderInstance; + friend class ShaderSet; protected: /** @@ -131,9 +135,6 @@ namespace sh std::string mCacheFolder; Factory* mFactory; - protected: - bool mShaderCachingEnabled; - private: void setFactory (Factory* factory); diff --git a/extern/shiny/Main/PropertyBase.cpp b/extern/shiny/Main/PropertyBase.cpp index 0c39e5c1e7..8592712fa9 100644 --- a/extern/shiny/Main/PropertyBase.cpp +++ b/extern/shiny/Main/PropertyBase.cpp @@ -6,6 +6,8 @@ #include #include +#include + namespace sh { @@ -39,8 +41,9 @@ namespace sh mValue = false; else { - std::cerr << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue" << std::endl; - mValue = false; + std::stringstream msg; + msg << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue"; + throw std::runtime_error(msg.str()); } } @@ -183,12 +186,16 @@ namespace sh void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) { if (!setPropertyOverride (name, value, context)) - std::cerr << "sh::PropertySet: Warning: No match for property with name '" << name << "'" << std::endl; + { + std::stringstream msg; + msg << "sh::PropertySet: Warning: No match for property with name '" << name << "'"; + throw std::runtime_error(msg.str()); + } } bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) { - // if we got here, none of the sub-classes was able to make use of the property + // if we got here, none of the sub-classes were able to make use of the property return false; } @@ -226,6 +233,11 @@ namespace sh mProperties [name] = value; } + void PropertySetGet::deleteProperty(const std::string &name) + { + mProperties.erase(name); + } + PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) { bool found = (mProperties.find(name) != mProperties.end()); @@ -241,7 +253,7 @@ namespace sh return mProperties[name]; } - bool PropertySetGet::hasProperty (const std::string& name) + bool PropertySetGet::hasProperty (const std::string& name) const { bool found = (mProperties.find(name) != mProperties.end()); @@ -256,13 +268,35 @@ namespace sh return true; } - void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context) + void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context, bool copyParent) { - if (mParent) + if (mParent && copyParent) mParent->copyAll (target, context); for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) { target->setProperty(it->first, it->second, context); } } + + void PropertySetGet::copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent) + { + if (mParent && copyParent) + mParent->copyAll (target, context); + for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + std::string val = retrieveValue(it->second, this).get(); + target->setProperty(it->first, sh::makeProperty(new sh::StringValue(val))); + } + } + + void PropertySetGet::save(std::ofstream &stream, const std::string& indentation) + { + for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + if (typeid( *(it->second) ) == typeid(LinkedValue)) + stream << indentation << it->first << " " << "$" + static_cast(&*(it->second))->_getStringValue() << '\n'; + else + stream << indentation << it->first << " " << retrieveValue(it->second, this).get() << '\n'; + } + } } diff --git a/extern/shiny/Main/PropertyBase.hpp b/extern/shiny/Main/PropertyBase.hpp index 240acce81b..13809443e2 100644 --- a/extern/shiny/Main/PropertyBase.hpp +++ b/extern/shiny/Main/PropertyBase.hpp @@ -133,6 +133,7 @@ namespace sh class PropertySet { public: + virtual ~PropertySet() {} void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); protected: @@ -151,18 +152,26 @@ namespace sh virtual ~PropertySetGet() {} - void copyAll (PropertySet* target, PropertySetGet* context); ///< call setProperty for each property/value pair stored in \a this + void save (std::ofstream& stream, const std::string& indentation); + + void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true); + ///< call setProperty for each property/value pair stored in \a this + void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true); + ///< call setProperty for each property/value pair stored in \a this void setParent (PropertySetGet* parent); + PropertySetGet* getParent () { return mParent; } void setContext (PropertySetGet* context); PropertySetGet* getContext(); virtual void setProperty (const std::string& name, PropertyValuePtr value); PropertyValuePtr& getProperty (const std::string& name); + void deleteProperty (const std::string& name); + const PropertyMap& listProperties() { return mProperties; } - bool hasProperty (const std::string& name); + bool hasProperty (const std::string& name) const; private: PropertyMap mProperties; @@ -225,7 +234,7 @@ namespace sh template /// Create a property of any type - /// Example: sh::makeProperty\ (new sh::Vector4(1, 1, 1, 1)) + /// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1)) inline PropertyValuePtr makeProperty (T* p) { return PropertyValuePtr ( static_cast(p) ); diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp index 93d728b023..bafe07fc8e 100644 --- a/extern/shiny/Main/ScriptLoader.cpp +++ b/extern/shiny/Main/ScriptLoader.cpp @@ -24,6 +24,10 @@ namespace sh } ScriptLoader::ScriptLoader(const std::string& fileEnding) + : mLoadOrder(0) + , mToken(TOKEN_NewLine) + , mLastToken(TOKEN_NewLine) + { mFileEnding = fileEnding; } @@ -36,7 +40,7 @@ namespace sh void ScriptLoader::clearScriptList() { std::map ::iterator i; - for (i = m_scriptList.begin(); i != m_scriptList.end(); i++) + for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i) { delete i->second; } @@ -293,7 +297,7 @@ namespace sh { //Delete all children std::vector::iterator i; - for (i = mChildren.begin(); i != mChildren.end(); i++) + for (i = mChildren.begin(); i != mChildren.end(); ++i) { ScriptNode *node = *i; node->mRemoveSelf = false; @@ -323,15 +327,24 @@ namespace sh ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) { - int indx, prevC, nextC; + int indx; int childCount = (int)mChildren.size(); if (mLastChildFound != -1) { //If possible, try checking the nodes neighboring the last successful search //(often nodes searched for in sequence, so this will boost search speeds). - prevC = mLastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1; - nextC = mLastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1; + int prevC = mLastChildFound-1; + if (prevC < 0) + prevC = 0; + else if (prevC >= childCount) + prevC = childCount-1; + int nextC = mLastChildFound+1; + if (nextC < 0) + nextC = 0; + else if (nextC >= childCount) + nextC = childCount-1; + for (indx = prevC; indx <= nextC; ++indx) { ScriptNode *node = mChildren[indx]; diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 628e0acee7..8fb530d394 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -37,6 +37,14 @@ namespace sh parse(); } + ShaderSet::~ShaderSet() + { + for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it) + { + sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName()); + } + } + void ShaderSet::parse() { std::string currentToken; diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index b21278ac99..988c6769fa 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -21,6 +21,7 @@ namespace sh public: ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, const std::string& name, PropertySetGet* globalSettingsPtr); + ~ShaderSet(); /// Retrieve a shader instance for the given properties. \n /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp index 4a550b8bff..77091fe03d 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp @@ -15,6 +15,7 @@ namespace sh OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) : Material() { + mName = name; assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); mMaterial->removeAllTechniques(); @@ -22,9 +23,22 @@ namespace sh mMaterial->compile(); } + void OgreMaterial::ensureLoaded() + { + if (mMaterial.isNull()) + mMaterial = Ogre::MaterialManager::getSingleton().getByName(mName); + } + + bool OgreMaterial::isUnreferenced() + { + // Resource system internals hold 3 shared pointers, we hold one, so usecount of 4 means unused + return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1); + } + OgreMaterial::~OgreMaterial() { - Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); + if (!mMaterial.isNull()) + Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); } boost::shared_ptr OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) @@ -34,6 +48,8 @@ namespace sh void OgreMaterial::removeAll () { + if (mMaterial.isNull()) + return; mMaterial->removeAllTechniques(); mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); mMaterial->compile(); diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp index bec23f0b6f..bfa6e2c6f8 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp @@ -18,6 +18,9 @@ namespace sh virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex); virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); + virtual bool isUnreferenced(); + virtual void ensureLoaded(); + virtual void removeAll (); Ogre::MaterialPtr getOgreMaterial(); @@ -30,6 +33,7 @@ namespace sh private: Ogre::MaterialPtr mMaterial; + std::string mName; std::string mShadowCasterMaterial; }; diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 3ed48b96f8..3a25c5c740 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -20,9 +20,9 @@ namespace sh mPass = t->createPass(); } - boost::shared_ptr OgrePass::createTextureUnitState () + boost::shared_ptr OgrePass::createTextureUnitState (const std::string& name) { - return boost::shared_ptr (new OgreTextureUnitState (this)); + return boost::shared_ptr (new OgreTextureUnitState (this, name)); } void OgrePass::assignProgram (GpuProgramType type, const std::string& name) @@ -105,7 +105,17 @@ namespace sh else if (type == GPT_Fragment) params = mPass->getFragmentProgramParameters(); - params->addSharedParameters (name); + try + { + params->addSharedParameters (name); + } + catch (Ogre::Exception& e) + { + std::stringstream msg; + msg << "Could not create a shared parameter instance for '" + << name << "'. Make sure this shared parameter has a value set (via Factory::setSharedParameter)!"; + throw std::runtime_error(msg.str()); + } } void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index) diff --git a/extern/shiny/Platforms/Ogre/OgrePass.hpp b/extern/shiny/Platforms/Ogre/OgrePass.hpp index da67a1a2a5..e7cfd4e337 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.hpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.hpp @@ -14,7 +14,7 @@ namespace sh public: OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); - virtual boost::shared_ptr createTextureUnitState (); + virtual boost::shared_ptr createTextureUnitState (const std::string& name); virtual void assignProgram (GpuProgramType type, const std::string& name); Ogre::Pass* getOgrePass(); diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp index 357949402f..2749c22ce6 100644 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "OgreMaterial.hpp" @@ -76,6 +77,11 @@ namespace sh return boost::shared_ptr (material); } + void OgrePlatform::destroyGpuProgram(const std::string &name) + { + Ogre::HighLevelGpuProgramManager::getSingleton().remove(name); + } + boost::shared_ptr OgrePlatform::createGpuProgram ( GpuProgramType type, const std::string& compileArguments, @@ -122,6 +128,7 @@ namespace sh if (mSharedParameters.find(name) == mSharedParameters.end()) { params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); + Ogre::GpuConstantType type; if (typeid(*value) == typeid(Vector4)) type = Ogre::GCT_FLOAT4; diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp index d115c46bb4..d3a1a83608 100644 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp @@ -47,6 +47,8 @@ namespace sh const std::string& name, const std::string& profile, const std::string& source, Language lang); + virtual void destroyGpuProgram (const std::string& name); + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); friend class ShaderInstance; diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp index 0938cf667d..54dda3523f 100644 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp @@ -6,10 +6,11 @@ namespace sh { - OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent) + OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name) : TextureUnitState() { mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); + mTextureUnitState->setName(name); } bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp index d36f4b945a..0f1914f62e 100644 --- a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp @@ -12,7 +12,7 @@ namespace sh class OgreTextureUnitState : public TextureUnitState { public: - OgreTextureUnitState (OgrePass* parent); + OgreTextureUnitState (OgrePass* parent, const std::string& name); virtual void setTextureName (const std::string& textureName);