这一节介绍GUI的实现。我们这里使用开源库ImGui。
首先我们将GUI分离为一个单独的层,创建ImGuiLayer:
ImGuiLayer.h
:
#pragma once
#include "Dragon/Core/Layer.h"
#include "Dragon/Events/ApplicationEvent.h"
#include "Dragon/Events/KeyEvents.h"
#include "Dragon/Events/MouseEvent.h"
namespace Dragon
{
class ImGuiLayer : public Layer
{
public:
ImGuiLayer();
~ImGuiLayer() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
virtual void OnImGuiRender() override;
//virtual void OnEvent(Event& e) override;
void Begin();
void End();
private:
float m_Time = 0.0f;
};
}
函数先不介绍,直接看实现:
namespace Dragon
{
ImGuiLayer::ImGuiLayer()
:Layer("ImGuiLayer")
{
}
void ImGuiLayer::OnAttach()
{
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
//// Setup Dear ImGui style
ImGui::StyleColorsDark();
////ImGui::StyleColorsClassic();
//// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
Application& app = Application::Get();
GLFWwindow* window = static_cast<GLFWwindow*>(app.GetWindow().GetNativeWindow());
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 410");
}
void ImGuiLayer::OnDetach()
{
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
}
void ImGuiLayer::Begin()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
}
void ImGuiLayer::End()
{
ImGuiIO& io = ImGui::GetIO();
Application& app = Application::Get();
io.DisplaySize = ImVec2((float)app.GetWindow().GetWidth(), (float)app.GetWindow().GetHeight());
// Rendering
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
}
void ImGuiLayer::OnImGuiRender()
{
/*static bool show = true;
ImGui::ShowDemoWindow(&show);*/
}
}
OnAttach()
函数初始化ImGui,创建上下文,然后获取输入输出io,并设置io的标识,设置按键标识,Docking标识(即GUI窗口可以相互内嵌),视口标识(和OpenGL视口配套)。ImGui::StyleColorsDark()
设置样式,默认有三种可选。然后获取样式,设置GUI窗口的背景以及圆角。ImGui_ImplGlfw_InitForOpenGL
是ImGui为GLFW提供的一个方法,可以传入一个GLFW窗口指针,然后配置好所需的参数,ImGui_ImplOpenGL3_Init
是ImGui为OpenGL提供的一个方法,可以为某一版本的OpenGL配置好所需的参数。
OnDetach()
函数没什么好说的。
Begin()
函数调用了三个NewFrame
方法,这是必须的,相当于新建窗口的意思。
OnImGuiRender()
函数是所绘制的GUI,大家可以把注释取消渲染一下ImGui自带的demo窗口看一下,里面提供了许多示例。
End()
函数主要是渲染GUI数据,并更新,这是示例中的代码。
重点是OnImGuiRender()
函数,它定义在Layer
类中,这样我们可以在客户端类中定义同名函数来设置GUI,比如:
virtual void OnImGuiRender() override
{
ImGui::Begin("Inspector");
if(m_GameObjectsName.size()!=0)
GameObjectGui(m_GameObjectsName[m_GameObjectsItem]);
ImGui::NewLine();
ImGui::Text("Shader List");
const char** shaderList = StringToChar(m_ShaderList);
ImGui::Combo("", &m_ShaderListItem, shaderList, m_ShaderList.size());
ShaderGui(m_ShaderList[m_ShaderListItem]);
ImGui::NewLine();
ImGui::Text("Post Effect");
ImGui::Checkbox("Opposition", &m_Opposition);
if (m_Opposition)
{
ImGui::SameLine();
ImGui::SliderFloat("Opposition Weight", &m_OppositionWeight, 0.0f, 1.0f);
}
ImGui::Checkbox("Gray", &m_Gray);
if (m_Gray)
{
ImGui::SameLine();
ImGui::SliderFloat("Gray Weight", &m_GrayWeight, 0.0f, 1.0f);
}
ImGui::Checkbox("Kernel", &m_Kernel);
if (m_Kernel)
{
ImGui::SameLine();
ImGui::SliderFloat("Kernel Weight", &m_KernelWeight, 0.0f, 1.0);
}
ImGui::Checkbox("Blur", &m_Blur);
if (m_Blur)
{
ImGui::SameLine();
ImGui::SliderFloat("Blur Weight", &m_BlurWeight, 0.0f, 1.0f);
}
ImGui::Checkbox("Edge Detection", &m_EdgeDetection);
if (m_EdgeDetection)
{
ImGui::SameLine();
ImGui::SliderFloat("Edge Detection Weight", &m_EdgeDetectionWeight, 0.0f, 1.0f);
}
ImGui::End();
ImGui::Begin("Game Object");
ImGui::Text("Geometry");
m_CubeButtonClicked = ImGui::Button("Cube");
ImGui::SameLine();
ImGui::Button("Sphere");
ImGui::SameLine();
ImGui::Button("Quad");
ImGui::Button("Import Model");
ImGui::NewLine();
ImGui::Text("Light Source");
ImGui::Button("Point Light");
ImGui::SameLine();
ImGui::Button("Directional Light");
ImGui::SameLine();
ImGui::Button("Spot Light");
ImGui::SameLine();
ImGui::Button("Area Light");
ImGui::Button("Sky Box");
ImGui::NewLine();
ImGui::Button("Orthographic Camera");
ImGui::SameLine();
ImGui::Button("Perspective Camera");
ImGui::End();
ImGui::Begin("Outline View");
const char** GameObjectList = StringToChar(m_GameObjectsName);
ImGui::ListBox("", &m_GameObjectsItem, GameObjectList, m_GameObjectsName.size(), m_GameObjectsName.size());
ImGui::End();
}
这些组件函数可以从ImGui的文档里看到用法,都是GUI的那一套,这是我的GUI效果:
![](https://img.haomeiwen.com/i18672981/8b488f8f72eae98a.png)
目前可以点击创建一些内置几何体,并调整TRS以及赋予shader,调整相关参数。
下一节介绍预编译模块(使用CMake或Premake),来方便整理外部模块,方便别人能够使用你的程序。
项目github地址:https://github.com/Dragon-Baby/Dragon
网友评论