From c4d07194a280d4116996ccd086654e8c31a57696 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 4 Mar 2008 14:04:48 +0000 Subject: [PATCH] From Art Trevs, add support for saving external shader files. From Robert Osfield, adding missing member variable initializes and Output::getShaderFileNameForOutput() implementation --- include/osg/Shader | 7 ++ include/osgDB/Input | 3 + include/osgDB/Output | 9 +++ include/osgDB/ReadFile | 40 ++++++++++ include/osgDB/ReaderWriter | 15 +++- include/osgDB/Registry | 26 +++++++ include/osgDB/WriteFile | 20 +++++ src/osg/Shader.cpp | 7 +- src/osgDB/Input.cpp | 11 ++- src/osgDB/Output.cpp | 21 ++++++ src/osgDB/ReadFile.cpp | 17 +++++ src/osgDB/ReaderWriter.cpp | 2 + src/osgDB/Registry.cpp | 93 ++++++++++++++++++++++++ src/osgDB/WriteFile.cpp | 8 ++ src/osgPlugins/CMakeLists.txt | 5 ++ src/osgPlugins/glsl/CMakeLists.txt | 6 ++ src/osgPlugins/glsl/ReaderWriterGLSL.cpp | 89 +++++++++++++++++++++++ src/osgPlugins/osg/Shader.cpp | 55 ++++++++++---- src/osgWrappers/osg/Shader.cpp | 13 ++++ src/osgWrappers/osgDB/Input.cpp | 11 +++ src/osgWrappers/osgDB/ReaderWriter.cpp | 40 ++++++++++ src/osgWrappers/osgDB/Registry.cpp | 36 +++++++++ 22 files changed, 515 insertions(+), 19 deletions(-) create mode 100644 src/osgPlugins/glsl/CMakeLists.txt create mode 100644 src/osgPlugins/glsl/ReaderWriterGLSL.cpp diff --git a/include/osg/Shader b/include/osg/Shader index 875065bd1..8eb719395 100644 --- a/include/osg/Shader +++ b/include/osg/Shader @@ -83,6 +83,12 @@ class OSG_EXPORT Shader : public osg::Object /** Get the Shader type as a descriptive string. */ const char* getTypename() const; + /** Set file name for the shader source code. */ + inline void setFileName(const std::string& fileName) { _shaderFileName = fileName; } + + /** Get filename to which the shader source code belongs. */ + inline const std::string& getFileName() const { return _shaderFileName; } + /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int maxSize); @@ -178,6 +184,7 @@ class OSG_EXPORT Shader : public osg::Object protected: /*data*/ Type _type; std::string _shaderSource; + std::string _shaderFileName; /** osg::Programs that this osg::Shader is attached to */ typedef std::set< osg::Program* > ProgramSet; ProgramSet _programSet; diff --git a/include/osgDB/Input b/include/osgDB/Input index 87fcd7c6b..bf44914db 100644 --- a/include/osgDB/Input +++ b/include/osgDB/Input @@ -15,6 +15,7 @@ #define OSGDB_INPUT 1 #include +#include #include #include #include @@ -50,10 +51,12 @@ class OSGDB_EXPORT Input : public FieldReaderIterator virtual osg::StateAttribute* readStateAttribute(); virtual osg::Uniform* readUniform(); virtual osg::Node* readNode(); + virtual osg::Shader* readShader(); virtual osg::Object* readObject(const std::string& fileName); virtual osg::Image* readImage(const std::string& fileName); virtual osg::Node* readNode(const std::string& fileName); + virtual osg::Shader* readShader(const std::string& fileName); virtual osg::Object* getObjectForUniqueID(const std::string& uniqueID); virtual void registerUniqueIDForObject(const std::string& uniqueID,osg::Object* obj); diff --git a/include/osgDB/Output b/include/osgDB/Output index 40033725e..3e8cbb9e7 100644 --- a/include/osgDB/Output +++ b/include/osgDB/Output @@ -92,6 +92,11 @@ class OSGDB_EXPORT Output : public std::ofstream bool getOutputTextureFiles() const { return _outputTextureFiles; } virtual std::string getTextureFileNameForOutput(); + + void setOutputShaderFiles(bool flag) { _outputShaderFiles = flag; } + bool getOutputShaderFiles() const { return _outputShaderFiles; } + + virtual std::string getShaderFileNameForOutput(); protected: @@ -111,9 +116,13 @@ class OSGDB_EXPORT Output : public std::ofstream std::string _filename; PathNameHint _pathNameHint; + bool _outputTextureFiles; unsigned int _textureFileNameNumber; + bool _outputShaderFiles; + unsigned int _shaderFileNameNumber; + bool _writeOutDefaultValues; }; diff --git a/include/osgDB/ReadFile b/include/osgDB/ReadFile index 38d7d97af..f1c78902f 100644 --- a/include/osgDB/ReadFile +++ b/include/osgDB/ReadFile @@ -132,6 +132,26 @@ inline osg::Node* readNodeFiles(osg::ArgumentParser& parser) return readNodeFiles(parser,Registry::instance()->getOptions()); } +/** Read an osg::Shader from file. + * Return valid osg::Shader on success, + * return NULL on failure. + * Use the Options object to control cache operations and file search paths in osgDB::Registry. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to read the specified file.*/ +extern OSGDB_EXPORT osg::Shader* readShaderFile(const std::string& filename,const ReaderWriter::Options* options); + +/** Read an osg::Shader from file. + * Return valid osg::Shader on success, + * return NULL on failure. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to read the specified file.*/ +inline osg::Shader* readShaderFile(const std::string& filename) +{ + return readShaderFile(filename,Registry::instance()->getOptions()); +} + /** Read an osg::Object from file. * Return an assigned osg::ref_ptr on success, @@ -213,6 +233,26 @@ inline osg::ref_ptr readRefNodeFile(const std::string& filename) return readRefNodeFile(filename,Registry::instance()->getOptions()); } +/** Read an osg::Shader from file. + * Return an assigned osg::ref_ptr on success, + * return an osg::ref_ptr with a NULL pointer assigned to it on failure. + * Use the Options object to control cache operations and file search paths in osgDB::Registry. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to read the specified file.*/ +extern OSGDB_EXPORT osg::ref_ptr readRefShaderFile(const std::string& filename,const ReaderWriter::Options* options); + +/** Read an osg::Shader from file. + * Return an assigned osg::ref_ptr on success, + * return an osg::ref_ptr with a NULL pointer assigned to it on failure. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to read the specified file.*/ +inline osg::ref_ptr readRefShaderFile(const std::string& filename) +{ + return readRefShaderFile(filename,Registry::instance()->getOptions()); +} + } diff --git a/include/osgDB/ReaderWriter b/include/osgDB/ReaderWriter index 60a2753da..3b5530b2b 100644 --- a/include/osgDB/ReaderWriter +++ b/include/osgDB/ReaderWriter @@ -75,12 +75,16 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object /// cache objects loaded via readObject(filename) CACHE_OBJECTS = 16, + /// cache shaders loaded via readShader(filename) + CACHE_SHADERS = 32, + /// cache on all read*(filename) calls CACHE_ALL = CACHE_NODES | CACHE_IMAGES | CACHE_HEIGHTFIELDS | CACHE_ARCHIVES | - CACHE_OBJECTS + CACHE_OBJECTS | + CACHE_SHADERS }; @@ -175,18 +179,21 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object osg::HeightField* getHeightField(); osg::Node* getNode(); osgDB::Archive* getArchive(); - + osg::Shader* getShader(); + bool validObject() { return _object.valid(); } bool validImage() { return getImage()!=0; } bool validHeightField() { return getHeightField()!=0; } bool validNode() { return getNode()!=0; } bool validArchive() { return getArchive()!=0; } + bool validShader() { return getShader()!=0; } osg::Object* takeObject(); osg::Image* takeImage(); osg::HeightField* takeHeightField(); osg::Node* takeNode(); osgDB::Archive* takeArchive(); + osg::Shader* takeShader(); std::string& message() { return _message; } const std::string& message() const { return _message; } @@ -253,21 +260,25 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object virtual ReadResult readImage(const std::string& /*fileName*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readHeightField(const std::string& /*fileName*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readNode(const std::string& /*fileName*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } + virtual ReadResult readShader(const std::string& /*fileName*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual WriteResult writeObject(const osg::Object& /*obj*/,const std::string& /*fileName*/,const Options* =NULL) const {return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeImage(const osg::Image& /*image*/,const std::string& /*fileName*/,const Options* =NULL) const {return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeHeightField(const osg::HeightField& /*heightField*/,const std::string& /*fileName*/,const Options* =NULL) const {return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } + virtual WriteResult writeShader(const osg::Shader& /*shader*/,const std::string& /*fileName*/,const Options* =NULL) const {return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual ReadResult readObject(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readImage(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readHeightField(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual ReadResult readNode(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } + virtual ReadResult readShader(std::istream& /*fin*/,const Options* =NULL) const { return ReadResult(ReadResult::FILE_NOT_HANDLED); } virtual WriteResult writeObject(const osg::Object& /*obj*/,std::ostream& /*fout*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeImage(const osg::Image& /*image*/,std::ostream& /*fout*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeHeightField(const osg::HeightField& /*heightField*/,std::ostream& /*fout*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } virtual WriteResult writeNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } + virtual WriteResult writeShader(const osg::Shader& /*shader*/,std::ostream& /*fout*/,const Options* =NULL) const { return WriteResult(WriteResult::FILE_NOT_HANDLED); } }; diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 7e3110a30..a2b87fa72 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -126,6 +126,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced osg::Uniform* readUniform(Input& fr); osg::StateAttribute* readStateAttribute(Input& fr); osg::Node* readNode(Input& fr); + osg::Shader* readShader(Input& fr); bool writeObject(const osg::Object& obj,Output& fw); @@ -158,6 +159,11 @@ class OSGDB_EXPORT Registry : public osg::Referenced { return osgDB::Registry::instance()->readNodeImplementation(filename,options); } + + virtual ReaderWriter::ReadResult readShader(const std::string& filename, const ReaderWriter::Options* options) + { + return osgDB::Registry::instance()->readShaderImplementation(filename,options); + } protected: virtual ~ReadFileCallback() {} @@ -208,6 +214,12 @@ class OSGDB_EXPORT Registry : public osg::Referenced } ReaderWriter::ReadResult readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options); + ReaderWriter::ReadResult readShader(const std::string& fileName,const ReaderWriter::Options* options) + { + if (_readFileCallback.valid()) return _readFileCallback->readShader(fileName,options); + else return readShaderImplementation(fileName,options); + } + ReaderWriter::ReadResult readShaderImplementation(const std::string& fileName,const ReaderWriter::Options* options); @@ -234,6 +246,11 @@ class OSGDB_EXPORT Registry : public osg::Referenced { return osgDB::Registry::instance()->writeNodeImplementation(obj,fileName,options); } + + virtual ReaderWriter::WriteResult writeShader(const osg::Shader& obj, const std::string& fileName,const ReaderWriter::Options* options) + { + return osgDB::Registry::instance()->writeShaderImplementation(obj,fileName,options); + } protected: virtual ~WriteFileCallback() {} @@ -277,6 +294,12 @@ class OSGDB_EXPORT Registry : public osg::Referenced } ReaderWriter::WriteResult writeNodeImplementation(const osg::Node& node, const std::string& fileName,const ReaderWriter::Options* options); + ReaderWriter::WriteResult writeShader(const osg::Shader& obj, const std::string& fileName,const ReaderWriter::Options* options) + { + if (_writeFileCallback.valid()) return _writeFileCallback->writeShader(obj,fileName,options); + else return writeShaderImplementation(obj,fileName,options); + } + ReaderWriter::WriteResult writeShaderImplementation(const osg::Shader& obj, const std::string& fileName,const ReaderWriter::Options* options); void setCreateNodeFromImage(bool flag) { _createNodeFromImage = flag; } @@ -447,6 +470,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced struct ReadHeightFieldFunctor; struct ReadNodeFunctor; struct ReadArchiveFunctor; + struct ReadShaderFunctor; // make helper classes friends to get round VS6.0 "issues" friend struct ReadFunctor; @@ -455,6 +479,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced friend struct ReadHeightFieldFunctor; friend struct ReadNodeFunctor; friend struct ReadArchiveFunctor; + friend struct ReadShaderFunctor; ReaderWriter::ReadResult read(const ReadFunctor& readFunctor); ReaderWriter::ReadResult readImplementation(const ReadFunctor& readFunctor,bool useObjectCache); @@ -474,6 +499,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced DotOsgWrapperMap _stateAttrWrapperMap; DotOsgWrapperMap _uniformWrapperMap; DotOsgWrapperMap _nodeWrapperMap; + DotOsgWrapperMap _shaderWrapperMap; DotOsgWrapperMap _classNameWrapperMap; diff --git a/include/osgDB/WriteFile b/include/osgDB/WriteFile index 3823e7a8c..72e8bd63e 100644 --- a/include/osgDB/WriteFile +++ b/include/osgDB/WriteFile @@ -105,6 +105,26 @@ inline bool writeNodeFile(const osg::Node& node, const std::string& filename) return writeNodeFile( node, filename, Registry::instance()->getOptions() ); } +/** Write an osg::Shader to file. + * Return true on success, + * return false on failure. + * Use the Options object to control cache operations and file search paths in osgDB::Registry. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to write the specified file.*/ +extern OSGDB_EXPORT bool writeShaderFile(const osg::Shader& shader, const std::string& filename, const ReaderWriter::Options* options ); + +/** Write an osg::Shader to file. + * Return true on success, + * return false on failure. + * The osgDB::Registry is used to load the appropriate ReaderWriter plugin + * for the filename extension, and this plugin then handles the request + * to write the specified file.*/ +inline bool writeShaderFile(const osg::Shader& shader, const std::string& filename) +{ + return writeShaderFile( shader, filename, Registry::instance()->getOptions() ); +} + } #endif diff --git a/src/osg/Shader.cpp b/src/osg/Shader.cpp index 57c18affe..fcf72e5d5 100644 --- a/src/osg/Shader.cpp +++ b/src/osg/Shader.cpp @@ -110,7 +110,8 @@ Shader::Shader(Type type, const std::string& source) : Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop): osg::Object( rhs, copyop ), _type(rhs._type), - _shaderSource(rhs._shaderSource) + _shaderSource(rhs._shaderSource), + _shaderFileName(rhs._shaderFileName) { } @@ -142,6 +143,9 @@ int Shader::compare(const Shader& rhs) const if( getShaderSource() < rhs.getShaderSource() ) return -1; if( rhs.getShaderSource() < getShaderSource() ) return 1; + + if( getFileName() < rhs.getFileName() ) return -1; + if( rhs.getFileName() < getFileName() ) return 1; return 0; } @@ -171,6 +175,7 @@ bool Shader::loadShaderSourceFromFile( const std::string& fileName ) } osg::notify(osg::INFO)<<"Loading shader source file \""<readShader(*this); +} + osg::Image* Input::readImage(const std::string& fileName) { - return readImageFile(fileName,_options.get()); } @@ -98,6 +102,11 @@ osg::Node* Input::readNode(const std::string& fileName) return readNodeFile(fileName,_options.get()); } +osg::Shader* Input::readShader(const std::string& fileName) +{ + return readShaderFile(fileName,_options.get()); +} + bool Input::read(Parameter value1) { if (value1.valid((*this)[0].getStr())) diff --git a/src/osgDB/Output.cpp b/src/osgDB/Output.cpp index dffa40889..279df61d7 100644 --- a/src/osgDB/Output.cpp +++ b/src/osgDB/Output.cpp @@ -46,8 +46,13 @@ void Output::init() _indentStep = 2; _numIndicesPerLine = 10; _pathNameHint = AS_IS; + _outputTextureFiles = false; _textureFileNameNumber = 0; + + _outputShaderFiles = false; + _shaderFileNameNumber = 0; + _writeOutDefaultValues = false; const char* env = getenv("OSG_WRITE_OUT_DEFAULT_VALUES"); @@ -212,3 +217,19 @@ std::string Output::getTextureFileNameForOutput() return fileName; } +std::string Output::getShaderFileNameForOutput() +{ + std::string fileName = osgDB::getNameLessExtension(_filename); + if (_shaderFileNameNumber>0) + { + std::ostringstream o; + o << '_' << _shaderFileNameNumber; + fileName += o.str(); + } + + fileName += ".glsl"; + ++_shaderFileNameNumber; + + return fileName; +} + diff --git a/src/osgDB/ReadFile.cpp b/src/osgDB/ReadFile.cpp index 7134ddefe..8f9eeb0e1 100644 --- a/src/osgDB/ReadFile.cpp +++ b/src/osgDB/ReadFile.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,14 @@ Image* osgDB::readImageFile(const std::string& filename,const ReaderWriter::Opti return NULL; } +Shader* osgDB::readShaderFile(const std::string& filename,const ReaderWriter::Options* options) +{ + ReaderWriter::ReadResult rr = Registry::instance()->readShader(filename,options); + if (rr.validShader()) return rr.takeShader(); + if (rr.error()) notify(WARN) << rr.message() << std::endl; + return NULL; +} + HeightField* osgDB::readHeightFieldFile(const std::string& filename,const ReaderWriter::Options* options) { @@ -255,6 +264,14 @@ osg::ref_ptr osgDB::readRefImageFile(const std::string& filename,con return NULL; } +osg::ref_ptr osgDB::readRefShaderFile(const std::string& filename,const ReaderWriter::Options* options) +{ + ReaderWriter::ReadResult rr = Registry::instance()->readShader(filename,options); + if (rr.validShader()) return osg::ref_ptr(rr.getShader()); + if (rr.error()) notify(WARN) << rr.message() << std::endl; + return NULL; +} + osg::ref_ptr osgDB::readRefHeightFieldFile(const std::string& filename,const ReaderWriter::Options* options) { ReaderWriter::ReadResult rr = Registry::instance()->readHeightField(filename,options); diff --git a/src/osgDB/ReaderWriter.cpp b/src/osgDB/ReaderWriter.cpp index 96f091639..a362d7515 100644 --- a/src/osgDB/ReaderWriter.cpp +++ b/src/osgDB/ReaderWriter.cpp @@ -21,12 +21,14 @@ osg::Image* ReaderWriter::ReadResult::getImage() { return dynamic_cast(_object.get()); } osg::Node* ReaderWriter::ReadResult::getNode() { return dynamic_cast(_object.get()); } osgDB::Archive* ReaderWriter::ReadResult::getArchive() { return dynamic_cast(_object.get()); } +osg::Shader* ReaderWriter::ReadResult::getShader() { return dynamic_cast(_object.get()); } osg::Object* ReaderWriter::ReadResult::takeObject() { osg::Object* obj = _object.get(); if (obj) { obj->ref(); _object=NULL; obj->unref_nodelete(); } return obj; } osg::Image* ReaderWriter::ReadResult::takeImage() { osg::Image* image=dynamic_cast(_object.get()); if (image) { image->ref(); _object=NULL; image->unref_nodelete(); } return image; } osg::HeightField* ReaderWriter::ReadResult::takeHeightField() { osg::HeightField* hf=dynamic_cast(_object.get()); if (hf) { hf->ref(); _object=NULL; hf->unref_nodelete(); } return hf; } osg::Node* ReaderWriter::ReadResult::takeNode() { osg::Node* node=dynamic_cast(_object.get()); if (node) { node->ref(); _object=NULL; node->unref_nodelete(); } return node; } osgDB::Archive* ReaderWriter::ReadResult::takeArchive() { osgDB::Archive* archive=dynamic_cast(_object.get()); if (archive) { archive->ref(); _object=NULL; archive->unref_nodelete(); } return archive; } +osg::Shader* ReaderWriter::ReadResult::takeShader() { osg::Shader* shader=dynamic_cast(_object.get()); if (shader) { shader->ref(); _object=NULL; shader->unref_nodelete(); } return shader; } ReaderWriter::~ReaderWriter() { diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index f4edcae99..5d90e8d4d 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -431,6 +432,11 @@ void Registry::addDotOsgWrapper(DotOsgWrapper* wrapper) _nodeWrapperMap[name] = wrapper; _nodeWrapperMap[compositeName] = wrapper; } + if (dynamic_cast(proto)) + { + _shaderWrapperMap[name] = wrapper; + _shaderWrapperMap[compositeName] = wrapper; + } } @@ -468,6 +474,7 @@ void Registry::removeDotOsgWrapper(DotOsgWrapper* wrapper) eraseWrapper(_uniformWrapperMap,wrapper); eraseWrapper(_stateAttrWrapperMap,wrapper); eraseWrapper(_nodeWrapperMap,wrapper); + eraseWrapper(_shaderWrapperMap,wrapper); } void Registry::addReaderWriter(ReaderWriter* rw) @@ -1126,6 +1133,31 @@ Node* Registry::readNode(Input& fr) return NULL; } +// +// read image from input iterator. +// +Shader* Registry::readShader(Input& fr) +{ + if (fr[0].matchWord("Use")) + { + if (fr[1].isString()) + { + Shader* shader = dynamic_cast(fr.getObjectForUniqueID(fr[1].getStr())); + if (shader) fr+=2; + return shader; + } + else return NULL; + + } + + osg::Object* obj = readObject(_shaderWrapperMap,fr); + osg::Shader* shader = dynamic_cast(obj); + if (shader) return shader; + else if (obj) obj->unref(); + + return NULL; +} + // // Write object to output // @@ -1313,6 +1345,15 @@ struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor }; +struct Registry::ReadShaderFunctor : public Registry::ReadFunctor +{ + ReadShaderFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {} + + virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const { return rw.readShader(_filename, _options); } + virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); } + virtual bool isValid(osg::Object* object) const { return dynamic_cast(object)!=0; } +}; + void Registry::addArchiveExtension(const std::string ext) { for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin(); @@ -1792,6 +1833,58 @@ ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,con return results.front(); } +ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const ReaderWriter::Options* options) +{ + return readImplementation(ReadShaderFunctor(fileName, options), + options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_SHADERS)!=0: false); +} + +ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const ReaderWriter::Options* options) +{ + // record the errors reported by readerwriters. + typedef std::vector Results; + Results results; + + // first attempt to load the file from existing ReaderWriter's + AvailableReaderWriterIterator itr(_rwList); + for(;itr.valid();++itr) + { + ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); + if (rr.success()) return rr; + else results.push_back(rr); + } + + results.clear(); + + // now look for a plug-in to save the file. + std::string libraryName = createLibraryNameForFile(fileName); + if (loadLibrary(libraryName)) + { + for(;itr.valid();++itr) + { + ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options); + if (rr.success()) return rr; + else results.push_back(rr); + } + } + + if (results.empty()) + { + return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\"."); + } + + if (results.front().message().empty()) + { + switch(results.front().status()) + { + case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break; + case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break; + default: break; + } + } + + return results.front(); +} void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { diff --git a/src/osgDB/WriteFile.cpp b/src/osgDB/WriteFile.cpp index 0417997d3..e61e57fce 100644 --- a/src/osgDB/WriteFile.cpp +++ b/src/osgDB/WriteFile.cpp @@ -53,3 +53,11 @@ bool osgDB::writeNodeFile(const Node& node,const std::string& filename, const Re if (wr.error()) notify(WARN) << "Error writing file " << filename << ": " << wr.message() << std::endl; return wr.success(); } + +bool osgDB::writeShaderFile(const Shader& shader,const std::string& filename, const ReaderWriter::Options* options ) +{ + ReaderWriter::WriteResult wr = Registry::instance()->writeShader( shader, filename, options ); + if (wr.error()) notify(WARN) << "Error writing file " << filename << ": " << wr.message() << std::endl; + return wr.success(); +} + diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index 0bd57a8aa..663b20294 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -59,6 +59,11 @@ ADD_SUBDIRECTORY(ive) # ADD_SUBDIRECTORY(cfg) +############################################################ +# +# Shader plugins +# +ADD_SUBDIRECTORY(glsl) ############################################################ # diff --git a/src/osgPlugins/glsl/CMakeLists.txt b/src/osgPlugins/glsl/CMakeLists.txt new file mode 100644 index 000000000..2a3fbaffd --- /dev/null +++ b/src/osgPlugins/glsl/CMakeLists.txt @@ -0,0 +1,6 @@ +#this file is automatically generated + + +SET(TARGET_SRC ReaderWriterGLSL.cpp ) +#### end var setup ### +SETUP_PLUGIN(glsl) diff --git a/src/osgPlugins/glsl/ReaderWriterGLSL.cpp b/src/osgPlugins/glsl/ReaderWriterGLSL.cpp new file mode 100644 index 000000000..5912fc25b --- /dev/null +++ b/src/osgPlugins/glsl/ReaderWriterGLSL.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +#include +#include +#include + + +class ReaderWriterGLSL : public osgDB::ReaderWriter +{ + public: + virtual const char* className() const { return "GLSL Shader Reader"; } + virtual bool acceptsExtension(const std::string& extension) const + { + return osgDB::equalCaseInsensitive(extension,"glsl") || osgDB::equalCaseInsensitive(extension,"gl"); + } + + virtual ReadResult readShader(std::istream& fin,const Options* options) const + { + // read source + fin.seekg(0, std::ios::end); + int length = fin.tellg(); + char *text = new char[length + 1]; + fin.seekg(0, std::ios::beg); + fin.read(text, length); + text[length] = '\0'; + + // create shader + osg::Shader* shader = new osg::Shader(); + shader->setShaderSource( text ); + + // check options which can define the type of the shader program + if (options) + { + if (options->getOptionString().find("fragment")!=std::string::npos) shader->setType(osg::Shader::FRAGMENT); + if (options->getOptionString().find("vertex")!=std::string::npos) shader->setType(osg::Shader::VERTEX); + if (options->getOptionString().find("geometry")!=std::string::npos) shader->setType(osg::Shader::GEOMETRY); + } + + // cleanup + delete [] text; + + // return valid shader + return shader; + } + + virtual ReadResult readShader(const std::string& file, const osgDB::ReaderWriter::Options* options) const + { + std::string ext = osgDB::getLowerCaseFileExtension(file); + if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + std::string fileName = osgDB::findDataFile( file, options ); + if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; + + std::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); + if(!istream) return ReadResult::FILE_NOT_HANDLED; + ReadResult rr = readShader(istream, options); + if(rr.validShader()) rr.getShader()->setFileName(file); + return rr; + } + + virtual WriteResult writeShader(const osg::Shader& shader,std::ostream& fout,const Options* = NULL) const + { + // get shader source + std::string source = shader.getShaderSource(); + + // write source to file + fout << source; + + // return all things went fine + return WriteResult::FILE_SAVED; + } + + virtual WriteResult writeShader(const osg::Shader &shader,const std::string& fileName, const osgDB::ReaderWriter::Options*) const + { + std::string ext = osgDB::getFileExtension(fileName); + if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; + + std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); + if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; + + return writeShader(shader, fout); + } +}; + +// now register with Registry to instantiate the above +// reader/writer. +REGISTER_OSGPLUGIN(glsl, ReaderWriterGLSL) diff --git a/src/osgPlugins/osg/Shader.cpp b/src/osgPlugins/osg/Shader.cpp index 11de40d97..645602072 100644 --- a/src/osgPlugins/osg/Shader.cpp +++ b/src/osgPlugins/osg/Shader.cpp @@ -8,6 +8,7 @@ #include "osgDB/Input" #include "osgDB/Output" #include "osgDB/FileUtils" +#include "osgDB/WriteFile" using namespace osg; using namespace osgDB; @@ -84,24 +85,48 @@ bool Shader_writeLocalData(const Object& obj,Output& fw) fw.indent() << "type " << shader.getTypename() << std::endl; - // split source text into individual lines - std::vector lines; - std::istringstream iss(shader.getShaderSource()); - std::string line; - while (std::getline(iss, line)) { - lines.push_back(line); + // osg::notify(osg::NOTICE)<<"fw.getOutputShaderFiles()="< lines; + std::istringstream iss(shader.getShaderSource()); + std::string line; + while (std::getline(iss, line)) { + lines.push_back(line); + } - fw.indent() << "code {\n"; - fw.moveIn(); - - std::vector::const_iterator j; - for (j=lines.begin(); j!=lines.end(); ++j) { - fw.indent() << fw.wrapString(*j) << "\n"; + fw.indent() << "code {\n"; + fw.moveIn(); + + std::vector::const_iterator j; + for (j=lines.begin(); j!=lines.end(); ++j) { + fw.indent() << fw.wrapString(*j) << "\n"; + } + + fw.moveOut(); + fw.indent() << "}\n"; } - fw.moveOut(); - fw.indent() << "}\n"; - return true; } diff --git a/src/osgWrappers/osg/Shader.cpp b/src/osgWrappers/osg/Shader.cpp index e202c1b44..d275fcec9 100644 --- a/src/osgWrappers/osg/Shader.cpp +++ b/src/osgWrappers/osg/Shader.cpp @@ -107,6 +107,16 @@ BEGIN_OBJECT_REFLECTOR(osg::Shader) __C5_char_P1__getTypename, "Get the Shader type as a descriptive string. ", ""); + I_Method1(void, setFileName, IN, const std::string &, fileName, + Properties::NON_VIRTUAL, + __void__setFileName__C5_std_string_R1, + "Set file name for the shader source code. ", + ""); + I_Method0(const std::string &, getFileName, + Properties::NON_VIRTUAL, + __C5_std_string_R1__getFileName, + "Get filename to which the shader source code belongs. ", + ""); I_Method1(void, resizeGLObjectBuffers, IN, unsigned int, maxSize, Properties::VIRTUAL, __void__resizeGLObjectBuffers__unsigned_int, @@ -175,6 +185,9 @@ BEGIN_OBJECT_REFLECTOR(osg::Shader) __bool__removeProgramRef__osg_Program_P1, "", ""); + I_SimpleProperty(const std::string &, FileName, + __C5_std_string_R1__getFileName, + __void__setFileName__C5_std_string_R1); I_SimpleProperty(const std::string &, ShaderSource, __C5_std_string_R1__getShaderSource, __void__setShaderSource__C5_std_string_R1); diff --git a/src/osgWrappers/osgDB/Input.cpp b/src/osgWrappers/osgDB/Input.cpp index f211532f8..84ac300b6 100644 --- a/src/osgWrappers/osgDB/Input.cpp +++ b/src/osgWrappers/osgDB/Input.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Input) __osg_Node_P1__readNode, "", ""); + I_Method0(osg::Shader *, readShader, + Properties::VIRTUAL, + __osg_Shader_P1__readShader, + "", + ""); I_Method1(osg::Object *, readObject, IN, const std::string &, fileName, Properties::VIRTUAL, __osg_Object_P1__readObject__C5_std_string_R1, @@ -101,6 +107,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Input) __osg_Node_P1__readNode__C5_std_string_R1, "", ""); + I_Method1(osg::Shader *, readShader, IN, const std::string &, fileName, + Properties::VIRTUAL, + __osg_Shader_P1__readShader__C5_std_string_R1, + "", + ""); I_Method1(osg::Object *, getObjectForUniqueID, IN, const std::string &, uniqueID, Properties::VIRTUAL, __osg_Object_P1__getObjectForUniqueID__C5_std_string_R1, diff --git a/src/osgWrappers/osgDB/ReaderWriter.cpp b/src/osgWrappers/osgDB/ReaderWriter.cpp index d9f935e41..3a8137571 100644 --- a/src/osgWrappers/osgDB/ReaderWriter.cpp +++ b/src/osgWrappers/osgDB/ReaderWriter.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter) __ReadResult__readNode__C5_std_string_R1__C5_Options_P1, "", ""); + I_MethodWithDefaults2(osgDB::ReaderWriter::ReadResult, readShader, IN, const std::string &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, + Properties::VIRTUAL, + __ReadResult__readShader__C5_std_string_R1__C5_Options_P1, + "", + ""); I_MethodWithDefaults3(osgDB::ReaderWriter::WriteResult, writeObject, IN, const osg::Object &, x, , IN, const std::string &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, Properties::VIRTUAL, __WriteResult__writeObject__C5_osg_Object_R1__C5_std_string_R1__C5_Options_P1, @@ -123,6 +129,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter) __WriteResult__writeNode__C5_osg_Node_R1__C5_std_string_R1__C5_Options_P1, "", ""); + I_MethodWithDefaults3(osgDB::ReaderWriter::WriteResult, writeShader, IN, const osg::Shader &, x, , IN, const std::string &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, + Properties::VIRTUAL, + __WriteResult__writeShader__C5_osg_Shader_R1__C5_std_string_R1__C5_Options_P1, + "", + ""); I_MethodWithDefaults2(osgDB::ReaderWriter::ReadResult, readObject, IN, std::istream &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, Properties::VIRTUAL, __ReadResult__readObject__std_istream_R1__C5_Options_P1, @@ -143,6 +154,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter) __ReadResult__readNode__std_istream_R1__C5_Options_P1, "", ""); + I_MethodWithDefaults2(osgDB::ReaderWriter::ReadResult, readShader, IN, std::istream &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, + Properties::VIRTUAL, + __ReadResult__readShader__std_istream_R1__C5_Options_P1, + "", + ""); I_MethodWithDefaults3(osgDB::ReaderWriter::WriteResult, writeObject, IN, const osg::Object &, x, , IN, std::ostream &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, Properties::VIRTUAL, __WriteResult__writeObject__C5_osg_Object_R1__std_ostream_R1__C5_Options_P1, @@ -163,6 +179,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter) __WriteResult__writeNode__C5_osg_Node_R1__std_ostream_R1__C5_Options_P1, "", ""); + I_MethodWithDefaults3(osgDB::ReaderWriter::WriteResult, writeShader, IN, const osg::Shader &, x, , IN, std::ostream &, x, , IN, const osgDB::ReaderWriter::Options *, x, NULL, + Properties::VIRTUAL, + __WriteResult__writeShader__C5_osg_Shader_R1__std_ostream_R1__C5_Options_P1, + "", + ""); END_REFLECTOR BEGIN_ENUM_REFLECTOR(osgDB::ReaderWriter::Options::CacheHintOptions) @@ -173,6 +194,7 @@ BEGIN_ENUM_REFLECTOR(osgDB::ReaderWriter::Options::CacheHintOptions) I_EnumLabel(osgDB::ReaderWriter::Options::CACHE_HEIGHTFIELDS); I_EnumLabel(osgDB::ReaderWriter::Options::CACHE_ARCHIVES); I_EnumLabel(osgDB::ReaderWriter::Options::CACHE_OBJECTS); + I_EnumLabel(osgDB::ReaderWriter::Options::CACHE_SHADERS); I_EnumLabel(osgDB::ReaderWriter::Options::CACHE_ALL); END_REFLECTOR @@ -344,6 +366,11 @@ BEGIN_VALUE_REFLECTOR(osgDB::ReaderWriter::ReadResult) __osgDB_Archive_P1__getArchive, "", ""); + I_Method0(osg::Shader *, getShader, + Properties::NON_VIRTUAL, + __osg_Shader_P1__getShader, + "", + ""); I_Method0(bool, validObject, Properties::NON_VIRTUAL, __bool__validObject, @@ -369,6 +396,11 @@ BEGIN_VALUE_REFLECTOR(osgDB::ReaderWriter::ReadResult) __bool__validArchive, "", ""); + I_Method0(bool, validShader, + Properties::NON_VIRTUAL, + __bool__validShader, + "", + ""); I_Method0(osg::Object *, takeObject, Properties::NON_VIRTUAL, __osg_Object_P1__takeObject, @@ -394,6 +426,11 @@ BEGIN_VALUE_REFLECTOR(osgDB::ReaderWriter::ReadResult) __osgDB_Archive_P1__takeArchive, "", ""); + I_Method0(osg::Shader *, takeShader, + Properties::NON_VIRTUAL, + __osg_Shader_P1__takeShader, + "", + ""); I_Method0(std::string &, message, Properties::NON_VIRTUAL, __std_string_R1__message, @@ -449,6 +486,9 @@ BEGIN_VALUE_REFLECTOR(osgDB::ReaderWriter::ReadResult) I_SimpleProperty(osg::Object *, Object, __osg_Object_P1__getObject, 0); + I_SimpleProperty(osg::Shader *, Shader, + __osg_Shader_P1__getShader, + 0); END_REFLECTOR BEGIN_ENUM_REFLECTOR(osgDB::ReaderWriter::WriteResult::WriteStatus) diff --git a/src/osgWrappers/osgDB/Registry.cpp b/src/osgWrappers/osgDB/Registry.cpp index 502cf4ff4..bae7d2af8 100644 --- a/src/osgWrappers/osgDB/Registry.cpp +++ b/src/osgWrappers/osgDB/Registry.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -179,6 +180,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Registry) __osg_Node_P1__readNode__Input_R1, "", ""); + I_Method1(osg::Shader *, readShader, IN, osgDB::Input &, fr, + Properties::NON_VIRTUAL, + __osg_Shader_P1__readShader__Input_R1, + "", + ""); I_Method2(bool, writeObject, IN, const osg::Object &, obj, IN, osgDB::Output &, fw, Properties::NON_VIRTUAL, __bool__writeObject__C5_osg_Object_R1__Output_R1, @@ -249,6 +255,16 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Registry) __ReaderWriter_ReadResult__readNodeImplementation__C5_std_string_R1__C5_ReaderWriter_Options_P1, "", ""); + I_Method2(osgDB::ReaderWriter::ReadResult, readShader, IN, const std::string &, fileName, IN, const osgDB::ReaderWriter::Options *, options, + Properties::NON_VIRTUAL, + __ReaderWriter_ReadResult__readShader__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); + I_Method2(osgDB::ReaderWriter::ReadResult, readShaderImplementation, IN, const std::string &, fileName, IN, const osgDB::ReaderWriter::Options *, options, + Properties::NON_VIRTUAL, + __ReaderWriter_ReadResult__readShaderImplementation__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); I_Method1(void, setWriteFileCallback, IN, osgDB::Registry::WriteFileCallback *, cb, Properties::NON_VIRTUAL, __void__setWriteFileCallback__WriteFileCallback_P1, @@ -304,6 +320,16 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Registry) __ReaderWriter_WriteResult__writeNodeImplementation__C5_osg_Node_R1__C5_std_string_R1__C5_ReaderWriter_Options_P1, "", ""); + I_Method3(osgDB::ReaderWriter::WriteResult, writeShader, IN, const osg::Shader &, obj, IN, const std::string &, fileName, IN, const osgDB::ReaderWriter::Options *, options, + Properties::NON_VIRTUAL, + __ReaderWriter_WriteResult__writeShader__C5_osg_Shader_R1__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); + I_Method3(osgDB::ReaderWriter::WriteResult, writeShaderImplementation, IN, const osg::Shader &, obj, IN, const std::string &, fileName, IN, const osgDB::ReaderWriter::Options *, options, + Properties::NON_VIRTUAL, + __ReaderWriter_WriteResult__writeShaderImplementation__C5_osg_Shader_R1__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); I_Method1(void, setCreateNodeFromImage, IN, bool, flag, Properties::NON_VIRTUAL, __void__setCreateNodeFromImage__bool, @@ -559,6 +585,11 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Registry::ReadFileCallback) __ReaderWriter_ReadResult__readNode__C5_std_string_R1__C5_ReaderWriter_Options_P1, "", ""); + I_Method2(osgDB::ReaderWriter::ReadResult, readShader, IN, const std::string &, filename, IN, const osgDB::ReaderWriter::Options *, options, + Properties::VIRTUAL, + __ReaderWriter_ReadResult__readShader__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); END_REFLECTOR BEGIN_ABSTRACT_OBJECT_REFLECTOR(osgDB::Registry::ReadFunctor) @@ -611,5 +642,10 @@ BEGIN_OBJECT_REFLECTOR(osgDB::Registry::WriteFileCallback) __ReaderWriter_WriteResult__writeNode__C5_osg_Node_R1__C5_std_string_R1__C5_ReaderWriter_Options_P1, "", ""); + I_Method3(osgDB::ReaderWriter::WriteResult, writeShader, IN, const osg::Shader &, obj, IN, const std::string &, fileName, IN, const osgDB::ReaderWriter::Options *, options, + Properties::VIRTUAL, + __ReaderWriter_WriteResult__writeShader__C5_osg_Shader_R1__C5_std_string_R1__C5_ReaderWriter_Options_P1, + "", + ""); END_REFLECTOR