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

  • 前言
  • 案例分析
    • 程序框架
      • 1.基本案例
      • 2.实现定制绑定/定制引擎
    • 渲染函数
  • 总结

前言

本篇我们来分析ImGui部分。首先,我们需要明确的是,imgui部分包含了Dear Imgui 的主要代码及文档,它们是直接添加进现有项目中的功能包,所以我们只需要了解怎么使用这个库即可。
Overload使用的Dear Imgui版本为1.77,我们阅读常见问题http://dearimgui.org/faq 了解到目前Dear Imgui已经更新到1.85版本,这里我们就按照Overload使用的1.77版本进行分析。
作为新手,我们有必要先阅读“程序员指南”,了解如何在代码库中设置Dear ImGui。这里我采用分析代码案例的方法来直观地了解Dear Imgui的使用。

案例分析

程序框架

1.基本案例

下面通过一些案例来了解一个简单的应用程序是什么样子的

// Application init: create a dear imgui context, setup some options, load fontsImGui::CreateContext();ImGuiIO& io = ImGui::GetIO();// TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.// TODO: Fill optional fields of the io structure later.// TODO: Load TTF/OTF fonts if you don't want to use the default font.// Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)ImGui_ImplWin32_Init(hwnd);ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);// Application main loopwhile (true){// Feed inputs to dear imgui, start new frameImGui_ImplDX11_NewFrame();ImGui_ImplWin32_NewFrame();ImGui::NewFrame();// Any application code hereImGui::Text("Hello, world!");// Render dear imgui into screenImGui::Render();ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());g_pSwapChain->Present(1, 0);}// ShutdownImGui_ImplDX11_Shutdown();ImGui_ImplWin32_Shutdown();ImGui::DestroyContext();

所有使用Dear Imgui的应用程序,第一步都是初始化,ImGui::CreateContext(); 最后一步都是关停,ImGui::DestroyContext();
在创建了一个Imgui context后,要做的是设置一些选项——包括字体和输入输出流。
然后,初始化助手平台和渲染器绑定,这里使用的是imgui_impl_win32.cpp和imgui_impl_dx11.cpp
接着是应用程序的主循环,首先将选定的助手平台以及渲染器馈送至Dear Imgui,启动新框架,然后定义了文本,最后将Dear imgui渲染到屏幕中。
在这里需要注意的是渲染语句的使用。使用ImGui_ImplDX11渲染了绘图数据,并将当前的交换链指向(1,0)
最后,由于这个案例调用了imgui_impl_win32.cpp和imgui_impl_dx11.cpp,所以我们要由下至上先将他们关停。

2.实现定制绑定/定制引擎

我们再来看一个案例,它实现了绑定和引擎的定制。

// Application init: create a dear imgui context, setup some options, load fontsImGui::CreateContext();ImGuiIO& io = ImGui::GetIO();// TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.// TODO: Fill optional fields of the io structure later.// TODO: Load TTF/OTF fonts if you don't want to use the default font.// Build and load the texture atlas into a texture// (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)int width, height;unsigned char* pixels = NULL;io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);// At this point you've got the texture data and you need to upload that your your graphic system:// After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.// This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)io.Fonts->TexID = (void*)texture;// Application main loopwhile (true){// Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.// (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings)io.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)io.DisplaySize.x = 1920.0f;             // set the current display widthio.DisplaySize.y = 1280.0f;             // set the current display height hereio.MousePos = my_mouse_pos;             // set the mouse positionio.MouseDown[0] = my_mouse_buttons[0];  // set the mouse button statesio.MouseDown[1] = my_mouse_buttons[1];// Call NewFrame(), after this point you can use ImGui::* functions anytime// (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)ImGui::NewFrame();// Most of your application code hereImGui::Text("Hello, world!");MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();MyGameRender(); // may use any Dear ImGui functions as well!// Render dear imgui, swap buffers// (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)ImGui::EndFrame();ImGui::Render();ImDrawData* draw_data = ImGui::GetDrawData();MyImGuiRenderFunction(draw_data);SwapBuffers();}// ShutdownImGui::DestroyContext();

这个案例显然比上面的案例更加完善。相比上一个案例,这个案例增加了构建纹理图集并将其加载到纹理中。通常使用渲染器ImGui_ImplXXX_Init()来实现这个功能。这里用到的函数是io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
此时,我们已获得纹理数据,这里用MyTexture* texture=MyEngine::CreateTextureFromMemoryPixels(…)将纹理数据上载到图形系统。创建纹理后,将其指针/标识符以引擎使用的格式存储在“io”中: io.Fonts->TexID = (void*)texture;
接下来是应用程序的主循环,首先是一些设置一些简单的参数,包括从每帧的时间间隔(1/60秒),分别设置显示器的宽度和高度为1920×1080,以及鼠标的位置,鼠标按键状态用0,1表示。
ImGui::NewFrame();是很重要的一步,因为在调用这条语句后,就可以在主循环中使用ImGui:: 中任意的函数了,所以应该尽早调用此语句。接下来我们就可以调用Imgui的一些函数来对界面进行设定了。设定完成之后将进行渲染,最后交换缓冲区。

渲染函数

下面我们接着通过案例来了解一个简单的渲染函数是什么样子的。
impl_impl_XXX.cpp文件包含许多渲染函数,可以用于实现。

void void MyImGuiRenderFunction(ImDrawData* draw_data){// TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled// TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize// TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize// TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.for (int n = 0; n < draw_data->CmdListsCount; n++){const ImDrawList* cmd_list = draw_data->CmdLists[n];const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by Dear ImGuiconst ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by Dear ImGuifor (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++){const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];if (pcmd->UserCallback){pcmd->UserCallback(cmd_list, pcmd);}else{// The texture for the draw call is specified by pcmd->TextureId.// The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.MyEngineBindTexture((MyTexture*)pcmd->TextureId);// We are using scissoring to clip some objects. All low-level graphics API should supports it.// - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches//   (some elements visible outside their bounds) but you can fix that once everything else works!// - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)//   In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.//   However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),//   always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.// - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)ImVec2 pos = draw_data->DisplayPos;MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y));// Render 'pcmd->ElemCount/3' indexed triangles.// By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);}idx_buffer += pcmd->ElemCount;}}}

这里的注释比较杂乱,主要说了一些可以添加的代码段,用于实现一些功能。
为了更好的理解代码,我们这里主要介绍已有的代码含义。第一层for循环是用命令列表遍历绘画数据的每一项,并生成顶点缓冲区和索引缓冲区。第二层for循环是遍历命令缓冲区,如果存在用户回调则处理,如果不存在则设定纹理并显示,这里添加了剪裁功能,即可以通过鼠标点击来控制显示大小。此外,还渲染了索引的三角面片。
最后,增加了索引的计数,以便下一次循环的进行。

总结

Dear Imgui与OpenGL都是图形化界面的工具,使用起来有一些相似之处。不过相比之下,Dear Imgui还是更简单易懂一些。

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

  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源码模块分析(三)——Internal

    <2021SC@SDUSC>[Overload游戏引擎]OvUI源码模块分析(三)--Internal 前言 Internal 1.Converter 2.EMemoryMode 3.Wi ...

  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. vue ui无效_vue开发中,父组件添加scoped之后。解决在父组件中无法修改子组件样式问题。...
  2. python sub 不区分大小写_解决Python列表字符不区分大小写的问题
  3. boost::math模块查找正态分布的均值或标准差的示例
  4. 配置使用EF6.0常见的一些问题及解决方案
  5. Error while compiling statement: FAILED: LockException [Error 10280]
  6. mysql 按顺序添加_MySQL按顺序排序
  7. ASP.NET Core跨域设置
  8. devc++源文件未编译_iOS 编译知识小结
  9. oracle date 隐式转换,PL/SQL中的数据类型隐式转换规则
  10. hdu 1671 Phone List 字典树模板
  11. java获取年份getyear_Java LocalDateTime getYear()用法及代码示例
  12. ft2232驱动安装方法_win7系统无法安装打印机驱动程序的解决方法
  13. 【备忘】二叉树遍历的迭代实现
  14. redis学习笔记---java操作redis,使用expire模拟指定时间段内限制ip访问的次数;
  15. Activiti 单环节多人办理一件
  16. 离散数学大作业代码及感想
  17. Linux 开发环境 -- glibc 升级(不建议轻易升级)
  18. Python 如何反方向迭代一个序列
  19. 企业微信/skype sdk demo
  20. 坚果投影仪陷入双11刷单漩涡?良性发展才是硬道理!

热门文章

  1. 2021年第十二届蓝桥杯省赛B组C/C++部分填空题解
  2. 用海龟画图画一个写轮眼
  3. 谢宾斯基三角形的几种生成方法
  4. JMeter最简单汉化中文版
  5. python查看图片的gps_浅析python中获取图片中exif中的gps方法
  6. 我脑中飘来飘去的 CSS 魔幻属性
  7. 图形图像概念以及在android中的应用
  8. CCNP之重发布实验
  9. 浅谈CORS的两种请求方式
  10. 2018“百越杯”第四届福建省高校网络空间安全大赛部分题目writeup