前篇:《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); } |
调用的是OpenGLRenderManager的drawOneFrame()方法,代码如下:
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); } |