CEGUI窗口的渲染顺序 四

定义和实现:CEGUIBase 里的:CEGUIWindow.h和CEGUIWindow.cpp。

cegui使用一个vector来存放所有的窗口,另外,再用一个vector存放渲染的顺序。

   //! definition of type used for the list of attached child windows.
    typedef std::vector<Window*> ChildList;    
//! The list of child Window objects attached to this.    
ChildList d_children;    
//! Child window objects arranged in rendering order.   
 ChildList d_drawList;

 

再有新的窗口添加时有两个重载的函数addChildWindow:

//添加一个名为name窗口作为this的子窗口。如果窗口存在,则先分离再添加。

void Window::addChildWindow(const String& name{
    addChildWindow(WindowManager::getSingleton().getWindow(name));
}

//----------------------------------------------------------------------------//

//添加wnd窗口作为this的子窗口。如果窗口存在,则先分离再添
void Window::addChildWindow(Window* window){
    // don't add null window or ourself as a child
    if (!window || window == this)  //检查不能添加自己为自己的孩子
        return;

    addChild_impl(window);//执行添加
    WindowEventArgs args(window); //激发事件
    onChildAdded(args);
    window->onZChange_impl();//通知窗口的Z值改变,窗口的Z值影响窗口的描述顺序
}

//添加指定窗口到合适的位置

void Window::addChild_impl(Window* wnd)

{
   //如果先前有父窗口则断开与先前父窗口的联系。
    if (wnd->getParent())         

         wnd->getParent()->removeChildWindow(wnd);

//添加窗口到描绘列表   

addWindowToDrawList(*wnd);

    //添加子窗口到列表

    d_children.push_back(wnd);

    // set the parent window
    wnd->setParent(this);

  //强制更新子窗口区域,因为父窗口已变

    WindowEventArgs args(this);
    wnd->onParentSized(args);
}

 

 /*Add the given window to the drawing list at an appropriate position for
        it's settings and the required direction.  Basically, when \a at_back
        is false, the window will appear in front of all other windows with the
        same 'always on top' setting.  When \a at_back is true, the window will
        appear behind all other windows wih the same 'always on top' setting.*/

添加指定的窗口到绘制的列表的合适的位置。如果at_back为false,并且设置“always on top”,这个窗口会显示有所有的窗口前面。如果at_back为true,则这窗口会设置在所有"'always on top"的窗口的后面。

void Window::addWindowToDrawList(Window& wnd, bool at_back)
{
    // add behind other windows in same group
    if (at_back)
    {
         // calculate position where window should be added for drawing
        ChildList::iterator pos = d_drawList.begin();
        if (wnd.isAlwaysOnTop())
        {
            // find first topmost window
            while ((pos != d_drawList.end()) && (!(*pos)->isAlwaysOnTop()))
                ++pos;
        }
        // add window to draw list
        d_drawList.insert(pos, &wnd);
    }
    // add in front of other windows in group
    else
    {
        // calculate position where window should be added for drawing
        ChildList::reverse_iterator position = d_drawList.rbegin();
        if (!wnd.isAlwaysOnTop())
        {
            // find last non-topmost window
            while ((position != d_drawList.rend()) && ((*position)->isAlwaysOnTop()))
                ++position;
        }
        // add window to draw list
        d_drawList.insert(position.base(), &wnd);
    }
}

 /*!
    \brief
        Causes the Window object to render itself and all of it's attached
        children

*/

//渲染时父窗口及其的子窗口,先渲染父,再渲染其子窗口

void Window::render()
{
    // don't do anything if window is not visible
    if (!isVisible())
        return;

    // get rendering context
    RenderingContext ctx;
    getRenderingContext(ctx);

    // clear geometry from surface if it's ours
    if (ctx.owner == this)
        ctx.surface->clearGeometry();

    // redraw if no surface set, or if surface is invalidated
    if (!d_surface || d_surface->isInvalidated())
    {
        // perform drawing for 'this' Window
        drawSelf(ctx);

        // 按顺序取得d_drawList里的所有的子窗口进行渲染

        const size_t child_count = getChildCount();
        for (size_t i = 0; i < child_count; ++i)
            d_drawList[i]->render();
    }

    // do final rendering for surface if it's ours
    if (ctx.owner == this)
        ctx.surface->draw();
}

 

          综上所述,cegui通过两个vector列表来控制所有的窗口渲染及其渲染顺序。渲染顺序又是通过一个添加窗口及at_back参数控制,at_back 默认是false,即默认添加的新窗口是在最前面,同时受“'always on top”影响。在实际游戏开发中Z值,应该要比这个复杂,并且有一些模态的窗口。我们可以改写addWindowToDrawList 来控制自己窗口实际显示时应在的位置,以达到项目的需求。

         对于模态窗口,以前我们的项目有个“变态”显示方法,每来一个模态的都显示在所有的窗口的最上面,但是鼠标消息却又还在第一个模态的窗口那里抢占着。我觉得应该再建立一个模态的列表,同时加上权重,但同时弹出N个模态的窗口时,选择权重最大的在最上面,即新弹出窗口时,则比较要弹出的模态窗口与显示的模态窗口的权重,如果权重大,则销毁前面的窗口,显示这个。 另一种方案是:如果有模态窗口显示时,不允许再弹出模态窗口。第三种方案是:管理一个要弹出的模态的窗口的列表,当判断有模态窗口显示在最上面时,则将此窗口压到栈里,每释放一个模态窗口时,在里面调一个接口检查是否有没有显示的模态窗口,如果有则显示下一个模态窗口,并从栈去掉该窗口。

原文地址:https://www.cnblogs.com/sier/p/5676502.html