<2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(三)——Internal

  • 前言
    • Internal
      • 1.Converter
      • 2.EMemoryMode
      • 3.WidgetContaine
        • WidgetContainer.h
        • WidgetContainer.cpp
          • 1)RemoveWidget
          • 2)RemoveAllWidgets
          • 3)ConsiderWidget
          • 4)UnconsiderWidget
          • 5)CollectGarbages
          • 6)DrawWidgets
  • 总结

前言

本篇我们来分析Overload源码OvUI部分的Internal模块。顾名思义,Internal部分处理的是在Overload中使用imgui包需要处理的一些内部转换的问题。Internal由Converter和WidgetContainer两部分组成。Converter处理imgui与Overload类型之间的转换,WidgetContaine是关于Overload中imgui内部小部件的使用,其包含了小部件容器的所以基类。下面我们来具体的分析一下它们是如何实现的。

Internal

1.Converter

首先,我们来分析一下converter.h中converter类的定义。

class Converter{public:/*** Disabled constructor*/Converter() = delete;/*** Convert the given Color to ImVec4* @param p_value*/static ImVec4 ToImVec4(const Types::Color& p_value);/*** Convert the given ImVec4 to Color* @param p_value*/static Types::Color ToColor(const ImVec4& p_value);/*** Convert the given FVector2 to ImVec2* @param p_value*/static ImVec2 ToImVec2(const OvMaths::FVector2& p_value);/*** Convert the given ImVec2 to FVector2* @param p_value*/static OvMaths::FVector2 ToFVector2(const ImVec2& p_value);};

1.Converter() = delete;
禁用构造函数,禁止编译器生成默认的构造函数。因为Converter类的作用是数值类型的转换,所以对于Converter类而言,对象的拷贝或赋值时不合法的。

2.static ImVec4 ToImVec4(const Types::Color& p_value);
static Types::Color ToColor(const ImVec4& p_value);
众所周知,我们表示颜色用的是一个四维向量,四个参数的值都在[0, 1]间,前三个维度代表RGB值,最后一维代表透明度(即RGBA),值越小越透明。 而ImVec4是imgui可以识别的四维向量,所以这里的作用是显示的颜色数值类型与imgui中的数值类型的转换。

3.static ImVec2 ToImVec2(const OvMaths::FVector2& p_value);
static OvMaths::FVector2 ToFVector2(const ImVec2& p_value);
FVector2是Overload中OvMath部分定义的二维浮点数向量的数学表示。所以这里的作用是二维浮点数向量在Overload中的类型与imgui可识别的类型之间的转换。

这样一来,Converter.cpp就很好理解了。

ImVec4 OvUI::Internal::Converter::ToImVec4(const Types::Color & p_value)
{return ImVec4(p_value.r, p_value.g, p_value.b, p_value.a);
}OvUI::Types::Color OvUI::Internal::Converter::ToColor(const ImVec4 & p_value)
{return Types::Color(p_value.x, p_value.y, p_value.z, p_value.w);
}ImVec2 OvUI::Internal::Converter::ToImVec2(const OvMaths::FVector2 & p_value)
{return ImVec2(p_value.x, p_value.y);
}OvMaths::FVector2 OvUI::Internal::Converter::ToFVector2(const ImVec2 & p_value)
{return OvMaths::FVector2(p_value.x, p_value.y);
}

就是简单的对应数值的输出,哈哈~

2.EMemoryMode

接着我们来看一下EMemoryMode.h的内容。

 enum class EMemoryMode{INTERNAL_MANAGMENT,EXTERNAL_MANAGMENT};

EMemoryMode是一个枚举类,它把内存管理分为了内部管理和外部管理。

3.WidgetContaine

WidgetContainer.h

同样,我们先来看一下WidgetContaine.h中WidgetContainer类的定义。

class WidgetContainer{public:/*** Remove a widget from the container* @param p_widget*/void RemoveWidget(Widgets::AWidget& p_widget);/*** Remove all widgets from the container*/void RemoveAllWidgets();/*** Consider a widget* @param p_manageMemory*/void ConsiderWidget(Widgets::AWidget& p_widget, bool p_manageMemory = true);/*** Unconsider a widget* @param p_widget*/void UnconsiderWidget(Widgets::AWidget& p_widget);/*** Collect garbages by removing widgets marked as "Destroyed"*/void CollectGarbages();/*** Draw every widgets*/void DrawWidgets();/*** Allow the user to reverse the draw order of this widget container*/void ReverseDrawOrder(bool reversed = true);/*** Create a widget* @param p_args*/template <typename T, typename ... Args>T& CreateWidget(Args&&... p_args){m_widgets.emplace_back(new T(p_args...), Internal::EMemoryMode::INTERNAL_MANAGMENT);T& instance = *reinterpret_cast<T*>(m_widgets.back().first);instance.SetParent(this);return instance;}/*** Returns the widgets and their memory management mode*/std::vector<std::pair<OvUI::Widgets::AWidget*, Internal::EMemoryMode>>& GetWidgets();protected:std::vector<std::pair<OvUI::Widgets::AWidget*, Internal::EMemoryMode>> m_widgets;bool m_reversedDrawOrder = false;};

我们可以清楚的看出,WidgetContainer类中先声明了7个函数,它们的作用是对小部件进行各种各样的操作,它们都在WidgetContainer.cpp中被定义,我们接下来会进行分析。
然后是创建小部件的功能,通过使用emplace_back插入末端元件,并通过back()增强了代码的健壮性。
最后返回小部件及其内存管理模式。

WidgetContainer.cpp

下面我们来分析一下WidgetContainer.cpp中函数的定义

1)RemoveWidget
void OvUI::Internal::WidgetContainer::RemoveWidget(Widgets::AWidget& p_widget)
{auto found = std::find_if(m_widgets.begin(), m_widgets.end(), [&p_widget](std::pair<OvUI::Widgets::AWidget*, Internal::EMemoryMode>& p_pair){ return p_pair.first == &p_widget;});if (found != m_widgets.end()){if (found->second == Internal::EMemoryMode::INTERNAL_MANAGMENT)delete found->first;m_widgets.erase(found);}
}

这个函数的作用是从容器中删除小部件。
这里使用了auto关键字来获取复杂类型,使用find_if查找。
首先,我们要了解find_if()函数的使用方法。find_if() 是在一定范围内查找单个对象的算法。它的前两个参数分别指定了起始位置和终止位置,在这个范围内查找可以使第三个参数指定的谓词返回 true 的第一个对象

其次,我们还需要了解pair的用法。pair的作用是将两个数据组合成一个数据,当函数需要返回两个数据时,也可以选择使用pair。

了解了以上几个关键字的使用,这段代码就变了容易理解了。在m_widgets的范围中找到为p_widget的小部件,提取出小部件和它的管理模式。判断其管理模式,如果是内部管理,则删除这个小组件。

2)RemoveAllWidgets
void OvUI::Internal::WidgetContainer::RemoveAllWidgets()
{std::for_each(m_widgets.begin(), m_widgets.end(), [](auto& pair){if (pair.second == Internal::EMemoryMode::INTERNAL_MANAGMENT)delete pair.first;});m_widgets.clear();
}

作用:从容器中删除所有小部件。
删除所有小部件明显比删除指定的小部件更加简单,不需要查找特定的小部件了,只需要判断管理模式是否为内部管理,如果是则可以删除。

3)ConsiderWidget
void OvUI::Internal::WidgetContainer::ConsiderWidget(Widgets::AWidget & p_widget, bool p_manageMemory)
{m_widgets.emplace_back(std::make_pair(&p_widget, p_manageMemory ? EMemoryMode::INTERNAL_MANAGMENT : EMemoryMode::EXTERNAL_MANAGMENT));p_widget.SetParent(this);
}

这个函数的翻译是考虑小部件,但分析其作用,应该是将小部件放入小部件组中。
这里用到了emplace_back(),其作用是在容器尾部添加一个元素。emplace_back()内部直接调用构造函数,即原地构造,性能较高。
还用到了make_paie。与上面的pair的作用类似,make_pair可以用来生成需要的pair,这里依旧是合并小部件和它的管理模式。
然后用SetParent把p_widget指定到当前的m_widgets中。不难看出p_widget是一个小部件,而m_widgets是一组小部件,在前面的函数中也是这样的含义。

4)UnconsiderWidget
void OvUI::Internal::WidgetContainer::UnconsiderWidget(Widgets::AWidget & p_widget)
{auto found = std::find_if(m_widgets.begin(), m_widgets.end(), [&p_widget](std::pair<OvUI::Widgets::AWidget*, Internal::EMemoryMode>& p_pair){return p_pair.first == &p_widget;});if (found != m_widgets.end()){p_widget.SetParent(nullptr);m_widgets.erase(found);}
}

显然,这个函数的作用于上一个函数对立,是将一个小部件从小部件组中删除。
这里用到的查找对应小部件并输出和其管理模式的组合的方式和前面删除小组件类似,就不必赘述了。
这里使用nullptr释放了p_widget.SetParent中的指针,然后将对应的小组件删除。

5)CollectGarbages
void OvUI::Internal::WidgetContainer::CollectGarbages()
{m_widgets.erase(std::remove_if(m_widgets.begin(), m_widgets.end(), [](std::pair<OvUI::Widgets::AWidget*, Internal::EMemoryMode>& p_item){bool toDestroy = p_item.first && p_item.first->IsDestroyed();if (toDestroy && p_item.second == Internal::EMemoryMode::INTERNAL_MANAGMENT)delete p_item.first;return toDestroy;}), m_widgets.end());
}

这个函数的作用是:通过移除标记为“已销毁”的小部件来收集垃圾。

remove_if函数的前两个参数表示迭代的起始位置和终止位置。最后一个参数是一个回调函数,这里是用于判断小部件是否已标记为“destroyed”,如果返回值为真,则将当前参数移到尾部。返回值为被移动区域的首个元素。

回调函数中运用IsDestroyed() 函数判断小组件是否被标记为“已销毁”,如果小部件被判定为“已销毁”且为内部管理,则移除小组件。

6)DrawWidgets
void OvUI::Internal::WidgetContainer::DrawWidgets()
{CollectGarbages();if (m_reversedDrawOrder){for (auto it = m_widgets.crbegin(); it != m_widgets.crend(); ++it)it->first->Draw();}else{for (const auto& widget : m_widgets)widget.first->Draw();}
}

作用:绘制每个小部件。
这个函数比较易懂,先判断小部件组是否为倒序,如果是就从后往前绘制小组件,否则就是从头到尾绘制小组件。

总结

关于Internal模块的分析到这里就结束啦!Internal模块的重点是关于小部件的操作,为了实现多种功能,这部分的代码稍微有点繁琐。不过只要认真的分析了几个关键函数,其它的也就大同小异啦~

<2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(三)——Internal相关推荐

  1. <2021SC@SDUSC>【Overload游戏引擎】源码模块简介及项目分工

    <2021SC@SDUSC>[Overload游戏引擎]源码模块简介及项目分工 模块简介 Overload SDK Overload 应用程序 项目分工 模块简介 Overload 由12 ...

  2. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(五)——Plugins

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(五)--Plugins 前言 DataDispatcher DDSource DDTarget IPlugin ...

  3. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(二)——ImGui

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(二) 前言 案例分析 程序框架 1.基本案例 2.实现定制绑定/定制引擎 渲染函数 总结 前言 本篇我们来分析 ...

  4. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(四)——ModulesPanels

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(四)--Modules&Panels 前言 Modules Canvas Panels APanel ...

  5. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(一)——Core

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(一) 文章目录 前言 OvUI的模块结构 源码分析 1.Core模块 (1)UIManger的构造函数和析构函 ...

  6. <2021SC@SDUSC>【Overload游戏引擎】OvUI源码模块分析(六)——Widgets

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(六)--Widgets Button Button namespace OvUI::Widgets::Butt ...

  7. 【Overload游戏引擎】源码分析之十三:OvRendering函数库(十一)

    2021SC@SDUSC 目录 1.Driver 1.1构造函数 1.2InitGlew 1.3GLDebugMessageCallback 2.Renderer 2.1Draw 2.2FetchGL ...

  8. 【Overload游戏引擎】源码分析之五:OvRendering函数库(三)

    2021SC@SDUSC 目录 IMesh.h与Mesh.h 1.CreateBuffers 2.ComputeBoundingSphere 3.其他函数 回顾一下前几篇文章,我们讲到了有关图形学三维 ...

  9. 【Overload游戏引擎】源码分析之六:OvRendering函数库(四)

    2021SC@SDUSC 目录 1.Uniform 1.1UniformType 1.2UniformInfo 2.Shader 2.1SetUniform和GetUniform 2.2GetUnif ...

最新文章

  1. 【原创】大数据基础之Spark(9)spark部署方式yarn/mesos
  2. JavaFX控件ID:设置Label文本内容代码示例
  3. kibana操作elasticsearch:创建映射字段
  4. Qt Remote Object(QtRO)给指定的客户端发送消息
  5. 智慧交通day03-车道线检测实现02-1:相机校正
  6. sqlserver isnull函数使用
  7. 经济型EtherCAT运动控制器(三):PLC实现多轴直线插补与电子凸轮
  8. 腾讯云服务器无限流量,腾讯云服务器有流量限制吗,您看仔细了
  9. stm32 win7 64位虚拟串口驱动安装失败解决办法
  10. 2022年 HSC-1th中MISC的汝闻,人言否
  11. IMU、AHRS、VRU和GNSS、INS
  12. 支付宝转账到银行卡的二维码
  13. 【DSP开发】【VS开发】MUX和DEMUX的含义
  14. 轻松学,Java 中的代理模式及动态代理
  15. java手机游戏开发人才短缺
  16. 走过冷暖的岁月,感知生命的厚重
  17. 嵌入式操作系统和RTOS(实时操作系统)介绍。
  18. 前端基于element组件的语音文件上传
  19. Strlen和Sizeof的区别
  20. CRC校验 串行 并行 长除 移位 查表 矩阵

热门文章

  1. Github 加载不出来,解决方法
  2. [N32G45x]轻松几步将embOS移植到国民N32G45X上
  3. 河海大学计算机与信息学院王敏,计算机技术-河海大学计算机与信息学院.PDF
  4. 快盘linux安装方法,linux mint安装金山快盘
  5. 改进地图搜索用户体验,还是完善
  6. 记录一次zookeeper集群其中一节点在hbase web页面中显示Connection rese
  7. dubbo-monitor启动异常之Native memory allocation (mmap) failed to map 1879048192 bytes for committing rese
  8. PN结在高掺杂的情况下,耗尽层宽度为什么变窄
  9. 联想台式电脑开机需要按F2才能继续的解决方法
  10. 2022年年终总结及2023年展望-----学习总是对的,机会善于光顾有准备的头脑