MyGui笔记(4)渲染过程

来源:互联网 发布:去哪里投诉淘宝卖家 编辑:程序博客网 时间:2024/05/16 08:27

前篇:《MyGui笔记(3)控件对齐方式和所在层》
本篇:记录下渲染的过程。
环境:MyGui3.2.0(OpenGL平台)

        MyGui的渲染过程比较复杂,这里仅记录一下一些要点,如有错误的地方,还请指出。在第一篇有提到在BaseManager::run函数里面进行每一帧的绘制,调用的是drawOneFrame()方法,这个方法代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void BaseManager::drawOneFrame()
{
    // First we clear the screen and depth buffer
    // 首先清除屏幕和深度缓冲
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Then we reset the modelview matrix
    // 然后重置模型视图矩阵
    glLoadIdentity();

    if (mPlatform)
        mPlatform->getRenderManagerPtr()->drawOneFrame();

    SwapBuffers(hDC);
}

调用的是OpenGLRenderManagerdrawOneFrame()方法,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void OpenGLRenderManager::drawOneFrame()
{
    Gui* gui = Gui::getInstancePtr();
    if (gui == nullptr)
        return;

    static Timer timer;
    static unsigned long last_time = timer.getMilliseconds();
    unsigned long now_time = timer.getMilliseconds();
    unsigned long time = now_time - last_time;

    onFrameEvent((float)((double)(time) / (double)1000));

    last_time = now_time;

    begin();
    onRenderToTarget(this, mUpdate);
    end();

    mUpdate = false;
}

在这里进行每一帧事件的触发,和每一帧的渲染,渲染调用其onRenderToTarget方法,代码如下: 

1
2
3
4
5
6
void RenderManager::onRenderToTarget(IRenderTarget* _target, bool _update)
{
    LayerManager* layers = LayerManager::getInstancePtr();
    if (layers != nullptr)
        layers->renderToTarget(_target, _update);
}

可以看到在这里调用的是LayerManager层管理器来进行绘制,具体代码如下: 

1
2
3
4
5
6
7
void LayerManager::renderToTarget(IRenderTarget* _target, bool _update)
{
    for (VectorLayer::iterator iter = mLayerNodes.begin(); iter != mLayerNodes.end(); ++iter)
    {
        (*iter)->renderToTarget(_target, _update);
    }
}

mLayerNodes里的所有层依次进行调用渲染,故定义在MyGUI_Layers.xml文件最上面的层,将会最先开始渲染,顺序如Wallpaper→Back→Overlapped→……。具体的渲染方法是根据不同的层类型来进行的,代码分别如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void SharedLayer::renderToTarget(IRenderTarget* _target, bool _update)
{
    if (mChildItem != nullptr)
        mChildItem->renderToTarget(_target, _update);

    mOutOfDate = false;
}

void OverlappedLayer::renderToTarget(IRenderTarget* _target, bool _update)
{
    for (VectorILayerNode::iterator iter = mChildItems.begin(); iter != mChildItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    mOutOfDate = false;
}

在这里可以看到SharedLayer只进行了一次渲染,而OverlappedLayer对附加的根控件节点依次进行渲染,最终调用的都是LayerNode::renderToTarget方法,代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void LayerNode::renderToTarget(IRenderTarget* _target, bool _update)
{
    mDepth = _target->getInfo().maximumDepth;

    // 检查压缩空隙
    bool need_compression = false;
    for (VectorRenderItem::iterator iter = mFirstRenderItems.begin(); iter != mFirstRenderItems.end(); ++iter)
    {
        if ((*iter)->getCompression())
        {
            need_compression = true;
            break;
        }
    }

    if (need_compression)
        updateCompression();

    // 首先渲染
    for (VectorRenderItem::iterator iter = mFirstRenderItems.begin(); iter != mFirstRenderItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    for (VectorRenderItem::iterator iter = mSecondRenderItems.begin(); iter != mSecondRenderItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    // 现在绘制子节点
    for (VectorILayerNode::iterator iter = mChildItems.begin(); iter != mChildItems.end(); ++iter)
        (*iter)->renderToTarget(_target, _update);

    mOutOfDate = false;
}

渲染调用的方法为RenderItem::renderToTarget,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
void RenderItem::renderToTarget(IRenderTarget* _target, bool _update)
{
    if (mTexture == nullptr)
        return;

    mRenderTarget = _target;

    mCurrentUpdate = _update;

    if (mOutOfDate || _update)
    {
        mCountVertex = 0;
        Vertex* buffer = mVertexBuffer->lock();
        if (buffer != nullptr)
        {
            for (VectorDrawItem::iterator iter = mDrawItems.begin(); iter != mDrawItems.end(); ++iter)
            {
                // 在调用之前记住缓冲区的位置
                mCurrentVertex = buffer;
                mLastVertexCount = 0;

                (*iter).first->doRender();

                // 数量惊人的顶点绘制
                MYGUI_DEBUG_ASSERT(mLastVertexCount <= (*iter).second, "It is too much vertexes");
                buffer += mLastVertexCount;
                mCountVertex += mLastVertexCount;
            }

            mVertexBuffer->unlock();
        }

        mOutOfDate = false;
    }

    // 虽然0不是批次显示,但它仍然不会产生状态和操作
    if (0 != mCountVertex)
    {
#if MYGUI_DEBUG_MODE == 1
        if (!RenderManager::getInstance().checkTexture(mTexture))
        {
            mTexture = nullptr;
            MYGUI_EXCEPT("texture pointer is not valid, texture name '" << mTextureName << "'");
            return;
        }
#endif
        //直接渲染
        if (mManualRender)
        {
            for (VectorDrawItem::iterator iter = mDrawItems.begin(); iter != mDrawItems.end(); ++iter)
                (*iter).first->doManualRender(mVertexBuffer, mTexture, mCountVertex);
        }
        else
        {
            _target->doRender(mVertexBuffer, mTexture, mCountVertex);
        }
    }
}

注释是俄语的,谷歌翻译成汉语,可能会有错误,还请指出。最后的渲染即调用OpenGLRenderManager::doRender方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void OpenGLRenderManager::doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count)
{
    OpenGLVertexBuffer* buffer = static_cast<OpenGLVertexBuffer*>(_buffer);
    unsigned int buffer_id = buffer->getBufferID();
    MYGUI_PLATFORM_ASSERT(buffer_id, "Vertex buffer is not created");

    unsigned int texture_id = 0;
    if (_texture)
    {
        OpenGLTexture* texture = static_cast<OpenGLTexture*>(_texture);
        texture_id = texture->getTextureID();
        //MYGUI_PLATFORM_ASSERT(texture_id, "Texture is not created");
    }

    glBindTexture(GL_TEXTURE_2D, texture_id);

    glBindBuffer(GL_ARRAY_BUFFER, buffer_id);

    // enable vertex arrays
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    // before draw, specify vertex and index arrays with their offsets
    size_t offset = 0;
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offset);
    offset += (sizeof(float) * 3);
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)offset);
    offset += (4);
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offset);

    glDrawArrays(GL_TRIANGLES, 0, _count);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

更多资料:
1.纯手绘的MyGUI类图、渲染流程图 http://blog.csdn.net/liigo/article/details/7078533
2.LayerManager  http://blog.csdn.net/geometry_/article/details/7324348
3.mygui跟踪 http://www.cppblog.com/flipcode/archive/2011/06/24/149388.aspx

 

原创粉丝点击