[osg]osgDB的加载机制,使用3DS插件做参考(转,整理现有osgDB资料)
参考:http://blog.sina.com.cn/s/blog_7cdaf8b60102uzu3.html
http://blog.csdn.net/wang15061955806/article/details/51011466
osgDB机制概述
osgDB库允许用户程序加载、使用和写入3D数据库,它采用插件管理的架构,可以支持大量常见的2D图形和3D图形文件格式。osgDB负责维护插件的信息注册表,并负责检查将要被载入的OSG插件接口的合法性。由于大型3D地形数据通常是多段数据块的组合体。因此,应用程序从文件中读取各部分数据库信息时,需要在不干扰当前渲染的前提下以后台线程的方式进行,osgDB::DatabaseParger提供了这样的功能。
插件的不足之处在于,其设计过程中只能遵循固定的格式和工作模式进行编程,它的一切行为都无法超出主系统所提供的公共接口规范。
osg插件是一组动态链接库,其中实现了osgDB头文件ReaderWriter定义的接口。OSG不可能查找并加载所有的插件以获取它们支持的文件格式,这样,在程序启动时将会是一个很大的开销。因此,OSG使用职责链(Chain of Responsibility)的设计模式,以加载尽量少的插件。当用户程序尝试使用osgDB读取或写入文件时,OSG将按照如下步骤来查找合适的插件:
1.OSG搜索已注册的插件列表,查找支持文件格式的插件。开始时已注册插件列表仅包含了Registry类构造函数中注册的插件。如果OSG找到了可以支持此文件格式的插件,并成功执行了I/O操作,那么它将返回相应的数据。
2.如果没有发现可以支持此格式的已注册插件,或者I/0操作失败,那么OSG将根据前面所述的文件命名规则创建插件文件的名称,并尝试读取相应的插件库。如果读取成功,OSG将添加此插件到已注册插件列表中。
3.OSG将重复步骤(1),如果文件I/O的操作再次失败,OSG将返回失败信息。
用3DS插件做说明:
先就3ds格式模型做一个简要说明,在加载3ds模型时,会根据模型格式在电脑的所有环境变量中找到对应的dll文件(osgdb_3ds.dll),并试着读取osgdb_3ds.dll,加载并成功执行osgdb_3ds.dll的宏定义,就会成功解析文件。
程序中代码的实现顺序如下图所示:
查找读取插件流程
函数执行顺序:
osg::Node *node=osgDB::readNodeFile(某种类型的文件路径),这个语句是osg读取节点数据常用的函数,下面对这个函数进行跟踪,简单介绍下数据的处理过程,方面自己对osgDB的插件进行简单的修改,供自己进行简单的修改;
osg::Node *readNodeFile(const std::string &filename) //函数所在位置osgDB/ReadFile,该函数属于文件作用域,调用文件中的另一个函数
{
//函数所在位置osgDB/ReadFile,该函数只是在原来的基础上,调用了osgDB/Registry的文件中的一个Registry单例,获取的是option,默认为空
return readNodeFile(filename,osgDB::Registry::instance()->getOptions());//osgDB/ReadFile ①
}
//①的具体实现,该函数的作用是调用osgDB/Registry的单例,进行数据的解析,参数options默认为空.
Node* osgDB::readNodeFile(const std::string& filename,const Options* options)
{
ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename,options);②
}
//②的具体实现,由于options参数为空,并且_readFileCallback为空,所以函数直接执行③
ReaderWriter::ReadResult readNode(const std::string& fileName,const Options* options, bool buildKdTreeIfRequired=true)
{
ReaderWriter::ReadResult result; result = readNodeImplementation(fileName,options);③
}
//③的具体实现,直接执行函数④
ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options)
{
return readImplementation(ReadNodeFuncto(fileName,options),Options::CACHE_NODES);④
}
//④的具体实现,由于readFunctor的options为空,所以函数在中间没有做实际的数据处理,直接执行⑤
ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint)
{
std::string file(readFunctor._filename);
ReaderWriter::ReadResult rr = read(readFunctor);⑤
return rr;
}
//⑤的具体实现,这里是主要的实现,主要的思想是,先从_rwList查找是否可以解析当前类型的数据,如果能解析,直接返回解析结果
//如果不能解析,根据当前的文件名称,创建一个跟当前名称相关的动态库的名称,然后使用loadLibrary加载该动态库,加载成功后
_rwList这里面存储的对象的数目会增加,这个是个有诀窍的地方,在这个工程中没有发现有对_rwList做增加操作的代码,那么_rwList是怎么增加的
主要的关键点是,对于每一个dll中都有个宏调用,该宏是如下,这个宏生成了一个静态的对象osgDB::RegistryReaderWriterProxy,这个对象的作用就是
增加_rwList的对象数目,这是注册机制的关键。然后使用新增加的readerWrite完成对数据文件的读取
/////////////#define REGISTER_OSGPLUGIN(ext, classname) \
////////////extern "C" void osgdb_##ext(void) {} \
/////////// static osgDB::RegisterReaderWriterProxy g_proxy_##classname;
ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
{ // first attempt to load the file from existing ReaderWriter's
//看是否有可用的ReaderWriter,对当前的数据进行解析,如果解析成功,就返回结果
AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
for(;itr.valid();++itr)
{
ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
if (readFunctor.isValid(rr)) return rr;
}
//根据文件名称创建新的动态库名称,然后加载动态库,加载动态库,增加_rwList的对象个数
std::string libraryName = createLibraryNameForFile(readFunctor._filename);
if (loadLibrary(libraryName)!=NOT_LOADED)
{
//重新遍历一下,使用新的ReaderWriter进行数据的解析
for(;itr.valid();++itr)
{
ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
if (readFunctor.isValid(rr)) return rr;
else results.push_back(rr);
}
}
}
[osg]osgDB的加载机制,使用3DS插件做参考(转,整理现有osgDB资料)的更多相关文章
- jvm系列(一):java类的加载机制
java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...
- 【前端】CommonJS的模块加载机制
CommonJS的模块加载机制 CommonJS模块的加载机制是,输入的是被输出的值的拷贝.也就是说,一旦输出一个值,模块内部的变化就影响不到这个值. 例如: // lib.js var counte ...
- Yii2的深入学习--自动加载机制
Yii2 的自动加载分两部分,一部分是 Composer 的自动加载机制,另一部分是 Yii2 框架自身的自动加载机制. Composer自动加载 对于库的自动加载信息,Composer 生成了一个 ...
- Yii2的深入学习--自动加载机制(转)
Yii2 的自动加载分两部分,一部分是 Composer 的自动加载机制,另一部分是 Yii2 框架自身的自动加载机制. Composer自动加载 对于库的自动加载信息,Composer 生成了一个 ...
- angular懒加载机制 刷新后无法回退解决方案
今天在项目中遇到一个很奇怪的问题,使用oclazyload来懒加载angular的模块,刷新页面后,单击回退按钮无法返回上一个页面.估计是使用懒加载机制销毁了angular内部的state关联,导致无 ...
- Java高级之虚拟机加载机制
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 1.0版本:2016-05-21 SubClass!! 执行结果说明一个问题:子类调用父类变量的时候 ...
- java加载机制整理
本文是根据李刚的<疯狂讲义>作的笔记,程序有的地方做了修改,特别是路径,一直在混淆,浪费了好多时间!!希望懂的同学能够指导本人,感激尽............ 1.jvm 和 类的关系 当 ...
- 浅析dex文件加载机制
我们可以利用DexClassLoader来实现动态加载dex文件,而很多资料也只是对于DexClassLoader的使用进行了介绍,没有深入讲解dex的动态加载机制,我们就借助于Android4.4的 ...
- 深入理解ClassLoader(四)—类的父委托加载机制
上几次我们介绍到了JVM内部的几个类加载器,我们来重新画一下这个图,再来看一下他们之间的关系.
随机推荐
- mysql5.6主从
1.环境 操作系统:centos6.5(主服务器IP:192.168.100.170,从服务器IP:192.168.100.171)软件版本:mysql5.6.24 2.开始安装: a.主库上设置从库 ...
- C++ 引用的辨别
对于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却有着不同的用途,掌握C++的&符号,是提高代码执行效率 ...
- Linux(Centos)下搭建SVN服务器
鉴于在搭建时,参考网上很多资料,网上资料在有用的同时,也坑了很多人,本文的目的,也就是想让后继之人在搭建svn服务器时不再犯错,不再被网上漫天的坑爹作品所坑害,故此总结! /******开始***** ...
- 免费访问:谷歌搜索,Gmail邮箱,Chrome商店
分享个免费的google的服务的方法 1,插件下载: http://note.youdao.com/noteshare?id=6a3e52f8d4ccf63c751eeddd625a118d 2,使用 ...
- ibatis 中#和 $ 符号的区别
1.数据类型匹配 #:会进行预编译,而且进行类型匹配(自动确定数据类型): $:不进行数据类型匹配. 2.实现方式: # 用于变量替换(先生成一个占位符,然后替换) select * from use ...
- 利用Qt开发跨平台APP(二)(iOS,使用Qt5.9,很详细,有截图)
本文将手把手教你如何使用Qt编译出iOS应用程序. Qt是一个优秀的跨平台开发工具.我们利用Qt可以很方便地将一次编写的应用,多次编译到不同平台上,如Windows.Linux.MAC.Android ...
- 洛谷P1156 垃圾陷阱 dp
正解:dp 解题报告: 这儿是传送门! 话说最近怎么神仙们都开始狂刷dp,,,感觉今天写了好多dp的题解的样子?(也就三四道其实× 然后这题,首先看到要么吃要么堆起来就会想到01背包趴?然后就考虑设方 ...
- tomcat启动错误:ZipException
[/opt/apache-tomcat-/webapps/secsight.war] -Dec- ::] org.apache.catalina.core.ContainerBase.addChild ...
- Flask系列之蓝图中使用动态URL前缀
让我们先来看一个简单的例子,假设有下面这样一个蓝图(是关于用户主页的): from flask import Blueprint, render_template profile = Blueprin ...
- 模块讲解----subprocess模块
历史 #输出结果到屏幕上,并不返回执行状态os.system('dir')#保存命令的执行结果输出ret = os.popen('dir').read() 问题:上面2条是把命令结果保存下来了,但是返 ...