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)

pull/16/head
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