[osg]osg中回调机制的设计研究

osg中消息机制和调度机制的实现:

1.      猜想:所有的消息的起源都来自osgViewer::View,所以,先分析下osgViewer::View是如何将事件处理器或回调机制器加载进来的。

此类中的方法:addEventHandler(osgGA::GUIEventHandler * eventHandler);

类View中有一个属性_eventHandlers,其定义如下所示:

typedefstd::list<osg::ref_ptr<osgGA::GUIEventHandler>> EventHandlers;
EventHandlers _eventHandlers;

#Q: 既然类View可以添加多个事件处理器,那么在事件发生时是如何选择事件处理器的?

类关系图如下所示:




>


> OsgGA::GUIEventHandler主要提供了窗口系统的GUI事件接口。它使用osgGA::GUIEventAdapter来接受更新,使用osgGA::GUIActionAdapter来向系统提出请求。

适配器osgGA::GUIActionAdapter已为基类,此类的作用是向系统提出请求,#Q:具体是如何提出请求的呢?

#A:

osgGA::GUIAdctionAdapter完全是一个抽象基类,只声明了几个抽象方法。主要有以下几个请求:requestRedraw,requestContinuosUpdate,requestWrapPointer。

不论是osgViewer::GraphicsWindow还是osgViewer::View在实现这三类方法时都是直接或间接的去设置osgViewer::ViewerBase的标志位:_requestRedraw,_requestContinusUpdate;而requestWrapPointer都是间接地去调用osgViewer::GraphicsWindow中的继承方法。

#Q: 相机在这中间期到了一个什么作用?相机既能获取osgViewer::View又能获取osgViewer::GraphicsWindow。osg::View用来管理所有的相机视图。。

 

#Q: 适配器osgGA::GUIEventAdapter如何获取更新?

#A:osgGA::GUIEventAdapter只定义了各类消息和事件的枚举类型,以及设置和获取消息和事件值(set/get)。具体设置消息和事件值得地方在osgGA::EventQueue中。所以消息的更进一个源头是在osgGA::EventQueue中产生。

 

#Q: osgGA::EventQueue是如何接收消息的?

#A:

而调用osgGA::EventQueue中具体某类消息的源头是在:osgViewer::GraphicsWindowWin32中的方法:

virtual LRESULT handleNativeWindowingEvent(HWND hwnd, UINTuMsg, WPARAM wParam , LPARAM lParam);

而最终handleNativeWindowingEvent方法调用的源头在文件GraphicsWindowWin32.cpp中的窗口过程函数staticLRESULT CALLBACK WindowProc中:

static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg,WPARAM wParam, LPARAM lParam )
{
    osgViewer::GraphicsWindowWin32* window =Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
    returnwindow ? window->handleNativeWindowingEvent(hwnd,uMsg, wParam, lParam) :
                    ::DefWindowProc(hwnd, uMsg,wParam, lParam);
}

#Q: 有关窗口类、窗口、及窗口过程的注册如何进行的?

#A: 在源文件GraphicsWindowWin32.cpp文件中声明并定义的类:

classWin32WindowSystem : public osg::GraphicsContext::WindowSystemInterface

该类提供了注册窗口、注册窗口类的方法。通过将HWND和osgViewer::GraphicsWindowWin32关联起来。

窗口的创建是在osgViewer::GraphicsWindowWin32::createWindow中进行的。

而这些工作全都在osgViewer::GraphicsWindowWin32::init方法中进行,方法init在该类的构造函数中进行调用。

最终的方法还是在Win32WindowSystem::createGraphicsContext中进行的。

可参照项目Review中对GraphicsWindow的初始化代码:在RenderModule.cpp文件中方法initViewer中:

    HWND hWnd = context.uc().mainframe()->m_wndView->m_hWnd;
 
    RECT rect;
    ::GetClientRect(hWnd, &rect);
 
    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    osg::ref_ptr<osgViewer::GraphicsWindowWin32::WindowData>windata = newosgViewer::GraphicsWindowWin32::WindowData(hWnd);
 
    traits->x = 0;
    traits->y = 0;
    traits->width = rect.right - rect.left;
    traits->height = rect.bottom - rect.top;
    traits->windowDecoration = false;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->setInheritedWindowPixelFormat = true;
    traits->inheritedWindowData = windata;
    if (context.ac().antialiasing)
    {
       traits->sampleBuffers = true;
       traits->samples = 4;
    }
 
    osg::ref_ptr<osg::GraphicsContext> gc =osg::GraphicsContext::createGraphicsContext(traits.get()); 

找到osg消息来源的源头:来自osgViewer::GraphicsWindowWin32,原理和一般地在windows编程中一样:先注册一个窗口类,给此窗口类绑定一个窗口过程,在GraphicsWindow.cpp中定义的是窗口方法是static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAMwParam, LPARAM lParam);然后通过重新组装定义windows发送过来的窗口消息来构建属于osg的消息模型,具体的消息管理由osgViewer::EventQueue进行。

 

2.      #Q: 既然已经知道有osgViewer::EventQueue来生成消息并管理消息的队列,那么osg是如何对消息进行分发的呢?

#A: 在osgViewer::GraphicsWindowWin32的父类osgViewer::GraphicsWindow中定义的属性:

           osg::ref_ptr<osgGA::EventQueue>_eventQueue;

在该类的方法handleNativeWindowingEvent中就是用到的_eventQueue;那么既然osgViewer::GraphicsWindowWin32是osg消息的源头,就从此类的_eventQueue开始分析。

在osgViewer::CompositeViewer和osgViewer::Viewer的eventTraversal方法中都有用到osgViewer::GraphicsWindowWin32的_eventQueue属性进行事件处理。而此二类中也有自己的_eventQueue,#Q: 那么osgViewer::Viewer中的_eventQueue是如何获取消息的呢?

#A: 首先osgViewer::Viewer中的_eventQueue在此类及父类中中都没有定义过,那就只能通过其父类osgViewer::View::setEventQueue来对其进行设置,其次对_eventQueue的赋值是在osgViewer::eventTraversal中进行的,其中间接用到了osgViewer::GraphicsWindowWin32中的_eventQueue,所以sgViewer::View::_eventQueue的最终来源还是来自福osgViewer::GraphicsWindowWin32中的_eventQueue,此类的_eventQueue在其构造函数中就对其进行了赋值操作。

 

分析可得所有的事件均是在osgViewer::Viewer::eventTraversal中进行的,它将每个事件都发送到_eventHandlers中的每个事件处理器中,而最终的过滤操作还是由osgGA::GUIEventHandler进行处理,通过调用虚拟方法handle

 

#Q: 那么,还剩下最后一个问题,那就是osgViewer::Viewer::eventTraversal方法是以什么样的方式进行调用?

#A: 通过osgViewer::ViewBase::frame方法和osgViewer::Viewer::checkNeedToFrame方法进行。osgViewer::CompositeViewer也一样。

 

而最终osg消息处理的循环体是在osgViewer::ViewBase::run方法中进行的。

 

osg定义的事件有:


3.      回调的设计与分析

http://www.osgchina.org/projects/osgcn/wikicn/Supportcn/Tutorials/Callbacks.php

#TODO: 对回调进行分析。

#Q: 重载方法()是什么时候执行的?

http://www.cnblogs.com/indif/archive/2011/04/22/2024805.html

>10OSG处理事件的时机和顺序是怎样的?

答:OSGViewer::eventTraversal函数中处理输入事件,eventTraversal在帧循环的更新遍历和渲染遍历之前被调用。

      eventTraversal中事件处理的顺序为:

1)   为本帧每一个事件遍历场景树,调用NodeDrawableStateSet对象的事件处理回调处理事件。

2)      为本帧每一个事件遍历Viewer的事件处理器(GUIEventHandler)队列,调用事件处理器处理事件。

3)      为本帧每一个事件,调用Viewer的相机操作器(CameraManipulator)处理事件。

#A: 都是在UpdateVisitor::apply方法中进行的,此类方法为虚拟重载方法,类UpdateVistor的父类为osg::NodeVisitor。

osg::NodeCallback首先回调是应用在节点上的,即osg::Node,该类分别提供对更新(update)、事件(event)、拣选(cull)的回调。在osgViewer::Viewer中只处理update回调和event回调。具体调用回调使用的虚拟方法osg::Node::accept,此方法调用的是osg::NodeVisitor::apply方法。分别有三个osg::NodeVisitor的派生类:osgGA::EventVisitor,osgUtil::UpdateVisitor和osgUtil::CullVisitor,其中有一点不解:为什么EventVisitor放在了osgGA库中??

方法osgViewer::Viewer::eventTraversal处理事件回调,方法updateTraversal处理更新回调。

osg::Drawable::EventCallback,osg::Drawable::CullCallback,osg::Drawable::UpdateCallback,这三个回调类是专门针对osg::Geode的回调,在osgGA::EventVisitor,osgUtil::UpdateVisitor和osgUtil::CullVisitor中的handle_geode_callback方法中增加了对osg::Drawable。。的回调处理。

结贴。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值