MyGUI 解析
MyGUI源码还是比较简单的,我们在这里只是简单分析相应控件如何生成,如何渲染。
我们分成三个部分来说明,分别是资源类型,控件生成,控件渲染。
资源类型:
ResourceSkin:用于记录各个控件状态的纹理坐标位置,关联的图片,如何划分SubSkin及文本。
- SubSkin有主要有几种Type,主要是SubSkin, MainSkin, EditText, SimpleText, RoatingSkin, PolygonalSkin, TileRect. 分别对应ISubWidget里的几种子类实现。
- ResourceSkin用来生成上面所说的各种ISubWidget.
ResourceLayout:用于记录控件结构,用于表示Widget的树成分,Widget与子Widget类型,大小,属性等。
ILayer:表示层的概念,和Ogre中的Overlay比较类似,一般我用把在某些时间一起显示的控件放入同一层中,如刚进游戏界面和进入游戏后的界面UI应该用不同的Larer.
- MyGUI默认给我们分配一些Layer,请看文件MyGUI_Layers.xml,如Overlapped,Main,Popup等是我们比较常用的。
- MyGUI注册了二种类型的Layer,分别是SharedLayer与OverlappedLayer,其中SharedLayer层上控件如果不重叠可以用这个,否则用OverlappedLayer,原因见后面.
控件生成:
ISubWidget:前面说ResourceSkin有提到,他的子类实现主要有EditText, MainSkin, SubSkin, TileRect, PolygonalSkin, RotationSkin ,SimpleText这些,ISubWidget负责最后的渲染,就是说控件到最后都是组合成ISubWidget来进行渲染.
- 上面所说的子类实现,主要是从二种ISubWidget的子类继承,一种是ISubWidgetRect,一种是ISubWidgetText.简单来说,一种没有文本,只有位置,颜色信号,一种包含文本信息,如字体名,字体大小等.上面说的EditText与SimpleText是从ISubWidgetText继承,别的ISubWidget都是从ISubWidgetRect继承.
LayerItem:一种树型结构,叶子节点为ISubWidget,非叶子节点为LayerItem,能绑定到Layer和LayerNode上,也能解绑.
SkinItem: LayerItem的子类.提供根据资源ResourceSkin文件生成ISubWidget列表功能,并提取一个ISubWidgetRect到字段mMainSkin,一个ISubWidgetText到mText上,没有则为空.
Widget:MyGUI中控件的父类,这个类就相当于winForm中的Control,本身是树型结构(Widget包含子Widget列表).可以对照上面的ResourceLayout的图.
- 继承多个类,其中继承SkinItem类能根据ResourceSkin生成子ISubWidget列表,继承WidgetInput 提供与键盘和鼠标事件的交互,继承IcroppedRectangle提供大小,绝对位置或相对父位置信息.
- Widget可以由ResourceLayout资源序列化得到,其中每个节点Widget属性上的Type指点对应生成子类控件(Button/EditBox等),而对应的Skin则指明对应的ResourceSkin,生成SkinItem信息.
Button/EditBox等:这些基本控件MyGUI中的WidgetManager注册,并且由MyGUI本身提供的基本Templates文件提供的ResoureceLayout生成Widget.
控件渲染:
IVertexBuffer:一块缓冲区数据,数据块格式P3fT2fC1i,就是每个顶点用三个float数据表示顶点,二个float表示纹理坐标,一个uint数据表示颜色,根据不同的平台来实现这个子类.
IRenderTarget:渲染目标,一般是当前窗口.
RenderItem:简单来说,把多个SubWidget组合在一起渲染,前面我们可以看到,同一类型的Skin一般都是用一张图,那么只要记录各顶点的纹理坐标位置就可以合成一个Pass渲染完成.MyGUI效率高从这个类可以看到原因.
LayerNode:管理Layer中的RenderItem,当把Widget加入Layer中,实际是把Widget中的顶层ISubWidget添加到对应的LayerNode中的RenderItem中,这样ISubWidget,RenderItem,LayerNode三者就联系在一起了.
- 对应上面的Layer, 一个OverlappedLayer包含多个LayerNode,而一个SharedLayer只有一个共用的SharedLayerNode.后面LayerNode是一个接一个渲染的,那么如果各顶层ISubWidget有覆盖,然后又添加到SharedLayerNode,他并不能保证覆盖渲染正确.
- 并不是所有的Widget都能加入到LayerNode, CroppedParent为空或是没有父Widget的Widget才会生成并添加到LayerNode中,其中没有父Widget的Widget一般是那种窗口,而CroppedParent为空一般是Popup类型(如PopupMenu).
加载控件与渲染流程
1.LayoutManager::loadLayout 加载layoutName 得到ResoureceLayout.
2.ResourceLayout::createLayout 根据ResoureceLayout中的WidgetInfo(对应ResoureceLayout资源文件中的Widget节点)创建Widget.
3.ResourceLayout::createWidget 根据控件是否是模版控件(对应的LayoutResourece file是否是模版文件,默认的Button /EditBox 等都在一个模板LayoutResource 文件里).分别调用不同的方法生成Widget.
4.LayerManager::attachToLayerNode 在上面创建Widget后,会把对应的Widget添加到他所属于的Layer层中.(注意前面说过,CroppedParent为空或是没有父Widget的Widget才会添加到Layer中的LayerNode中.这样,只有顶层Widget才会添加到LayerNode中.)其中OverlappedLayer每个顶层Widget生成一个对应的LayerNode,而SharedLayer只会生成一个SharedLayerNode,所有顶层Widget同享这个SharedLayerNode.这样前面说的控件如果不重叠可以用SharedLayerNode就有了解释,因为同层LayerNode中的RenderItem的渲染顺序我们控制不了,但是不同LayerNode我们可以控制渲染顺序,如二个部分重合的窗口,我激活那个,我就让那个RenderItem后渲染.这样激活的那个就显示在后面了.
5.LayerNode::attachLayerItem 把顶层Widget附加到LayerNode中.
6.LayerItem::attachToLayerItemNode 编历LayerItem(前面有说过)中的树层次,把所有叶子节点的ISubWidget放入一个列表.
7.ISubWidget::createDrawItem(注意,ISubWidget没有这方法,但是其最后的实体子类都实现了这个方法).在这里根据上面的LayerItem叶子节点中的ISubWidget列表,我们来创建对应LayerNode中的RenderItem.
8.LayerNode::addToRenderItem 根据ISubWidget中的图片决定是否生成新的RenderItem.并把ISubWidget添加到RenderItem中.
- 其中ISubWidgetText的子类添加到LayerNode的第二通道上,而ISubWidgetRect添加到LayerNode的第一通道上.
- 在这里并不是一个ISubWidget创建一个RenderItem,如果多个ISubWidget都用的相同图片,则只生成一个RenderItem.
如上这些,是在初始化Layout资源文件发生的过程,那么渲染是如何进行的.
在MyGUI.OgrePlatform中,Ogre渲染平台实现了MyGUI中的RenderManager实现类OgreRenderManager.其中OgreRenderManager 实现了监听类Ogre::RenderQueueListener,这个监听类具体方法以及作用请看Ogre 监听类与渲染流程.
当我们调用OgrePlatform::initialise时,把OgreRenderManager注册到SceneManager中的RenderQueueListener中.这样Ogre开始渲染通道时,进入到OgreRenderManager::renderQueueStarted中,然后交给RenderManager::onRenderToTarget.
1.RenderManager::onRenderToTarget MyGUI开始渲染.
2.ILayer::renderToTarget MyGUI中的每个层开始渲染.
3.LayerNode::renderToTarget 每层中的每个LayerNode开始渲染.
4.RenderItem::renderToTarget 渲染二个通道里的每个RenderItem.(RenderItem如何来的,请看前面.)
5.ISubWidget::doRender 渲染RenderItem里的ISubWidget列表.根据当前ISubWidget计算位置,大小,颜色,纹理坐标等等,整合所有ISubWidget成一个IVertexBuffe与一个ITexture.
6.OgreRenderManager::doRender 调用Ogre渲染上面的IVertexBuffe与ITexture.
如上一个渲染结束,大致总结下,MyGUI最后就是ISubWidget在更新渲染的数据,而ISubWidget根据资源文件ResourceSkin生成.一个窗口里的控件如果用的是同一样式,同一字体,那么一般二次渲染就行了.
ResourceSkin如果上面说的不是很清楚,可以看下面TabHeaderButtonSkin在Skin editor中的显示.
如下是上面ComboBox中的Layout文件在Layout editor中的界面显示.
写完,睡觉.
MyGUI 解析的更多相关文章
- Ogre 编辑器一(MyGUI+Ogre整合与主界面)
在查看Ogre例子时,想看材质要里的纹理,着色器代码都需要每个去查找,非常麻烦.也想看更新每个Ogre里的对象后有什么效果.然后看到Compositor组件与粒子组件时,想到能实时编辑着色器代码实时更 ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Html Agility Pack 解析Html
Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面 用Fir ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- Asp.Net WebApi核心对象解析(下篇)
在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...
- 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye
一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...
随机推荐
- WebClient请求帮助类
/// <summary> /// 通过JSON方式发送POST请求 /// 将返回结果按JSON方式解析 /// </summary> public static class ...
- C语言发展历程及其保留字(关键字)——附:C语言标准文档
引言 抽时间对C语言发展历程和C语言的标准库文件及其保留字/关键字做了个梳理,后面附C语言各版本国际标准. C语言发展历程及其标准库 C语言关键字/保留字 C语言国际标准 ...
- lua -- io.pathinfo
io.pathinfo 拆分一个路径字符串,返回组成路径的各个部分. 格式: parts = io.pathinfo(路径) 使用示例: local pathinfo = io.pathinfo(&q ...
- elastic search internal
Realtime Search with Lucene http://2010.berlinbuzzwords.de/sites/2010.berlinbuzzwords.de/files/busch ...
- Swift中Notification.Name这么难用怎么办
Swift中Notification.Name这么难用怎么办 以前的发送通知的参数就是一个简单的字符串: NSNotificationCenter.defaultCenter().post(" ...
- DIOCP开源项目-利用队列+0MQ+多进程逻辑处理,搭建稳定,高效,分布式的服务端
最近头脑里面一直在想怎么样让能让大家基于DIOCP上写出稳定的服务端程序.很多朋友问我,你DIOCP稳定吗,我可以用他来做三层服务器吗? 当时我是这样回答的,我只能保证DIOCP底层通信的稳定. 说实 ...
- XnView查看图片实际大小
找了很多软件,只有它可以显示尺寸大小. 各位如有别的发现,可留言推荐,谢谢
- 【转载】关于Java String, StringBuilder, StringBuffer, Hashtable, HashMap的面试题
REF: http://blog.csdn.net/fightforyourdream/article/details/15333405 题目是一道简单的小程序,像下面这样:[java] view p ...
- YII登陆错误 mcrypt_create_iv()
使用php框架YII进行开发的时候,虽然很快,性能很好,但是也有一些小问题,现在记录下来. 1.在使用gii的自动代码生成后,登陆系统,就会报错 mcrypt_create_iv() [<a h ...
- kali Rolling 安装QQ和虚拟机
环境: kali Rolling 64位 WPS 官网linux版下载链接:http://community.wps.cn/download/ 使用dpkg命令安装,遇到依赖问题,用apt-get ...