读书人

MyGui札记(4)渲染过程

发布时间: 2013-10-18 20:53:13 作者: rapoo

MyGui笔记(4)渲染过程

前篇:《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

读书人网 >移动开发

热点推荐