Sync extern/shiny, set memory budgets for texture and mesh managers (however this has no effect yet and depends on changes in Ogre being made)

actorid
scrawl 12 years ago
parent 28ef4d97da
commit 75dcf52552

@ -14,6 +14,7 @@
#include <OgreCompositionPass.h> #include <OgreCompositionPass.h>
#include <OgreHardwarePixelBuffer.h> #include <OgreHardwarePixelBuffer.h>
#include <OgreControllerManager.h> #include <OgreControllerManager.h>
#include <OgreMeshManager.h>
#include <extern/shiny/Main/Factory.hpp> #include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp> #include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
@ -120,13 +121,11 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); 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(); ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
// causes light flicker in opengl when moving..
//mRendering.getScene()->setCameraRelativeRendering(true);
// disable unsupported effects // disable unsupported effects
if (!Settings::Manager::getBool("shaders", "Objects")) if (!Settings::Manager::getBool("shaders", "Objects"))
Settings::Manager::setBool("enabled", "Shadows", false); Settings::Manager::setBool("enabled", "Shadows", false);
@ -236,6 +235,7 @@ void RenderingManager::toggleWater()
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
{ {
sh::Factory::getInstance().unloadUnreferencedMaterials();
mObjects.buildStaticGeometry (*store); mObjects.buildStaticGeometry (*store);
mDebugging->cellAdded(store); mDebugging->cellAdded(store);
if (store->mCell->isExterior()) 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; int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude;
mRendering.getFader()->setFactor(1.f-(blind / 100.f)); mRendering.getFader()->setFactor(1.f-(blind / 100.f));
setAmbientMode(); setAmbientMode();
// player position // player position

@ -9,8 +9,6 @@ set(SHINY_LIBRARY "shiny")
set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform")
# Sources # Sources
file(GLOB SOURCE_FILES Main/*.cpp )
set(SOURCE_FILES set(SOURCE_FILES
Main/Factory.cpp Main/Factory.cpp
Main/MaterialInstance.cpp Main/MaterialInstance.cpp
@ -57,12 +55,20 @@ file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp)
add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES})
set(SHINY_LIBRARIES ${SHINY_LIBRARY})
if (SHINY_BUILD_OGRE_PLATFORM) if (SHINY_BUILD_OGRE_PLATFORM)
add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES})
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY})
endif() 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_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE)
set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE) endif()
link_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE)

@ -21,7 +21,7 @@
} }
\endcode \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 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 \code

@ -51,8 +51,6 @@ namespace sh
{ {
assert(mCurrentLanguage != Language_None); assert(mCurrentLanguage != Language_None);
bool removeBinaryCache = false;
if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
{ {
std::ifstream file; std::ifstream file;
@ -86,8 +84,9 @@ namespace sh
break; break;
} }
PropertySetGet newConfiguration; Configuration newConfiguration;
newConfiguration.setParent(&mGlobalSettings); newConfiguration.setParent(&mGlobalSettings);
newConfiguration.setSourceFile (it->second->mFileName);
std::vector<ScriptNode*> props = it->second->getChildren(); std::vector<ScriptNode*> props = it->second->getChildren();
for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
@ -137,82 +136,7 @@ namespace sh
} }
// load shader sets // load shader sets
{ bool removeBinaryCache = reloadShaders();
ScriptLoader shaderSetLoader(".shaderset");
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::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<std::string> profiles_cg;
boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
std::string cg_profile;
for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
{
if (mPlatform->isProfileSupported(*it2))
{
cg_profile = *it2;
break;
}
}
std::vector<std::string> profiles_hlsl;
boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
std::string hlsl_profile;
for (std::vector<std::string>::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));
}
}
// load materials // load materials
{ {
@ -315,6 +239,8 @@ namespace sh
Factory::~Factory () Factory::~Factory ()
{ {
mShaderSets.clear();
if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache)
{ {
std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
@ -367,15 +293,16 @@ namespace sh
while (i>0) while (i>0)
{ {
--i; --i;
m->createForConfiguration (configuration, i); if (m->createForConfiguration (configuration, i) && mListener)
if (mListener)
mListener->materialCreated (m, configuration, i); mListener->materialCreated (m, configuration, i);
else
return NULL;
} }
m->createForConfiguration (configuration, lodIndex); if (m->createForConfiguration (configuration, lodIndex) && mListener)
if (mListener)
mListener->materialCreated (m, configuration, lodIndex); mListener->materialCreated (m, configuration, lodIndex);
else
return NULL;
} }
return m; return m;
} }
@ -439,6 +366,12 @@ namespace sh
ShaderSet* Factory::getShaderSet (const std::string& name) 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; 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) MaterialInstance* Factory::getMaterialInstance (const std::string& name)
{ {
return findInstance(name); return findInstance(name);
@ -493,17 +434,21 @@ namespace sh
return ""; return "";
} }
PropertySetGet* Factory::getConfiguration (const std::string& name) Configuration* Factory::getConfiguration (const std::string& name)
{ {
return &mConfigurations[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); mConfigurations[name].setParent (&mGlobalSettings);
} }
void Factory::destroyConfiguration(const std::string &name)
{
mConfigurations.erase(name);
}
void Factory::registerLodConfiguration (int index, PropertySetGet configuration) void Factory::registerLodConfiguration (int index, PropertySetGet configuration)
{ {
mLodConfigurations[index] = configuration; mLodConfigurations[index] = configuration;
@ -571,17 +516,93 @@ namespace sh
return p; return p;
} }
void Factory::saveMaterials (const std::string& filename) void Factory::saveAll ()
{ {
std::ofstream file; std::map<std::string, std::ofstream*> files;
file.open (filename.c_str ()); 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<std::string, std::ofstream*>::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<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
{
delete it->second;
}
}
void Factory::listMaterials(std::vector<std::string> &out)
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{ {
it->second.save(file); out.push_back(it->first);
} }
}
void Factory::listGlobalSettings(std::map<std::string, std::string> &out)
{
const PropertyMap& properties = mGlobalSettings.listProperties();
file.close(); for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
{
out[it->first] = retrieveValue<StringValue>(mGlobalSettings.getProperty(it->first), NULL).get();
}
}
void Factory::listConfigurationSettings(const std::string& name, std::map<std::string, std::string> &out)
{
const PropertyMap& properties = mConfigurations[name].listProperties();
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
{
out[it->first] = retrieveValue<StringValue>(mConfigurations[name].getProperty(it->first), NULL).get();
}
}
void Factory::listConfigurationNames(std::vector<std::string> &out)
{
for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
{
out.push_back(it->first);
}
}
void Factory::listShaderSets(std::vector<std::string> &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) void Factory::_ensureMaterial(const std::string& name, const std::string& configuration)
@ -630,4 +651,146 @@ namespace sh
} }
return ret; return ret;
} }
bool Factory::reloadShaders()
{
mShaderSets.clear();
notifyConfigurationChanged();
bool removeBinaryCache = false;
ScriptLoader shaderSetLoader(".shaderset");
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::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<std::string> profiles_cg;
boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
std::string cg_profile;
for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
{
if (mPlatform->isProfileSupported(*it2))
{
cg_profile = *it2;
break;
}
}
std::vector<std::string> profiles_hlsl;
boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
std::string hlsl_profile;
for (std::vector<std::string>::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 <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::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";
}
} }

@ -3,6 +3,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <sstream>
#include "MaterialInstance.hpp" #include "MaterialInstance.hpp"
#include "ShaderSet.hpp" #include "ShaderSet.hpp"
@ -12,9 +13,21 @@ namespace sh
{ {
class Platform; 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<std::string, MaterialInstance> MaterialMap; typedef std::map<std::string, MaterialInstance> MaterialMap;
typedef std::map<std::string, ShaderSet> ShaderSetMap; typedef std::map<std::string, ShaderSet> ShaderSetMap;
typedef std::map<std::string, PropertySetGet> ConfigurationMap; typedef std::map<std::string, Configuration> ConfigurationMap;
typedef std::map<int, PropertySetGet> LodConfigurationMap; typedef std::map<int, PropertySetGet> LodConfigurationMap;
typedef std::map<std::string, int> LastModifiedMap; typedef std::map<std::string, int> LastModifiedMap;
@ -81,8 +94,8 @@ namespace sh
/// Get a MaterialInstance by name /// Get a MaterialInstance by name
MaterialInstance* getMaterialInstance (const std::string& name); MaterialInstance* getMaterialInstance (const std::string& name);
/// Register a configuration, which can then be used by switching the active material scheme /// Create a configuration, which can then be altered by using Factory::getConfiguration
void registerConfiguration (const std::string& name, PropertySetGet configuration); 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 /// 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 /// 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) /// \note The default is off (no cache reading)
void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; }
/// Saves all the materials that were initially loaded from the file with this name /// Lists all materials currently registered with the factory. Whether they are
void saveMaterials (const std::string& filename); /// loaded or not does not matter.
void listMaterials (std::vector<std::string>& out);
/// Lists current name & value of all global settings.
void listGlobalSettings (std::map<std::string, std::string>& out);
/// Lists configuration names.
void listConfigurationNames (std::vector<std::string>& out);
/// Lists current name & value of settings for a given configuration.
void listConfigurationSettings (const std::string& name, std::map<std::string, std::string>& out);
/// Lists shader sets.
void listShaderSets (std::vector<std::string>& 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(); static Factory& getInstance();
///< Return instance of this class. ///< Return instance of this class.
@ -137,11 +190,13 @@ namespace sh
/// You will probably never have to use this. /// You will probably never have to use this.
void _ensureMaterial(const std::string& name, const std::string& configuration); void _ensureMaterial(const std::string& name, const std::string& configuration);
Configuration* getConfiguration (const std::string& name);
private: private:
MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex);
ShaderSet* getShaderSet (const std::string& name); ShaderSet* getShaderSet (const std::string& name);
PropertySetGet* getConfiguration (const std::string& name);
Platform* getPlatform (); Platform* getPlatform ();
PropertySetGet* getCurrentGlobalSettings(); PropertySetGet* getCurrentGlobalSettings();
@ -163,6 +218,8 @@ namespace sh
std::map<TextureUnitState*, std::string> mTextureAliasInstances; std::map<TextureUnitState*, std::string> mTextureAliasInstances;
void logError (const std::string& msg);
friend class Platform; friend class Platform;
friend class MaterialInstance; friend class MaterialInstance;
friend class ShaderInstance; friend class ShaderInstance;
@ -179,6 +236,7 @@ namespace sh
bool mWriteMicrocodeCache; bool mWriteMicrocodeCache;
bool mReadSourceCache; bool mReadSourceCache;
bool mWriteSourceCache; bool mWriteSourceCache;
std::stringstream mErrorLog;
MaterialMap mMaterials; MaterialMap mMaterials;
ShaderSetMap mShaderSets; ShaderSetMap mShaderSets;

@ -1,6 +1,7 @@
#include "MaterialInstance.hpp" #include "MaterialInstance.hpp"
#include <stdexcept> #include <stdexcept>
#include <iostream>
#include "Factory.hpp" #include "Factory.hpp"
#include "ShaderSet.hpp" #include "ShaderSet.hpp"
@ -12,6 +13,7 @@ namespace sh
, mShadersEnabled(true) , mShadersEnabled(true)
, mFactory(f) , mFactory(f)
, mListener(NULL) , mListener(NULL)
, mFailedToCreate(false)
{ {
} }
@ -46,6 +48,7 @@ namespace sh
return; return;
mMaterial->removeAll(); mMaterial->removeAll();
mTexUnits.clear(); mTexUnits.clear();
mFailedToCreate = false;
} }
void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value)
@ -54,118 +57,136 @@ namespace sh
destroyAll(); // trigger updates 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 (mFailedToCreate)
if (!res) return false;
return; // listener was false positive try{
mMaterial->ensureLoaded();
if (mListener) bool res = mMaterial->createConfiguration(configuration, lodIndex);
mListener->requestedConfiguration (this, configuration); if (!res)
return false; // listener was false positive
mFactory->setActiveConfiguration (configuration);
mFactory->setActiveLodLevel (lodIndex); if (mListener)
mListener->requestedConfiguration (this, configuration);
bool allowFixedFunction = true;
if (!mShadersEnabled && hasProperty("allow_fixed_function")) mFactory->setActiveConfiguration (configuration);
{ mFactory->setActiveLodLevel (lodIndex);
allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get();
} bool allowFixedFunction = true;
if (!mShadersEnabled && hasProperty("allow_fixed_function"))
{
allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get();
}
bool useShaders = mShadersEnabled || !allowFixedFunction; bool useShaders = mShadersEnabled || !allowFixedFunction;
// get passes of the top-most parent // get passes of the top-most parent
PassVector passes = getPasses(); PassVector* passes = getParentPasses();
if (passes.size() == 0) if (passes->empty())
throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); throw std::runtime_error ("material \"" + mName + "\" does not have any passes");
for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it) for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it)
{ {
boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex); boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex);
it->copyAll (pass.get(), this); it->copyAll (pass.get(), this);
// texture samplers used in the shaders // texture samplers used in the shaders
std::vector<std::string> usedTextureSamplersVertex; std::vector<std::string> usedTextureSamplersVertex;
std::vector<std::string> usedTextureSamplersFragment; std::vector<std::string> usedTextureSamplersFragment;
PropertySetGet* context = this; PropertySetGet* context = this;
// create or retrieve shaders // create or retrieve shaders
bool hasVertex = it->hasProperty("vertex_program"); bool hasVertex = it->hasProperty("vertex_program")
bool hasFragment = it->hasProperty("fragment_program"); && !retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get().empty();
if (useShaders) bool hasFragment = it->hasProperty("fragment_program")
{ && !retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get().empty();
it->setContext(context); if (useShaders)
it->mShaderProperties.setContext(context);
if (hasVertex)
{ {
ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get()); it->setContext(context);
ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); it->mShaderProperties.setContext(context);
if (v) if (hasVertex)
{ {
pass->assignProgram (GPT_Vertex, v->getName()); ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get());
v->setUniformParameters (pass, &it->mShaderProperties); ShaderInstance* v = vertex->getInstance(&it->mShaderProperties);
if (v)
std::vector<std::string> sharedParams = v->getSharedParameters ();
for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it)
{ {
pass->addSharedParameter (GPT_Vertex, *it); pass->assignProgram (GPT_Vertex, v->getName());
} v->setUniformParameters (pass, &it->mShaderProperties);
std::vector<std::string> sharedParams = v->getSharedParameters ();
for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
{
pass->addSharedParameter (GPT_Vertex, *it2);
}
std::vector<std::string> vector = v->getUsedSamplers (); std::vector<std::string> vector = v->getUsedSamplers ();
usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end());
}
} }
} if (hasFragment)
if (hasFragment)
{
ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get());
ShaderInstance* f = fragment->getInstance(&it->mShaderProperties);
if (f)
{ {
pass->assignProgram (GPT_Fragment, f->getName()); ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get());
f->setUniformParameters (pass, &it->mShaderProperties); ShaderInstance* f = fragment->getInstance(&it->mShaderProperties);
if (f)
std::vector<std::string> sharedParams = f->getSharedParameters ();
for (std::vector<std::string>::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it)
{ {
pass->addSharedParameter (GPT_Fragment, *it); pass->assignProgram (GPT_Fragment, f->getName());
} f->setUniformParameters (pass, &it->mShaderProperties);
std::vector<std::string> vector = f->getUsedSamplers (); std::vector<std::string> sharedParams = f->getSharedParameters ();
usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
{
pass->addSharedParameter (GPT_Fragment, *it2);
}
std::vector<std::string> vector = f->getUsedSamplers ();
usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end());
}
} }
} }
}
// create texture units // create texture units
std::vector<MaterialInstanceTextureUnit> texUnits = it->getTexUnits(); std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits;
int i=0; int i=0;
for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt ) for (std::vector<MaterialInstanceTextureUnit>::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<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get()))
{ {
boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (); // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled
texIt->copyAll (texUnit.get(), context); 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<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get()))
{
boost::shared_ptr<TextureUnitState> 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) // set texture unit indices (required by GLSL)
if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL)
{ {
pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i);
++i; ++i;
}
} }
} }
} }
}
if (mListener) if (mListener)
mListener->createdConfiguration (this, configuration); 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 () Material* MaterialInstance::getMaterial ()
@ -180,12 +201,23 @@ namespace sh
return &mPasses.back(); 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) if (mParent)
return static_cast<MaterialInstance*>(mParent)->getPasses(); return static_cast<MaterialInstance*>(mParent)->getParentPasses();
else else
return mPasses; return &mPasses;
}
PassVector* MaterialInstance::getPasses()
{
return &mPasses;
} }
void MaterialInstance::setShadersEnabled (bool enabled) void MaterialInstance::setShadersEnabled (bool enabled)
@ -206,7 +238,7 @@ namespace sh
if (mParent) if (mParent)
{ {
stream << "\t" << static_cast<MaterialInstance*>(mParent)->getName() << "\n"; stream << "\t" << "parent " << static_cast<MaterialInstance*>(mParent)->getName() << "\n";
} }
const PropertyMap& properties = listProperties (); const PropertyMap& properties = listProperties ();
@ -215,6 +247,14 @@ namespace sh
stream << "\t" << it->first << " " << retrieveValue<StringValue>(getProperty(it->first), NULL).get() << "\n"; stream << "\t" << it->first << " " << retrieveValue<StringValue>(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"; stream << "}\n";
} }
} }

@ -41,8 +41,12 @@ namespace sh
MaterialInstance (const std::string& name, Factory* f); MaterialInstance (const std::string& name, Factory* f);
virtual ~MaterialInstance (); virtual ~MaterialInstance ();
PassVector* getParentPasses(); ///< gets the passes of the top-most parent
PassVector* getPasses(); ///< get our passes (for derived materials, none)
MaterialInstancePass* createPass (); 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! /// @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! /// 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); 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: private:
void setParentInstance (const std::string& name); void setParentInstance (const std::string& name);
std::string getParentInstance (); std::string getParentInstance ();
void create (Platform* platform); 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 destroyAll ();
void setShadersEnabled (bool enabled); 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); 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; friend class Factory;

@ -1,5 +1,7 @@
#include "MaterialInstancePass.hpp" #include "MaterialInstancePass.hpp"
#include <fstream>
namespace sh namespace sh
{ {
@ -9,8 +11,25 @@ namespace sh
return &mTexUnits.back(); return &mTexUnits.back();
} }
std::vector <MaterialInstanceTextureUnit> 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 <MaterialInstanceTextureUnit>::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";
}
} }
} }

@ -18,10 +18,10 @@ namespace sh
public: public:
MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); MaterialInstanceTextureUnit* createTextureUnit (const std::string& name);
void save (std::ofstream& stream);
PropertySetGet mShaderProperties; PropertySetGet mShaderProperties;
std::vector <MaterialInstanceTextureUnit> getTexUnits ();
private:
std::vector <MaterialInstanceTextureUnit> mTexUnits; std::vector <MaterialInstanceTextureUnit> mTexUnits;
}; };
} }

@ -18,6 +18,7 @@ namespace sh
public: public:
MaterialInstanceTextureUnit (const std::string& name); MaterialInstanceTextureUnit (const std::string& name);
std::string getName() const; std::string getName() const;
void setName (const std::string& name) { mName = name; }
private: private:
std::string mName; std::string mName;
}; };

@ -9,7 +9,7 @@ namespace sh
Platform::Platform (const std::string& basePath) Platform::Platform (const std::string& basePath)
: mBasePath(basePath) : mBasePath(basePath)
, mCacheFolder("./") , mCacheFolder("./")
, mShaderCachingEnabled(false) , mFactory(NULL)
{ {
} }
@ -57,11 +57,6 @@ namespace sh
mCacheFolder = folder; mCacheFolder = folder;
} }
void Platform::setShaderCachingEnabled (bool enabled)
{
mShaderCachingEnabled = enabled;
}
std::string Platform::getCacheFolder() const std::string Platform::getCacheFolder() const
{ {
return mCacheFolder; return mCacheFolder;

@ -24,6 +24,7 @@ namespace sh
class GpuProgram class GpuProgram
{ {
public: public:
virtual ~GpuProgram() {}
virtual bool getSupported () = 0; ///< @return true if the compilation was successful virtual bool getSupported () = 0; ///< @return true if the compilation was successful
/// @param name name of the uniform in the shader /// @param name name of the uniform in the shader
@ -35,8 +36,7 @@ namespace sh
class TextureUnitState : public PropertySet class TextureUnitState : public PropertySet
{ {
public: public:
virtual ~TextureUnitState(); virtual ~TextureUnitState();
virtual void setTextureName (const std::string& textureName) = 0; virtual void setTextureName (const std::string& textureName) = 0;
protected: protected:
@ -46,7 +46,7 @@ namespace sh
class Pass : public PropertySet class Pass : public PropertySet
{ {
public: public:
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState () = 0; virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name) = 0;
virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; virtual void assignProgram (GpuProgramType type, const std::string& name) = 0;
/// @param type gpu program type /// @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 bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists
virtual void removeAll () = 0; ///< remove all configurations 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 setLodLevels (const std::string& lodLevels) = 0;
virtual void setShadowCasterMaterial (const std::string& name) = 0; virtual void setShadowCasterMaterial (const std::string& name) = 0;
@ -79,8 +82,6 @@ namespace sh
Platform (const std::string& basePath); Platform (const std::string& basePath);
virtual ~Platform (); virtual ~Platform ();
void setShaderCachingEnabled (bool enabled);
/// set the folder to use for shader caching /// set the folder to use for shader caching
void setCacheFolder (const std::string& folder); void setCacheFolder (const std::string& folder);
@ -93,6 +94,8 @@ namespace sh
const std::string& name, const std::string& profile, const std::string& name, const std::string& profile,
const std::string& source, Language lang) = 0; 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 void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0;
virtual bool isProfileSupported (const std::string& profile) = 0; virtual bool isProfileSupported (const std::string& profile) = 0;
@ -105,6 +108,7 @@ namespace sh
friend class Factory; friend class Factory;
friend class MaterialInstance; friend class MaterialInstance;
friend class ShaderInstance; friend class ShaderInstance;
friend class ShaderSet;
protected: protected:
/** /**
@ -131,9 +135,6 @@ namespace sh
std::string mCacheFolder; std::string mCacheFolder;
Factory* mFactory; Factory* mFactory;
protected:
bool mShaderCachingEnabled;
private: private:
void setFactory (Factory* factory); void setFactory (Factory* factory);

@ -6,6 +6,8 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <fstream>
namespace sh namespace sh
{ {
@ -39,8 +41,9 @@ namespace sh
mValue = false; mValue = false;
else else
{ {
std::cerr << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue" << std::endl; std::stringstream msg;
mValue = false; 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) void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context)
{ {
if (!setPropertyOverride (name, value, 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) 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; return false;
} }
@ -226,6 +233,11 @@ namespace sh
mProperties [name] = value; mProperties [name] = value;
} }
void PropertySetGet::deleteProperty(const std::string &name)
{
mProperties.erase(name);
}
PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) PropertyValuePtr& PropertySetGet::getProperty (const std::string& name)
{ {
bool found = (mProperties.find(name) != mProperties.end()); bool found = (mProperties.find(name) != mProperties.end());
@ -241,7 +253,7 @@ namespace sh
return mProperties[name]; 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()); bool found = (mProperties.find(name) != mProperties.end());
@ -256,13 +268,35 @@ namespace sh
return true; 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); mParent->copyAll (target, context);
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
{ {
target->setProperty(it->first, it->second, context); 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<StringValue>(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<LinkedValue*>(&*(it->second))->_getStringValue() << '\n';
else
stream << indentation << it->first << " " << retrieveValue<StringValue>(it->second, this).get() << '\n';
}
}
} }

@ -133,6 +133,7 @@ namespace sh
class PropertySet class PropertySet
{ {
public: public:
virtual ~PropertySet() {}
void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
protected: protected:
@ -151,18 +152,26 @@ namespace sh
virtual ~PropertySetGet() {} 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); void setParent (PropertySetGet* parent);
PropertySetGet* getParent () { return mParent; }
void setContext (PropertySetGet* context); void setContext (PropertySetGet* context);
PropertySetGet* getContext(); PropertySetGet* getContext();
virtual void setProperty (const std::string& name, PropertyValuePtr value); virtual void setProperty (const std::string& name, PropertyValuePtr value);
PropertyValuePtr& getProperty (const std::string& name); PropertyValuePtr& getProperty (const std::string& name);
void deleteProperty (const std::string& name);
const PropertyMap& listProperties() { return mProperties; } const PropertyMap& listProperties() { return mProperties; }
bool hasProperty (const std::string& name); bool hasProperty (const std::string& name) const;
private: private:
PropertyMap mProperties; PropertyMap mProperties;
@ -225,7 +234,7 @@ namespace sh
template <typename T> template <typename T>
/// Create a property of any type /// Create a property of any type
/// Example: sh::makeProperty\<sh::Vector4\> (new sh::Vector4(1, 1, 1, 1)) /// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1))
inline PropertyValuePtr makeProperty (T* p) inline PropertyValuePtr makeProperty (T* p)
{ {
return PropertyValuePtr ( static_cast<PropertyValue*>(p) ); return PropertyValuePtr ( static_cast<PropertyValue*>(p) );

@ -24,6 +24,10 @@ namespace sh
} }
ScriptLoader::ScriptLoader(const std::string& fileEnding) ScriptLoader::ScriptLoader(const std::string& fileEnding)
: mLoadOrder(0)
, mToken(TOKEN_NewLine)
, mLastToken(TOKEN_NewLine)
{ {
mFileEnding = fileEnding; mFileEnding = fileEnding;
} }
@ -36,7 +40,7 @@ namespace sh
void ScriptLoader::clearScriptList() void ScriptLoader::clearScriptList()
{ {
std::map <std::string, ScriptNode *>::iterator i; std::map <std::string, ScriptNode *>::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; delete i->second;
} }
@ -293,7 +297,7 @@ namespace sh
{ {
//Delete all children //Delete all children
std::vector<ScriptNode*>::iterator i; std::vector<ScriptNode*>::iterator i;
for (i = mChildren.begin(); i != mChildren.end(); i++) for (i = mChildren.begin(); i != mChildren.end(); ++i)
{ {
ScriptNode *node = *i; ScriptNode *node = *i;
node->mRemoveSelf = false; node->mRemoveSelf = false;
@ -323,15 +327,24 @@ namespace sh
ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive)
{ {
int indx, prevC, nextC; int indx;
int childCount = (int)mChildren.size(); int childCount = (int)mChildren.size();
if (mLastChildFound != -1) if (mLastChildFound != -1)
{ {
//If possible, try checking the nodes neighboring the last successful search //If possible, try checking the nodes neighboring the last successful search
//(often nodes searched for in sequence, so this will boost search speeds). //(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; int prevC = mLastChildFound-1;
nextC = mLastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-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) for (indx = prevC; indx <= nextC; ++indx)
{ {
ScriptNode *node = mChildren[indx]; ScriptNode *node = mChildren[indx];

@ -37,6 +37,14 @@ namespace sh
parse(); parse();
} }
ShaderSet::~ShaderSet()
{
for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it)
{
sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName());
}
}
void ShaderSet::parse() void ShaderSet::parse()
{ {
std::string currentToken; std::string currentToken;

@ -21,6 +21,7 @@ namespace sh
public: public:
ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, 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); const std::string& name, PropertySetGet* globalSettingsPtr);
~ShaderSet();
/// Retrieve a shader instance for the given properties. \n /// Retrieve a shader instance for the given properties. \n
/// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n

@ -15,6 +15,7 @@ namespace sh
OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup)
: Material() : Material()
{ {
mName = name;
assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists");
mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup);
mMaterial->removeAllTechniques(); mMaterial->removeAllTechniques();
@ -22,9 +23,22 @@ namespace sh
mMaterial->compile(); 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() OgreMaterial::~OgreMaterial()
{ {
Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); if (!mMaterial.isNull())
Ogre::MaterialManager::getSingleton().remove(mMaterial->getName());
} }
boost::shared_ptr<Pass> OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) boost::shared_ptr<Pass> OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex)
@ -34,6 +48,8 @@ namespace sh
void OgreMaterial::removeAll () void OgreMaterial::removeAll ()
{ {
if (mMaterial.isNull())
return;
mMaterial->removeAllTechniques(); mMaterial->removeAllTechniques();
mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName);
mMaterial->compile(); mMaterial->compile();

@ -18,6 +18,9 @@ namespace sh
virtual boost::shared_ptr<Pass> createPass (const std::string& configuration, unsigned short lodIndex); virtual boost::shared_ptr<Pass> createPass (const std::string& configuration, unsigned short lodIndex);
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
virtual bool isUnreferenced();
virtual void ensureLoaded();
virtual void removeAll (); virtual void removeAll ();
Ogre::MaterialPtr getOgreMaterial(); Ogre::MaterialPtr getOgreMaterial();
@ -30,6 +33,7 @@ namespace sh
private: private:
Ogre::MaterialPtr mMaterial; Ogre::MaterialPtr mMaterial;
std::string mName;
std::string mShadowCasterMaterial; std::string mShadowCasterMaterial;
}; };

@ -20,9 +20,9 @@ namespace sh
mPass = t->createPass(); mPass = t->createPass();
} }
boost::shared_ptr<TextureUnitState> OgrePass::createTextureUnitState () boost::shared_ptr<TextureUnitState> OgrePass::createTextureUnitState (const std::string& name)
{ {
return boost::shared_ptr<TextureUnitState> (new OgreTextureUnitState (this)); return boost::shared_ptr<TextureUnitState> (new OgreTextureUnitState (this, name));
} }
void OgrePass::assignProgram (GpuProgramType type, const std::string& name) void OgrePass::assignProgram (GpuProgramType type, const std::string& name)
@ -105,7 +105,17 @@ namespace sh
else if (type == GPT_Fragment) else if (type == GPT_Fragment)
params = mPass->getFragmentProgramParameters(); 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) void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index)

@ -14,7 +14,7 @@ namespace sh
public: public:
OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex);
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (); virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name);
virtual void assignProgram (GpuProgramType type, const std::string& name); virtual void assignProgram (GpuProgramType type, const std::string& name);
Ogre::Pass* getOgrePass(); Ogre::Pass* getOgrePass();

@ -4,6 +4,7 @@
#include <OgreDataStream.h> #include <OgreDataStream.h>
#include <OgreGpuProgramManager.h> #include <OgreGpuProgramManager.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreRoot.h> #include <OgreRoot.h>
#include "OgreMaterial.hpp" #include "OgreMaterial.hpp"
@ -76,6 +77,11 @@ namespace sh
return boost::shared_ptr<Material> (material); return boost::shared_ptr<Material> (material);
} }
void OgrePlatform::destroyGpuProgram(const std::string &name)
{
Ogre::HighLevelGpuProgramManager::getSingleton().remove(name);
}
boost::shared_ptr<GpuProgram> OgrePlatform::createGpuProgram ( boost::shared_ptr<GpuProgram> OgrePlatform::createGpuProgram (
GpuProgramType type, GpuProgramType type,
const std::string& compileArguments, const std::string& compileArguments,
@ -122,6 +128,7 @@ namespace sh
if (mSharedParameters.find(name) == mSharedParameters.end()) if (mSharedParameters.find(name) == mSharedParameters.end())
{ {
params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name);
Ogre::GpuConstantType type; Ogre::GpuConstantType type;
if (typeid(*value) == typeid(Vector4)) if (typeid(*value) == typeid(Vector4))
type = Ogre::GCT_FLOAT4; type = Ogre::GCT_FLOAT4;

@ -47,6 +47,8 @@ namespace sh
const std::string& name, const std::string& profile, const std::string& name, const std::string& profile,
const std::string& source, Language lang); const std::string& source, Language lang);
virtual void destroyGpuProgram (const std::string& name);
virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); virtual void setSharedParameter (const std::string& name, PropertyValuePtr value);
friend class ShaderInstance; friend class ShaderInstance;

@ -6,10 +6,11 @@
namespace sh namespace sh
{ {
OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent) OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name)
: TextureUnitState() : TextureUnitState()
{ {
mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); mTextureUnitState = parent->getOgrePass()->createTextureUnitState("");
mTextureUnitState->setName(name);
} }
bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context)

@ -12,7 +12,7 @@ namespace sh
class OgreTextureUnitState : public TextureUnitState class OgreTextureUnitState : public TextureUnitState
{ {
public: public:
OgreTextureUnitState (OgrePass* parent); OgreTextureUnitState (OgrePass* parent, const std::string& name);
virtual void setTextureName (const std::string& textureName); virtual void setTextureName (const std::string& textureName);

Loading…
Cancel
Save