上一章节:
一、文件读取原理
ReadNodeFile,读取流程:
二、实现一个简单的读取器
仿造ReaderWriterOSG.CPP原码,自己实现一个文件读写器的dll, 该dll名为osgdb_fs.dll,并用这个文件读写器,读取后缀为.fs自定义模型文件
项目输出为类型设置为dll:
输出路径改为:
编译生成路径如下:
再将你编译好的这个库放到osg的bin目录下,就可以通过osgviewer 查看之前定义的sphere.fs文件。
读取器ReadFs.cpp代码如下:
/**
自定义OSG 文件读写器
**/
#include <windows.h>
#include <iostream>
#include <sstream>
#include <osg/Image>
#include <osg/Group>
#include <osg/Notify>
#include <osg/Version>
#include <osg/Geode>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/fstream>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
using namespace osg;
using namespace osgDB;
class FSReaderWriter : public ReaderWriter
{
public:
mutable OpenThreads::Mutex _mutex;
mutable bool _wrappersLoaded;
FSReaderWriter()
{
supportsExtension("fs", "FreeSouth 's format");
}
virtual const char* className() const { return "FSReaderWriter"; }
bool loadWrappers() const
{
#ifndef OSG_LIBRARY_STATIC
if (_wrappersLoaded) return true;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
if (_wrappersLoaded) return true;
std::string filename = osgDB::Registry::instance()->createLibraryNameForExtension("fsreadwrite_osg");
if (osgDB::Registry::instance()->loadLibrary(filename) == osgDB::Registry::LOADED)
{
OSG_INFO << "FSReaderWriter wrappers loaded OK" << std::endl;
_wrappersLoaded = true;
return true;
}
else
{
OSG_NOTICE << "FSReaderWriter wrappers failed to load" << std::endl;
_wrappersLoaded = true;
return false;
}
#else
return true;
#endif
}
virtual ReadResult readNode(const std::string& file, const Options* opt) const
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
std::string fileName = osgDB::findDataFile(file, opt);
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
osgDB::ifstream fin(fileName.c_str());
if (!fin)
{
std::cerr << "Failed to open file: " << fileName << std::endl;
return ReadResult::FILE_NOT_FOUND;
}
return readNode(fin, opt);
}
virtual ReadResult readNode(std::istream& fin, const Options* options) const
{
Input fr;
fr.attach(&fin);
osg::ref_ptr<osg::Geode> gnode = new osg::Geode;
osg::Vec3 center;
float radius;
// load all nodes in file, placing them in a group.
while (!fr.eof())
{
// 匹配文件中中心点,跟半径
if (fr.matchSequence("%f%f%f%f"))
{
fr.readSequence(center);
fr.readSequence(radius);
std::cout << "Center is:" << center.x() << " " << center.y() <<" "<< center.z() << std::endl;
std::cout << "Radius:" << radius << std::endl;
gnode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(center, radius)));
}
else {
std::cout << "fr is NULL" << std::endl;
++fr;
}
}
return gnode;
}
};
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(fs, FSReaderWriter)
再切换到编写一个exe,程序加载使用这个读写器,读取文件,main.cpp 如下:
#include <windows.h>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
int main()
{
osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来
osg::ref_ptr<osg::Group> group = new osg::Group;
group->addChild(osgDB::readNodeFile("sphere.fs")); // 自定义的fs文件
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setUpViewInWindow(100, 100, 1500, 1000);
viewer->setSceneData(group.get());
viewer->run();
return 0;
}
运行结果如下图:
三、实现获取读取OSG文件进度功能
文件读取流程如下:
通过从写文件读取流的方式进行:
代码仓库:
代码如下:
/**
自定义文件读取,并实时获得读取进度
**/
#include <windows.h>
#include <iostream>
#include <fstream>
#include <streambuf>
#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
template<class _Elem, class _Traits = std::char_traits<_Elem>>
class ReadStream :public std::basic_filebuf<_Elem, _Traits>
{
public:
using int_type = typename _Traits::int_type;
ReadStream(const std::string& fileName):_itotalSize(0)
{
if (this->open(fileName.c_str(), std::ios_base::in | std::ios_base::binary))
{
//std::cout << "Read Success" << std::endl;
// 打开文件时,会获得文件指针,将文件指针移动到文件末尾;从而获取文件大小
_itotalSize = this->pubseekoff(0, std::ios_base::end, std::ios_base::in);
std::cout << "file size:" <<_itotalSize << std::endl; // 获取文件大小字节数
// 再回置指针到文件开头
this->pubseekoff(0, std::ios_base::beg, std::ios_base::in);
}
}
protected:
int_type uflow() override // 读取文件时,会不断的执行这个文件
{
int_type value = std::basic_filebuf<_Elem, _Traits>::uflow();
_iCurSize += (this->egptr() - this->gptr()); // 用结尾指针减去当前读取的指针, 获取当前读取到的字符数;
std::cout << 100 * ((float)_iCurSize/_itotalSize)<<"%" << std::endl;
return value;
}
int _iCurSize{ 0 };
int _itotalSize{0};
};
class ReadFileCB :public osgDB::Registry::ReadFileCallback
{
public:
typedef ReadStream<char> ReadStreamString;
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* opt) override {
std::cout << "Use our function" << std::endl;
// 第一步:获取OSG、IVE ReaderWriter
std::string ext = osgDB::getLowerCaseFileExtension(file);
// 用扩展名获取 ReaderWriter
osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
if (!rw)
{
return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
}
std::string fileName = osgDB::findDataFile(file, opt);
if (fileName.empty())
{
return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
}
//osgDB::ifstream fin(fileName.c_str());
ReadStreamString *fin = new ReadStreamString(fileName);
if (fin->is_open())
{
std::cout << "Using default format readerwriter" << std::endl;
//rw->readNode(fin);
std::istream stream(fin);
// 调用接受 std::istream 的 readNode 重载版本
osgDB::ReaderWriter::ReadResult result = rw->readNode(stream, opt);
if (result.success()) {
return result;
}
}
else
{
return osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE;
}
return osgDB::Registry::instance()->readNodeImplementation(file, opt);
}
};
int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setUpViewInWindow(100, 100, 1500, 1000);
osgDB::Registry::instance()->setReadFileCallback(new ReadFileCB);
viewer->setSceneData(osgDB::readNodeFile("glider.osg"));
viewer->run();
return 0;
}
四、osgDB写文件
核心函数接口,osgDB::Registry::RwriteNode();
代码仓库:
实例代码:
/**
osg 写文件
**/
#include <windows.h>
#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
int main()
{
osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setUpViewInWindow(100, 100, 1500, 1000);
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("sphere.fs"); // 读取自定义文件
viewer->setSceneData(osgDB::readNodeFile("sphere.fs"));
osg::Node& writeNode = (*(node)); // 将读到的文件节点,写道指定目录下的文件里
osgDB::Registry::instance()->writeNode(writeNode, "D:/test.osg", osgDB::Registry::instance()->getOptions());
return viewer->run();
}
源代码:
/**
osg 写文件
**/
#include <windows.h>
#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <osg/Matrixd>
#include <osg/MatrixTransform>
int main()
{
osgDB::Registry::instance()->addFileExtensionAlias("fs", "fs");//将文件扩展名与dll名关联起来
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setUpViewInWindow(100, 100, 1500, 1000);
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("sphere.fs"); // 读取自定义文件
viewer->setSceneData(osgDB::readNodeFile("sphere.fs"));
osg::Node& writeNode = (*(node)); // 将读到的文件节点,写道指定目录下的文件里
osgDB::Registry::instance()->writeNode(writeNode, "D:/test.fs", osgDB::Registry::instance()->getOptions());
osg::ref_ptr<osg::Group> gp = new osg::Group;
osg::ref_ptr<osg::Node> node1 = new osg::Node;
osg::ref_ptr<osg::MatrixTransform> mx = new osg::MatrixTransform;
node1 = osgDB::readNodeFile("glider.osg");
mx->addChild(node1.get());
mx->setMatrix(osg::Matrix::translate(1.0, 0.0, 0.0));
gp->addChild(mx);
gp->addChild(node1);
viewer->setSceneData(gp);
osg::Node& writeNode1 = (*(gp)); // 将读到的文件节点,写道指定目录下的文件里
osgDB::Registry::instance()->writeNode(writeNode1, "D:/tt.osg", osgDB::Registry::instance()->getOptions());
return viewer->run();
}
osgArchive:将很多osg,文件压缩到一个包文件内。
例如:
# 将两个模型文件压缩到一个ive 文件中
osgconv cow.osg glider.osg d:\\g.ive