osgcallback例子

这个例子演示了Callback功能。
Registry是一个单例,存储了不同类型的文件读取器(reader)和写入器(writer)。
下面让我们浅浅的看一下Registry和ReaderWriter这两个东西。
我们都知道OSG是通过插件的方式支持数据类型的扩展,如果想实现自己的数据类型,只需要写个插件继

承自ReaderWriter,然后重写readNode等方法就可以了,对了一定得需要REGISTER_OSGPLUGIN(osg,

OSGReaderWriter)这句话,这里的玄机在哪呢?进去看看吧!
REGISTER_OSGPLUGIN是个宏,在Registry中是这样定义的。
#define REGISTER_OSGPLUGIN(ext, classname) \
    extern "C" void osgdb_##ext(void) {} \
   

static osgDB::RegisterReaderWriterProxy<classname> g_proxy_##classname;
这里说一下“#”“##”的含义:
“#”是只后面跟的变量由引号包含,如:#value会解析成“value”
“##”是只前后两个值连接,去掉空格,如:A##B会解析成AB
所以,如果上面ext是osg,classname是OSGReaderWriter,就会解析成g_proxy_OSGReaderWriter。
我们接着往下看,是在Registry.cpp中的ReaderWriter::ReadResult Registry::read(const

ReadFunctor& readFunctor)函数loadLibrary(libraryName)这里调用的,libraryName会是osgPlugins-

3.0.1/osgdb_osg.dll,loadLibrary这个函数如果再往下跟下去在windows下就会是调用windows API加载

动态链接库了,这里很明显加载了osgdb_osg.dll这个动态链接库了,这也就是为什么自己写的插件一定

要输出osgdb_xxx.dll格式,并且放入osgPlugins-3.0.1中的原因了,因为这样osg才会找到这个插件。
上面我们说了加载对于格式插件的过程,如果加载了osgdb_osg.dll这个动态链接库,在OSGReaderWriter

中我们写了REGISTER_OSGPLUGIN(osg, OSGReaderWriter),对应的是#define REGISTER_OSGPLUGIN(ext,

classname) \
    extern "C" void osgdb_##ext(void) {} \
    static

osgDB::RegisterReaderWriterProxy<classname> g_proxy_##classname;
看看这里面有个static,这个非常的关键,加载一个动态链接库的时候,static的会默认执行,因此

osgDB::RegisterReaderWriterProxy就做了初始化。
class RegisterReaderWriterProxy
{
    public:
        RegisterReaderWriterProxy()
        {
     

      if (Registry::instance())
            {
                _rw = new T;
               

Registry::instance()->addReaderWriter(_rw.get());
            }
        }

       

~RegisterReaderWriterProxy()
        {
            if (Registry::instance())
            {
     

          Registry::instance()->removeReaderWriter(_rw.get());
            }
        }
       
        T* get() { return _rw.get(); }
       
    protected:
        osg::ref_ptr<T> _rw;
};
把这个new了这个ReaderWriter,然后放入了Registry进行注册。
因此,具有解析该种类型数据的插件的对象就会在OSG中保存了,如果下次再加载这个类型数据,直接去

这个对象就可以了,这里也解释了为什么插件要继承ReaderWriter,并且要REGISTER_OSGPLUGIN(osg,

OSGReaderWriter)进行注册,只有注册后才能实例化该插件对象,放入Registry中。
这个static是不是用的很巧妙,不同系统实例化ContextGraphic也同样用的该种方法,以后我们会进行研

究。
不知不觉已经离题万里,但相信这么走一趟我们是有收获的,回到例子中。
 osgDB::Registry::instance()->setReadFileCallback(new MyReadFileCallback());
例子中这样设置了一个callback,我们还得去源码中看看为什么要这样设置。
看看Registry.h中的readNode,当加载一个数据的时候ReadFile中会调用它,看看它都干了什么,
 if (options && options->getReadFileCallback()) result = options->getReadFileCallback()-

>readNode(fileName,options);
            else if (_readFileCallback.valid()) result =

_readFileCallback->readNode(fileName,options);
            else result =

readNodeImplementation(fileName,options);
三句话,如果options可用就执行它的readNode,否则执行_readFileCallback,都没有的话才执行自己的

readNodeImplementation。实际上面options,和_readFileCallback,中都执行了

readNodeImplementation这个函数。这里是OSG为扩展性考虑的,可以通过自定义options或

_readFileCallback来执行自己的read操作,因此,可以理解了例子中osgDB::Registry::instance()-

>setReadFileCallback(new MyReadFileCallback());就是通过自己写_readFileCallback实现自己的

readNode的。
看看继承关系MyReadFileCallback : public osgDB::Registry::ReadFileCallback
重写readNode方法,这里还是调用了        osgDB::ReaderWriter::ReadResult result =

osgDB::Registry::instance()->readNodeImplementation(fileName,options);
但是在这里做了打印的操

作,能够在控制台中看见调用,这里我们还可以扩展做很多事情。
接下来:
osgUtil::Optimizer optimzer;
    optimzer.optimize(rootnode);
看看优化都做了什么了,这里不深究了,看看Oprimizer的optimize方法,一目了然:
StaticObjectDetectionVisitor
TessellateVisitor
RemoveLoadedProxyNodesVisitor
CombineLODsVisitor
TextureVisitor
StateVisitor
TextureAtlasVisitor
StateVisitor
CopySharedSubgraphsVisitor
FlattenStaticTransformsVisitor
CombineStaticTransformsVisitor
FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor
MergeGeodesVisitor
CheckGeometryVisitor
MakeFastGeometryVisitor
MergeGeometryVisitor
TriStripVisitor
RemoveEmptyNodesVisitor
RemoveRedundantNodesVisitor
FlattenBillboardVisitor
SpatializeGroupsVisitor
IndexMeshVisitor
VertexCacheVisitor
VertexAccessOrderVisitor
这些都对根节点走了一遍,做了优化处理。
 InsertCallbacksVisitor icv;
    rootnode->accept(icv);

    viewer.getCamera()-

>setUpdateCallback(new CameraUpdateCallback());
    viewer.getCamera()->setEventCallback(new

CameraEventCallback());

这里通过InsertCallbacksVisitor 为根节点中的每个node,每个drawable都增加了callback,
节点需要继承NodeCallback,drawable需要继承 osg::Drawable::DrawCallback,重写相应的函数来实现

每一帧的回调,关于callback会以后单独的进行研究,包括 eventTraversal();
    updateTraversal

();
    renderingTraversals();三个重要的过程。
这里只顾着走源码了,没有强调callback的用途,Node和drawable的callback的作用就是在每一帧对节点

进行更新,实现节点的运动,状态的改变等操作。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值