清源游民  gameogre@gmail.com

下面直接涉及到相关类


首先看一下
ExampleFrameListener, 下面是类间关系图

 
ExampleFrameListener 继承了 FrameListener, 因此拥有了它的两个方法

virtual bool frameStarted(constFrameEvent& evt)

virtual bool frameEnded(constFrameEvent& evt)

在 ExampleApplication 中将它们注册到 ogre 中,在适当的时候, ogre 会调用这两个方法 . 下面是注册地点与时机

virtual void ExampleApplication::createFrameListener(void)

    {

        mFrameListener= newExampleFrameListener(mWindow, mCamera);

        mFrameListener->showDebugOverlay(true);

        mRoot->addFrameListener(mFrameListener);

}

createFrameListener 在 ExampleApplication::setup() 中被调用.

ExampleFrameListener 又继承了 WindowEventListener.

WindowEventListerner 在ogre 1.4中是新加的。按照手册:它是一个 Callback class used to send out window events to client app. 它定义以下四个接口,而显然例子程序中只用到了两个
virtual void windowMoved(RenderWindow* rw)   {}

virtual void windowResized(RenderWindow* rw) {}

virtual void windowClosed(RenderWindow* rw)  {}

virtual void windowFocusChange(RenderWindow* rw) {}

这种所谓的回调类如何实现?下面只说明windows操作系统的情况。

我们知道,windows操作系统监视系统中发生的一切,通过消息的方式通知相应的窗口。每个窗口类注册的时候,都指明一个回调过程,在那里处理传来的消息。应用程序又有各自的消息队列,从消息队列中取得消息,然后分开给各窗口.

不防从ogre的源码中看看上述windows基本过程如何实现,这有助理解回调类的实现过程:

首先,ogre可以为我们创建一个窗口:

mWindow = mRoot->initialise(true);//

于是我们进入到initialise()中看看吧,它倒底做了些什么事情。

RenderWindow * Root::initialise(boolautoCreateWindow, constString& windowTitle)

{

// ……

mAutoWindow =  mActiveRenderer->initialise(autoCreateWindow, windowTitle);

// 这里:RenderSystem* mActiveRenderer

// ……

}

mActivaRenderer 只是接口,不用实际的事情,实际的工作由它的子类完成,现只看DirectX实现:

RenderWindow * D3D9RenderSystem::initialise( boolautoCreateWindow, constString& windowTitle )

{

// ……………………

autoWindow = this->createRenderWindow( windowTitle, width, height,

              fullScreen, &miscParams );

// ………………… ..

}

好,继续下去,看看createRenderWindow做了些什么

    

RenderWindow * D3D9RenderSystem::createRenderWindow(constString &name,

       unsigned int width, unsignedintheight, boolfullScreen,

       const NameValuePairList *miscParams)

{

// …………… ..

RenderWindow * win = newD3D9RenderWindow(mhInstance, mActiveD3DDriver,

           mPrimaryWindow ? mpD3DDevice : 0);

 

win ->create( name, width, height, fullScreen, miscParams);

// ………………

}

继续

void D3D9RenderWindow::create(constString& name, unsignedintwidth, unsignedintheight,

       bool fullScreen, constNameValuePairList *miscParams)

{

// Register the window class

// NB allow 4 bytes of window data for D3D9RenderWindow pointer

    WNDCLASS wc = { 0, WindowEventUtilities::_WndProc, 0, 0, hInst,

           LoadIcon(0, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),

              (HBRUSH)GetStockObject(BLACK_BRUSH), 0, "OgreD3D9Wnd" };

           RegisterClass(&wc);

// 定义了窗口类,并且进行注册,需要注意的是,你看看它把窗口类的回调函数的值设为了什么?先记住,一会儿讨论它吧。

           // Create our main window

           // Pass pointer to self

           mIsExternal = false;

           mHWnd = CreateWindow("OgreD3D9Wnd", title.c_str(), dwStyle,

              mLeft, mTop, mWidth, mHeight, parentHWnd, 0, hInst, this);

// 调用win32API把窗口真正Create出来了

WindowEventUtilities ::_addRenderWindow(this);

// 这一步也要注意到

}

继续

void WindowEventUtilities::_addRenderWindow(RenderWindow* window)

{

    _msWindows.push_back(window);

}

_msWindows 定义为:

typedef std::vector<RenderWindow*> Windows;

 static Windows _msWindows;

,没什么,只是个stl容器,把生成的窗口放进去了.

到现在,容器类注册好了,回调函数也指定了,窗口也创建出来了。现在我们继续思考我们最最初的问题: WindowEventListerner 这个回调类是如何实现所谓的回调机制的,也就是说windowEventListerner不是定义了四个接口,它响应特定的windows事件,我们要讨论的就是这四个接口方法如何被调用起来,实现所谓的回调机制。 还记得注册窗口类的回调函数是什么吧,

WindowEventUtilities::_WndProc , 呵呵,只要在那里调用上述四个接口函数就好了。

哪问题又来了,_WndProc到哪里找这四个接口函数呢?

在 ExampleFrameListener 类的构造函数里我们可以看到如下代码

//Register as a Window listener

WindowEventUtilities::addWindowEventListener(mWindow, this);

啊,这就是奥秘所在!到源码中看看吧。

void WindowEventUtilities::addWindowEventListener( RenderWindow* window, WindowEventListener* listener )

{

    _msListeners.inser t(std::make_pair(window, listener));

}

-msListeners 被定义成这样子:

typedef std::multimap<RenderWindow*, WindowEventListener*> WindowEventListeners;

static WindowEventListeners _msListeners;

没有什么,就是STL容器,它使得窗口(RenderWindow)与(WindowEventListener)

组成了亲密派对,窗口有了什么消息,就可以用对应的回调类响应。

只剩下一点秘密了,到底怎么调用起来的呢,某某某说过,源码之下,了无秘密,那就看源码吧:

LRESULT CALLBACK WindowEventUtilities::_WndProc(HWNDhWnd, UINTuMsg, WPARAMwParam, LPARAMlParam)

{

WindowEventListeners ::iteratorstart = _msListeners.lower_bound(win),

                     end = _msListeners.upper_bound(win);

// 为遍历做准备

    switch( uMsg )   // 消息真的来了

  {

case WM_MOVE:

       //log->logMessage("WM_MOVE");

       win->windowMovedOrResized();

       for( ; start != end; ++start )

           (start->second)->windowMoved(win);

       break;

    case WM_SIZE:

       //log->logMessage("WM_SIZE");

       win->windowMovedOrResized();

       for( ; start != end; ++start )

           (start->second)->windowResized(win);

       break;

}

}

就这样,四个接口函数被调用起来了!

也许,也许,关于消息还有些要说明的。消息如何泵出来的?

当看到了如下代码,突然就想找个朋友,会心一笑.

void WindowEventUtilities::messagePump()

{

    MSG   msg;

    while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )

    {

       TranslateMessage( &msg );

       DispatchMessage( &msg );

    }

}

打破铁锅问到底吧,它又如何被调用起来?

void Root::startRendering(void)

    {

        while( !mQueuedEnd )

        {

           //Pump messages in all registered RenderWindow windows

           WindowEventUtilities::messagePump();

 

           if (!renderOneFrame())

                break;

        }

}

就是这里了。写的乱七八糟,脑子也乱七八糟,梳理一下吧。

首先,mWindow = mRoot->initialise(true);初始化,随便通过一系统连锁反应create出来一个窗口,并把它的回调函数设定为 WindowEventUtilities::_WndProc.

ExampleFrameListener 继承了 WindowEventListener 的四个约定接口函数。并且在它的构造函数里调用 WindowEventUtilities::addWindowEventListener(mWindow, this); 进行了注册,以便特定窗口消息发生时进行响应. Root ::startRendering ()进入了渲染循环,渲染每一帧前,检测widnows消息,并进行分发。于是消息进入到窗口类的回调函数_WndProc,在函数内部根据消息的不同,分别调用已注册的侦听器的约定接口函数。
先写到这里吧,原来只是想写写CEGUI的使用,谁知已经写了这么多了,CEGUI还一字未提。脑子乱了,先休息吧。下面还得说说OIS,CEGUI又得靠后了.


posted on 2007-03-01 21:47 清源游民 阅读(1828) 评论(1)  编辑 收藏 引用 所属分类: OGRE

FeedBack:
# re: ORGE(Eihort)学习笔记之GUI Demo 第一部分 例子框架
2008-12-31 11:30 | ouch
感謝! 相當清楚 而且好用  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2007年3月>
25262728123
45678910
11121314151617
18192021222324
25262728293031
1234567

留言簿(35)

随笔分类(78)

随笔档案(74)

文章档案(5)

搜索

  •  

最新评论

阅读排行榜

评论排行榜