本文为了分析osg插件的内部实现,举了一个ReaderWriterJPEG插件的例子进行分析,本文代码全为C++代码
osg通过插件的方式读取写入文件
用osg的jpeg插件举例
文件OSGsrcosgPluginsjpegReaderWriterJPEG.cpp 中定义了类:
class ReaderWriterJPEG : public osgDB::ReaderWriter
一、插件读取部分
在virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const函数中
1.首先将文件以二进制流的方式读取进来
osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
2.然后再将二进制流通过算法解析成读取结果:ReadResult
ReadResult rr = readJPGStream(istream);
那这个ReadResult是个什么东西,这个要怎么用,我们来分析一下这个类
osgDB/ReaderWriter 头文件中
声明并定义了osgDB::ReaderWriter类
在这个类中声明并定义了ReadResult类
1 class OSGDB_EXPORT ReadResult 2 { 3 public: 4 5 enum ReadStatus 6 { 7 NOT_IMPLEMENTED, //!< read*() method not implemented in concrete ReaderWriter. 8 FILE_NOT_HANDLED, //!< File is not appropriate for this file reader, due to some incompatibility, but *not* a read error. 9 FILE_NOT_FOUND, //!< File could not be found or could not be read. 10 ERROR_IN_READING_FILE, //!< File found, loaded, but an error was encountered during processing. 11 FILE_LOADED, //!< File successfully found, loaded, and converted into osg. 12 FILE_LOADED_FROM_CACHE, //!< File found in cache and returned. 13 FILE_REQUESTED, //!< Asynchronous file read has been requested, but returning immediately, keep polling plugin until file read has been completed. 14 INSUFFICIENT_MEMORY_TO_LOAD //!< File found but not loaded because estimated required memory surpasses available memory. 15 }; 16 17 ReadResult(ReadStatus status=FILE_NOT_HANDLED):_status(status) {} 18 ReadResult(const std::string& m):_status(ERROR_IN_READING_FILE),_message(m) {} 19 20 ReadResult(osg::Object* obj, ReadStatus status=FILE_LOADED):_status(status),_object(obj) {} 21 22 template<class T> 23 ReadResult(const osg::ref_ptr<T>& obj, ReadStatus status=FILE_LOADED):_status(status),_object(obj.get()) {} 24 25 ReadResult(const ReadResult& rr):_status(rr._status),_message(rr._message),_object(rr._object) {} 26 ReadResult& operator = (const ReadResult& rr) { if (this==&rr) return *this; _status=rr._status; _message=rr._message;_object=rr._object; return *this; } 27 28 bool operator < (const ReadResult& rhs) const { return _status < rhs._status; } 29 30 osg::Object* getObject(); 31 osg::Image* getImage(); 32 osg::HeightField* getHeightField(); 33 osg::Node* getNode(); 34 osgDB::Archive* getArchive(); 35 osg::Shader* getShader(); 36 osg::Script* getScript(); 37 38 bool validObject() { return _object.valid(); } 39 bool validImage() { return getImage()!=0; } 40 bool validHeightField() { return getHeightField()!=0; } 41 bool validNode() { return getNode()!=0; } 42 bool validArchive() { return getArchive()!=0; } 43 bool validShader() { return getShader()!=0; } 44 bool validScript() { return getScript()!=0; } 45 46 osg::Object* takeObject(); 47 osg::Image* takeImage(); 48 osg::HeightField* takeHeightField(); 49 osg::Node* takeNode(); 50 osgDB::Archive* takeArchive(); 51 osg::Shader* takeShader(); 52 osg::Script* takeScript(); 53 54 std::string& message() { return _message; } 55 const std::string& message() const { return _message; } 56 57 ReadStatus status() const { return _status; } 58 bool success() const { return _status==FILE_LOADED || _status==FILE_LOADED_FROM_CACHE ; } 59 bool loadedFromCache() const { return _status==FILE_LOADED_FROM_CACHE; } 60 bool error() const { return _status==ERROR_IN_READING_FILE; } 61 bool notHandled() const { return _status==FILE_NOT_HANDLED || _status==NOT_IMPLEMENTED; } 62 bool notFound() const { return _status==FILE_NOT_FOUND; } 63 bool notEnoughMemory() const { return _status==INSUFFICIENT_MEMORY_TO_LOAD; } 64 65 protected: 66 67 ReadStatus _status; 68 std::string _message; 69 osg::ref_ptr<osg::Object> _object; 70 71 };
这个ReadResult支持osg读取多种类型的数据,有7种类型:目标物、图片、高度场、节点、文档、着色器、脚本。
1 osg::Object* getObject(); 2 osg::Image* getImage(); 3 osg::HeightField* getHeightField(); 4 osg::Node* getNode(); 5 osgDB::Archive* getArchive(); 6 osg::Shader* getShader(); 7 osg::Script* getScript();
接口定义:
1 osg::Object* ReaderWriter::ReadResult::getObject() { return _object.get(); } 2 osg::Image* ReaderWriter::ReadResult::getImage() { return dynamic_cast<osg::Image*>(_object.get()); } 3 osg::HeightField* ReaderWriter::ReadResult::getHeightField() { return dynamic_cast<osg::HeightField*>(_object.get()); } 4 osg::Node* ReaderWriter::ReadResult::getNode() { return dynamic_cast<osg::Node*>(_object.get()); } 5 osgDB::Archive* ReaderWriter::ReadResult::getArchive() { return dynamic_cast<osgDB::Archive*>(_object.get()); } 6 osg::Shader* ReaderWriter::ReadResult::getShader() { return dynamic_cast<osg::Shader*>(_object.get()); } 7 osg::Script* ReaderWriter::ReadResult::getScript() { return dynamic_cast<osg::Script*>(_object.get()); }
通过接口定义可以看到这里所有类型都是由osg::Object指针强转过来的,所以ReadResult即可支持了需要读取的所有类型。
读取的函数readJPGStream需要实现的其实就是将数据流std::ifstream转成对应的osg::Image数据。
二、插件写入部分
在 virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const
1.先将文件输出流打开
osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
2.将数据写入数据流
WriteResult::WriteStatus ws = write_JPEG_file(fout, *(tmp_img.get()), getQuality(options));
这个写入结果WriteResult就简单很多,它不关心写入的数据类型,只关注写入成功与否,这里不用去仔细分析。
这里的write_JPEG_file函数就完成了,从osg::Image到数据流std::ofstream的转换
备注:
osgDB下面的两个流就是调用std的fstream
class OSGDB_EXPORT ifstream : public std::ifstream
class OSGDB_EXPORT ofstream : public std::ofstream
readJPGStream和write_JPEG_file里面的实现除了osg::Image的转换,调用的都是jpeg的第三方库进行操作,这里不去分析。