Commit ce03ceed authored by Robert Menzel's avatar Robert Menzel

added multifile manager - all related shaderprograms are updated now if one shader changes

parent c0822cdb
......@@ -6,6 +6,7 @@
#ifndef ACGL_ANIMATIONS_ANIMATION_HH
#define ACGL_ANIMATIONS_ANIMATION_HH
#include <ACGL/ACGL.hh>
#include <ACGL/Types.hh>
#include <ACGL/Base/Macros.hh>
#include <ACGL/Animations/EaseFunctions.hh>
......
......@@ -30,6 +30,8 @@ private:\
typedef ptr::shared_ptr<const Class> ConstShared ## Class; \
typedef ptr::weak_ptr<Class> Weak ## Class; \
typedef ptr::weak_ptr<const Class> ConstWeak ## Class;
#error "TR1 used"
#endif
#endif // MACROS_HH
......@@ -16,9 +16,11 @@
#include <ACGL/ACGL.hh>
#include <ACGL/Resource/MultiFileController.hh>
#include <ACGL/Resource/FileController.hh>
#include <ACGL/OpenGL/Objects/ShaderProgram.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/Base/Settings.hh>
#include <vector>
#include <ACGL/OpenGL/Data/LocationMappings.hh>
......@@ -26,7 +28,7 @@
namespace ACGL{
namespace OpenGL{
class ShaderProgramControlFiles : public Resource::FileController<ShaderProgram>
class ShaderProgramControlFiles : public Resource::MultiFileController<ShaderProgram>
{
struct ShaderEndings
{
......@@ -40,16 +42,20 @@ class ShaderProgramControlFiles : public Resource::FileController<ShaderProgram>
// ============================================================================================ CONSTRUCTORS \/
// ========================================================================================================= \/
public:
//! the filename will also be the name of the resource
//! The filenames (sorted and concatenated) will also be the name of the resource (can be changed by setResourceName() below).
//! If the filename has a dot in it (or _type is set), it will be treated as a single file, otherwise all
//! files starting with that string will be used.
ShaderProgramControlFiles(const std::string& _fileName, GLenum _type = GL_INVALID_VALUE )
: Resource::FileController<ShaderProgram>(_fileName),
: Resource::MultiFileController<ShaderProgram>(),
mShaderType(),
mAttributeLocations(new LocationMappings),
mFragmentDataLocations(new LocationMappings),
mUniformBufferLocations(new LocationMappings)
{
// the base path is only needed for updating the time stamps, as the shaders itself get loaded via ShaderControlFiles
// which itself will add the base path! (read: mFileNames will _NOT_ store the base path!)
mBasePath = Base::Settings::the()->getFullShaderPath();
if ( _type != GL_INVALID_VALUE ) {
andFile( _fileName, _type );
return;
......@@ -68,15 +74,16 @@ public:
// ============================================================================================ METHODS \/
// ==================================================================================================== \/
public:
//void addFile (const std::string &_fileName) {};
//
// Adding files:
//
//! adds a single file, the shader type will be guessed by the ending:
inline ShaderProgramControlFiles& andFile (const std::string &_fileName) { mFileName.push_back( _fileName ); mShaderType.push_back( GL_INVALID_VALUE ); return *this; }
inline ShaderProgramControlFiles& andFile (const std::string &_fileName) { addFile( _fileName ); mShaderType.push_back( GL_INVALID_VALUE ); return *this; }
//! adds a single file, the shader type is explicitly given and must be one of:
//! GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER
inline ShaderProgramControlFiles& andFile (const std::string &_fileName, GLenum _type) { mFileName.push_back( _fileName ); mShaderType.push_back( _type ); return *this; }
inline ShaderProgramControlFiles& andFile (const std::string &_fileName, GLenum _type) { addFile( _fileName ); mShaderType.push_back( _type ); return *this; }
//! adds all files begining with the given name, the shader type will be guessed by the ending:
ShaderProgramControlFiles& autoFiles (const std::string &_fileName);
......@@ -117,6 +124,14 @@ public:
//! adds a whole list of mappings
inline ShaderProgramControlFiles& uniformBufferLocations(const SharedLocationMappings &_mapping) { mUniformBufferLocations->addLocations(_mapping);return *this; }
//
// Modifying the resource name:
// A ShaderProgram consists of multiple shader files, so associating the ShaderProgram with just one of those file names
// is often not useful.
//
inline ShaderProgramControlFiles& setResourceName(const std::string &_resourceName) { mResourceName = _resourceName; return *this; }
//virtual std::string getResourceName(void) const;// { return mResourceName; }
// ===================================================================================================== \/
// ============================================================================================ OVERRIDE \/
......@@ -130,7 +145,6 @@ public:
// =================================================================================================== \/
protected:
std::vector<GLenum> mShaderType;
std::vector<std::string> mFileName;
SharedLocationMappings mAttributeLocations;
SharedLocationMappings mFragmentDataLocations;
......
......@@ -34,7 +34,7 @@ typedef Resource::NameManager<Shader> ShaderNameManager;
typedef Resource::FileManager<Shader> ShaderFileManager;
typedef Resource::NameManager<ShaderProgram> ShaderProgramNameManager;
typedef Resource::FileManager<ShaderProgram> ShaderProgramFileManager;
typedef Resource::MultiFileManager<ShaderProgram> ShaderProgramFileManager;
typedef Resource::NameManager<ShaderProgramObject> ShaderProgramObjectNameManager;
......
......@@ -22,6 +22,7 @@
#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
namespace ACGL{
namespace OpenGL{
......@@ -39,6 +40,10 @@ public:
mType(_type)
{
mObjectName = glCreateShader(mType);
if (mObjectName == 0) {
openGLRareError();
ACGL::Utils::error() << "couldn't create Shader object! Requested type = " << (unsigned int) mType << std::endl;
}
}
virtual ~Shader(void)
......
......@@ -35,6 +35,7 @@ public:
// ============================================================================================ METHODS \/
// ==================================================================================================== \/
public:
virtual std::string getResourceName(void) const { return getFilename(); }
const std::string& getFilename(void) const { return mFilename; }
const std::string& getFullFilePath(void) const { return mFullFilePath; }
......
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University //
// Copyright (c) 2011, 2012 Computer Graphics Group RWTH Aachen University //
// All rights reserved. //
////////////////////////////////////////////////////////////////////////////////
......@@ -10,6 +10,7 @@
#include <ACGL/Base/Singleton.hh>
#include <ACGL/Base/Macros.hh>
#include <ACGL/Resource/FileController.hh>
#include <ACGL/Resource/MultiFileController.hh>
#include <map>
#include <string>
......@@ -60,7 +61,7 @@ private:
template<typename RESOURCE> template<typename CONTROLLER>
typename FileManager<RESOURCE>::ConstSharedRESOURCE FileManager<RESOURCE>::get(const CONTROLLER& _controller)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_controller.getFilename());
typename ResourceMap::iterator existingResource = mResourceMap.find(_controller.getResourceName());
if(existingResource != mResourceMap.end())
return existingResource->second.resource;
......@@ -69,13 +70,13 @@ typename FileManager<RESOURCE>::ConstSharedRESOURCE FileManager<RESOURCE>::get(c
if(pResource)
{
Resource resource = { pController, pResource };
mResourceMap[_controller.getFilename()] = resource;
Utils::debug() << "FileManager::getResource: Resource loaded: " << _controller.getFilename() << std::endl;
mResourceMap[_controller.getResourceName()] = resource;
Utils::debug() << "FileManager::getResource: Resource loaded: " << _controller.getResourceName() << std::endl;
return pResource;
}
else
{
Utils::error() << "FileManager::getResource: Resource could not be loaded: " << _controller.getFilename() << std::endl;
Utils::error() << "FileManager::getResource: Resource could not be loaded: " << _controller.getResourceName() << std::endl;
}
return SharedRESOURCE();
}
......@@ -136,6 +137,129 @@ void FileManager<RESOURCE>::updateAll(void)
i->second.controller->update(i->second.resource);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: merge FileManager & MultiFileManager
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename RESOURCE>
class MultiFileManager : public Base::Singleton< MultiFileManager<RESOURCE> >
{
ACGL_SINGLETON(MultiFileManager<RESOURCE>)
public:
typedef ptr::shared_ptr< MultiFileController<RESOURCE> > SharedController;
ACGL_SMARTPOINTER_TYPEDEFS(RESOURCE)
struct Resource
{
SharedController controller;
SharedRESOURCE resource;
};
typedef std::map<std::string, Resource> ResourceMap;
typedef ResourceMap ResourceContainer;
virtual ~MultiFileManager(void) {}
template<typename CONTROLLER>
ConstSharedRESOURCE get(const CONTROLLER& _controller);
ConstSharedRESOURCE query(const std::string& _filename);
bool exists(const std::string& _key);
bool erase(const std::string& key);
void eraseAll(void);
bool update(const std::string& key);
void updateAll(void);
typename ResourceMap::const_iterator begin(void) const { return mResourceMap.begin(); }
typename ResourceMap::const_iterator end(void) const { return mResourceMap.end(); }
protected:
MultiFileManager(void)
: mResourceMap()
{}
private:
ResourceMap mResourceMap;
};
template<typename RESOURCE> template<typename CONTROLLER>
typename MultiFileManager<RESOURCE>::ConstSharedRESOURCE MultiFileManager<RESOURCE>::get(const CONTROLLER& _controller)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_controller.getResourceName());
if(existingResource != mResourceMap.end())
return existingResource->second.resource;
SharedController pController(new CONTROLLER(_controller));
SharedRESOURCE pResource = pController->create();
if(pResource)
{
Resource resource = { pController, pResource };
mResourceMap[_controller.getResourceName()] = resource;
Utils::debug() << "FileManager::getResource: Resource loaded: " << _controller.getResourceName() << std::endl;
return pResource;
}
else
{
Utils::error() << "FileManager::getResource: Resource could not be loaded: " << _controller.getResourceName() << std::endl;
}
return SharedRESOURCE();
}
template<typename RESOURCE>
typename MultiFileManager<RESOURCE>::ConstSharedRESOURCE MultiFileManager<RESOURCE>::query(const std::string& _key)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_key);
if(existingResource != mResourceMap.end())
return existingResource->second.resource;
return ConstSharedRESOURCE();
}
template<typename RESOURCE>
bool MultiFileManager<RESOURCE>::exists(const std::string& _key)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_key);
if(existingResource != mResourceMap.end())
return true;
return false;
}
template<typename RESOURCE>
bool MultiFileManager<RESOURCE>::erase(const std::string& _key)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_key);
if(existingResource != mResourceMap.end())
{
mResourceMap.erase(existingResource);
Utils::debug() << "FileManager::Resource deleted: " << _key << std::endl;
return true;
}
Utils::warning() << "FileManager::Resource not found for deletion! " << std::endl;
return false;
}
template<typename RESOURCE>
void MultiFileManager<RESOURCE>::eraseAll(void)
{
mResourceMap.clear();
}
template<typename RESOURCE>
bool MultiFileManager<RESOURCE>::update(const std::string& _key)
{
typename ResourceMap::iterator existingResource = mResourceMap.find(_key);
if(existingResource != mResourceMap.end())
return existingResource->second.controller->update(existingResource->second.resource);
return false;
}
template<typename RESOURCE>
void MultiFileManager<RESOURCE>::updateAll(void)
{
for(typename ResourceMap::iterator i = mResourceMap.begin();
i != mResourceMap.end();
++i)
i->second.controller->update(i->second.resource);
}
} // Resource
} // ACGL
......
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, 2012 Computer Graphics Group RWTH Aachen University //
// All rights reserved. //
////////////////////////////////////////////////////////////////////////////////
#ifndef ACGL_RESOURCE_MULTIFILECONTROLLER_HH
#define ACGL_RESOURCE_MULTIFILECONTROLLER_HH
/**
* Similar to a file controller, but this keeps track of multiple files and updates
* itself if one of them was changed.
* A special Resourcename can be set as one filename alown can't identify the
* resource.
*/
#include <ACGL/ACGL.hh>
#include <ACGL/Resource/BasicCreateController.hh>
#include <ACGL/Resource/BasicUpdateController.hh>
#include <ACGL/Base/FileHelpers.hh>
#include <string>
#include <sstream>
#include <algorithm>
namespace ACGL{
namespace Resource{
template<typename RESOURCE>
class MultiFileController : public BasicCreateController<RESOURCE>, public BasicUpdateController<RESOURCE>
{
// ========================================================================================================= \/
// ============================================================================================ CONSTRUCTORS \/
// ========================================================================================================= \/
public:
//! sets the first file and the base path, more files can be added with 'addFile'
MultiFileController(const std::string& _filename,const std::string& _basePath)
: mBasePath(_basePath)
{
addFile( _filename );
}
virtual ~MultiFileController(){}
// ==================================================================================================== \/
// ============================================================================================ METHODS \/
// ==================================================================================================== \/
public:
//! the default resourcename is the concatenation of the alphabetically sorted filenames
//! a setter for a user-defined resourcename should be defined in derived classes
virtual std::string getResourceName(void) const
{
// unless a name was set explicitly, set the 'filename' of this resource to the concatenation
// of the sorted list of filenames (most likely unique, but not guaranteed)
if (mResourceName == "") {
std::vector<std::string> namesAlpha = mFileNames;
std::sort(namesAlpha.begin(), namesAlpha.end());
std::stringstream sstream;
for (unsigned int i = 0; i < namesAlpha.size(); ++i) {
sstream << namesAlpha[i];
}
return sstream.str();
}
return mResourceName;
}
protected:
//! This constructor does not add any files, use this only on derived types which constructor will add a file itself!
MultiFileController() : mBasePath("") {}
//! adds another file, this is protected to derived classes can expose specific versions which do more than just remembering one file
void addFile (const std::string &_fileName) {
mFileNames.push_back( _fileName );
mFileModificationTime.push_back( Base::FileHelpers::FileModificationTime() );
}
//! returns true iff _all_ files are up to date
bool filesAreUpToDate(void) {
bool b = true;
for (unsigned int i = 0; i < mFileNames.size(); ++i) {
b &= ( Base::FileHelpers::getFileModificationTime( mBasePath+mFileNames[i] ) == mFileModificationTime[i] );
}
return b;
}
//! updates _all_ modification times
void updateFileModificationTimes(void) {
for (unsigned int i = 0; i < mFileNames.size(); ++i) {
mFileModificationTime[i] = Base::FileHelpers::getFileModificationTime( mBasePath+mFileNames[i]);
}
}
// =================================================================================================== \/
// ============================================================================================ FIELDS \/
// =================================================================================================== \/
protected:
std::vector<std::string> mFileNames;
std::string mBasePath;
std::string mResourceName;
std::vector<Base::FileHelpers::FileModificationTime> mFileModificationTime;
};
} // Resource
} // ACGL
#endif // ACGL_RESOURCE_MULTIFILECONTROLLER_HH
......@@ -10,6 +10,9 @@
#include <ACGL/Base/Settings.hh>
#include <ACGL/Base/FileHelpers.hh>
#include <sstream>
#include <algorithm>
using namespace ACGL::Base;
using namespace ACGL::OpenGL;
......@@ -35,13 +38,13 @@ const ShaderProgramControlFiles::ShaderEndings ShaderProgramControlFiles::sShade
ShaderProgramControlFiles& ShaderProgramControlFiles::autoFiles(const std::string &_fileName)
{
//Utils::debug() << "autoFiles: " << _fileName << std::endl;
std::string baseFileName = Base::Settings::the()->getFullShaderPath() + _fileName + ".";
std::string baseFileName = _fileName + ".";
for (unsigned int ending = 0; ending < sShaderEndingsSize; ++ending)
{
std::string fileName = baseFileName + sShaderEndings[ending].ending;
if ( FileHelpers::fileExists(fileName) )
if ( FileHelpers::fileExists( mBasePath + fileName ) )
{
mFileName.push_back( _fileName +"."+sShaderEndings[ending].ending ); // DON'T store a version with the full shader path
addFile( fileName ); // DON'T store a version with the full shader path
mShaderType.push_back( sShaderEndings[ending].type );
//Utils::debug() << "autoFiles: added " << fileName << " - type: " << sShaderEndings[ending].ending << std::endl;
}
......@@ -53,7 +56,7 @@ SharedShaderProgram ShaderProgramControlFiles::create(void)
{
SharedShaderProgram shaderProgram(new ShaderProgram());
std::vector<std::string>::size_type numberOfFiles = mFileName.size();
std::vector<std::string>::size_type numberOfFiles = mFileNames.size();
// some of the files have correct types already, some not yet -> try to guess the rest
for (std::vector<std::string>::size_type file = 0; file < numberOfFiles; ++file) {
......@@ -62,7 +65,7 @@ SharedShaderProgram ShaderProgramControlFiles::create(void)
// guess the shader type:
for (unsigned int ending = 0; ending < sShaderEndingsSize; ++ending)
{
if ( FileHelpers::stringEndsWith( mFileName[file], sShaderEndings[ending].ending ) )
if ( FileHelpers::stringEndsWith( mFileNames[file], sShaderEndings[ending].ending ) )
{
mShaderType[file] = sShaderEndings[ending].type;
continue;
......@@ -76,34 +79,35 @@ SharedShaderProgram ShaderProgramControlFiles::create(void)
// check for problems:
if ( mShaderType[i] == GL_INVALID_VALUE ) {
Utils::error() << "file extension of file " << mFileName[i] << " not recognized - ignored" << std::endl;
Utils::error() << "file extension of file " << mFileNames[i] << " not recognized - ignored" << std::endl;
}
if (! FileHelpers::fileExists( Settings::the()->getFullShaderPath() + mFileName[i] ) ) {
Utils::warning() << "file " << mFileName[i] << " does not exist - ignored" << std::endl;
if (! FileHelpers::fileExists( Settings::the()->getFullShaderPath() + mFileNames[i] ) ) {
Utils::warning() << "file " << mFileNames[i] << " does not exist - ignored ( full path: "
<< Settings::the()->getFullShaderPath() + mFileNames[i] << " )" << std::endl;
mShaderType[i] = GL_INVALID_VALUE;
}
if ( (mShaderType[i] == GL_GEOMETRY_SHADER) && !OpenGL::doesSupportGeometryShader() ) {
Utils::error() << "file " << mFileName[i] << " ignored, hardware does not support geometry shader" << std::endl;
Utils::error() << "file " << mFileNames[i] << " ignored, hardware does not support geometry shader" << std::endl;
mShaderType[i] = GL_INVALID_VALUE;
}
if ( ((mShaderType[i] == GL_TESS_CONTROL_SHADER) || (mShaderType[i] == GL_TESS_EVALUATION_SHADER))
&& !OpenGL::doesSupportTessellationShader() ) {
Utils::error() << "file " << mFileName[i] << " ignored, hardware does not support tessellation shader" << std::endl;
Utils::error() << "file " << mFileNames[i] << " ignored, hardware does not support tessellation shader" << std::endl;
mShaderType[i] = GL_INVALID_VALUE;
}
# endif // critical checks
// attach shader
if ( mShaderType[i] != GL_INVALID_VALUE ) {
ConstSharedShader shader = ShaderFileManager::the()->get(ShaderControlFile( mFileName[i] ).type( mShaderType[i] ));
ConstSharedShader shader = ShaderFileManager::the()->get(ShaderControlFile( mFileNames[i] ).type( mShaderType[i] ));
if ( shader ) {
shaderProgram->attachShader( shader );
} else {
# ifdef ACGL_CHECK_CRITICAL_GL_ERRORS
Utils::error() << "could not attach shader " << mFileName[i] << std::endl;
Utils::error() << "could not attach shader " << mFileNames[i] << std::endl;
# endif // critical checks
}
}
......@@ -113,6 +117,7 @@ SharedShaderProgram ShaderProgramControlFiles::create(void)
return SharedShaderProgram(); // linking failed
}
setBindings( shaderProgram ); // will relink, but needs a linked program :-(
updateFileModificationTimes();
return shaderProgram;
}
......@@ -145,15 +150,21 @@ bool ShaderProgramControlFiles::update(SharedShaderProgram &_shaderProgram)
{
bool update = false;
for (std::vector<std::string>::size_type i = 0; i < mFileName.size(); ++i) {
//Utils::debug() << "updating " << mResourceName << std::endl;
for (std::vector<std::string>::size_type i = 0; i < mFileNames.size(); ++i) {
if ( mShaderType[i] != GL_INVALID_VALUE ) {
update |= ShaderFileManager::the()->update( mFileName[i] );
update |= ShaderFileManager::the()->update( mFileNames[i] );
}
}
setBindings( _shaderProgram );
if (update)
if ((!filesAreUpToDate() ) || (update))
{
Utils::debug() << "updating " << mResourceName << " AND RELINKING!" << std::endl;
setBindings( _shaderProgram );
updateFileModificationTimes();
return _shaderProgram->link();
}
return false;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment