修改ImGui层架构:
创建:
ImGuiBuild.cpp:引入ImGui
#include"ytpch.h"
#define IMGUI_IMPL_OPENGL_LOADER_GLAD//opengl的头文件需要的定义,说明使用的是gald
#include "backends/imgui_impl_opengl3.cpp"
#include "backends/imgui_impl_glfw.cpp"
Layer.h:加入GuiRender方法,每次渲染Gui都会调用
#pragma once
#include"YOTO/Core.h"
#include"YOTO/Event/Event.h"
namespace YOTO {class YOTO_API Layer{public:Layer(const std::string& name = "Layer");virtual ~Layer();virtual void OnAttach(){}virtual void OnDetach() {}virtual void OnUpdate() {}virtual void OnImGuiRender() {}// 每层都可以拥有自己的UI窗口virtual void OnEvent(Event& event) {}inline const std::string& GetName() const { return m_DebugName; }protected:std::string m_DebugName;};}
ImGuiLayer.h:删除冗余部分,仅留下加入,删除,和Render方法,添加Begine和End,用于每次刷新UI的配置和删除UI。
#pragma once
#include"YOTO/Layer.h"
#include"YOTO/Event/KeyEvent.h"
#include"YOTO/Event/MouseEvent.h"
#include"YOTO/Event/ApplicationEvent.h"
namespace YOTO {class YOTO_API ImGuiLayer:public Layer{public:ImGuiLayer();~ImGuiLayer();virtual void OnAttach()override;virtual void OnDetach()override;virtual void OnImGuiRender()override; void Begin();void End();private:float m_Time = 0.0f;};
}
ImGuiLayer.cpp:删除原来的Update,把配置、绘制UI的代码、渲染分离
#include"ytpch.h"
#include"ImGuiLayer.h"#include"YOTO/Application.h"#include<GLFW/glfw3.h>
#include<glad/glad.h>#define IMGUI_IMPL_API
#include "backends/imgui_impl_glfw.h"
#include "backends/imgui_impl_opengl3.h"
namespace YOTO {ImGuiLayer::ImGuiLayer():Layer("ImGuiLayer") {}ImGuiLayer::~ImGuiLayer() {}void ImGuiLayer::OnAttach(){// 不需要手动写ImGui的键值对应GLFW的键值、ImGui接收GLFW窗口事件,ImGui自动完成// 设置Gui配置IMGUI_CHECKVERSION();ImGui::CreateContext();ImGuiIO& io = ImGui::GetIO(); (void)io;io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 启用键盘控制//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; //启用手柄控制io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 启用自动布局io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; //启用多视窗/平台视窗(也就是能走出Opengl绘制的框子)//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;// 设置Gui配置样式ImGui::StyleColorsDark();//ImGui::StyleColorsClassic();// 当viewport被启用时,我们调整windowwround /WindowBg,使平台窗口看起来与常规窗口相同。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());//设置平台/渲染器绑定ImGui_ImplGlfw_InitForOpenGL(window, true);ImGui_ImplOpenGL3_Init("#version 410");}void ImGuiLayer::OnDetach(){ImGui_ImplOpenGL3_Shutdown();ImGui_ImplGlfw_Shutdown();ImGui::DestroyContext();}void ImGuiLayer::OnImGuiRender(){static bool show = true;ImGui::ShowDemoWindow(&show);// 当前OnImGuiRender层显示DemoUI窗口}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(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());// RenderingImGui::Render();ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());//如果启动启用多视窗/平台视窗if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable){GLFWwindow* backup_current_context = glfwGetCurrentContext();ImGui::UpdatePlatformWindows();ImGui::RenderPlatformWindowsDefault();glfwMakeContextCurrent(backup_current_context);}}}
LayerStack.h:修改m_LayerInsertIndex:
#pragma once
#include"Layer.h"namespace YOTO {class YOTO_API LayerStack{public:LayerStack();~LayerStack();void PushLayer(Layer* layer);void PushOverlay(Layer* layer);void PopLayer(Layer* layer);void PopOverlay(Layer* layer);std::vector<Layer*>::iterator begin() { return m_Layers.begin(); }std::vector<Layer*>::iterator end() { return m_Layers.end(); }private:std::vector<Layer*>m_Layers;unsigned int m_LayerInsertIndex=0;};}
LayerStack.cpp: 修改PushLayer:
#include "ytpch.h"
#include "LayerStack.h"
namespace YOTO {LayerStack::LayerStack() {}LayerStack::~LayerStack() {for (Layer* layer : m_Layers)delete layer;}//普通push在队列最左(查找时候性能更优)void LayerStack::PushLayer(Layer* layer) {// emplace在vector容器指定位置之前插入一个新的元素。返回插入元素的位置// 插入 1 2 3,vector是 3 2 1m_Layers.emplace(m_Layers.begin()+ m_LayerInsertIndex, layer);m_LayerInsertIndex++;}//在最右插入void LayerStack::PushOverlay(Layer* overlay) {//m_LayerInsert = m_Layers.begin();//如果报错,则把这个注释取消m_Layers.emplace_back(overlay);}//查找void LayerStack::PopLayer(Layer* layer) {auto it = std::find(m_Layers.begin(), m_Layers.end(), layer);if (it != m_Layers.end()) {m_Layers.erase(it);m_LayerInsertIndex--; // 指向Begin}}void LayerStack::PopOverlay(Layer* overlay) {auto it = std::find(m_Layers.begin(), m_Layers.end(), overlay);if (it != m_Layers.end())m_Layers.erase(it);}
}
Application.h:在APP中添加Gui层,无需在Sandbox中手动添加:
#pragma once
#include"Core.h"
#include"Event/Event.h"
#include"Event/ApplicationEvent.h"
#include "YOTO/Window.h"
#include"YOTO/LayerStack.h"
#include"YOTO/ImGui/ImGuiLayer.h"
namespace YOTO {class YOTO_API Application{public:Application();virtual ~Application();void Run();void OnEvent(Event &e);void PushLayer(Layer* layer);void PushOverlay(Layer* layer);inline static Application& Get() {return * s_Instance;}inline Window& GetWindow() { return *m_Window; }private:bool OnWindowClosed(WindowCloseEvent& e);std::unique_ptr<Window> m_Window;ImGuiLayer * m_ImGuiLayer;bool m_Running = true;LayerStack m_LayerStack;static Application* s_Instance;};//在客户端定义Application* CreateApplication();
}
Application.cpp:在构造函数中newImGuiLayer然后Push到最后
#include"ytpch.h"
#include "Application.h"#include"Log.h"
#include<glad/glad.h>
#include"Input.h"namespace YOTO {
#define BIND_EVENT_FN(x) std::bind(&x, this, std::placeholders::_1)Application* Application::s_Instance = nullptr;Application::Application() {YT_CORE_ASSERT(!s_Instance, "Application需要为空!")s_Instance = this;//智能指针m_Window = std::unique_ptr<Window>(Window::Creat());//设置回调函数m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));//new一个Layer,放在最后层进行渲染m_ImGuiLayer = new ImGuiLayer();PushOverlay(m_ImGuiLayer); //unsigned int id;//glGenBuffers(1, &id);}Application::~Application() {}/// <summary>/// 所有的Window事件都会在这触发,作为参数e/// </summary>/// <param name="e"></param>void Application::OnEvent(Event& e) {//根据事件类型绑定对应事件EventDispatcher dispatcher(e);dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClosed));//输出事件信息YT_CORE_INFO("Application:{0}",e);for (auto it = m_LayerStack.end(); it != m_LayerStack.begin();) {(*--it)->OnEvent(e);if (e.m_Handled)break;}}bool Application::OnWindowClosed(WindowCloseEvent& e) {m_Running = false;return true;}void Application::Run() {WindowResizeEvent e(1280, 720);if (e.IsInCategory(EventCategoryApplication)) {YT_CORE_TRACE(e);}if (e.IsInCategory(EventCategoryInput)) {YT_CORE_ERROR(e);}while (m_Running){glClearColor(1,0,1,1);glClear(GL_COLOR_BUFFER_BIT);for (Layer* layer : m_LayerStack) {layer->OnUpdate();}//将ImGui的刷新放到APP中,与Update分开m_ImGuiLayer->Begin();for (Layer* layer : m_LayerStack) {layer->OnImGuiRender();}m_ImGuiLayer->End();m_Window->OnUpdate();}}void Application::PushLayer(Layer* layer) {m_LayerStack.PushLayer(layer);layer->OnAttach();}void Application::PushOverlay(Layer* layer) {m_LayerStack.PushOverlay(layer);layer->OnAttach();}
}
SandboxApp.cpp:把PushImgGui的哪行代码删掉:
#include<YOTO.h>
#include "imgui/imgui.h"
#include<stdio.h>
//#include <glm/vec3.hpp> // glm::vec3
//#include <glm/vec4.hpp> // glm::vec4
//#include <glm/mat4x4.hpp> // glm::mat4
//#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
//glm::mat4 camera(float Translate, glm::vec2 const& Rotate)
//{
// glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.f);
// glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
// View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
// View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
// glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
// return Projection * View * Model;
//}class ExampleLayer:public YOTO::Layer
{
public:ExampleLayer():Layer("Example") {//auto cam=camera(5.0f,{0.5f,0.5f});}void OnImGuiRender() override {ImGui::Begin("Test");ImGui::Text("Test");ImGui::End();}void OnUpdate()override {//YT_CLIENT_INFO("测试update");if (YOTO::Input::IsKeyPressed(YT_KEY_TAB)) {YT_CLIENT_INFO("ExampleLayerOnUpdate:TAB按下了");}}void OnEvent(YOTO::Event& event)override {if (event.GetEventType() == YOTO::EventType::KeyPressed) {YOTO:: KeyPressedEvent& e = (YOTO::KeyPressedEvent&)event;YT_CLIENT_TRACE("ExampleLayer:{0}",(char)e.GetKeyCode());if (e.GetKeyCode()==YT_KEY_TAB) {YT_CLIENT_INFO("ExampleLayerOnEvent:TAB按下了");}}//YT_CLIENT_TRACE("SandBoxApp:测试event{0}", event);}private:};class Sandbox:public YOTO::Application
{
public:Sandbox() {PushLayer(new ExampleLayer());//PushLayer(new YOTO::ImGuiLayer());}~Sandbox() {}private:};YOTO::Application* YOTO::CreateApplication() {printf("helloworld");return new Sandbox();
}
作业:
src下的premake5.lua:修改sandbox的includedirs加入"YOTOEngine/vendor"
workspace "YOTOEngine" -- sln文件名architecture "x64" configurations{"Debug","Release","Dist"}
startproject "Sandbox"
-- https://github.com/premake/premake-core/wiki/Tokens#value-tokens
-- 组成输出目录:Debug-windows-x86_64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
-- 包含相对解决方案的目录
IncludeDir={}
IncludeDir["GLFW"]="YOTOEngine/vendor/GLFW/include"
IncludeDir["Glad"]="YOTOEngine/vendor/Glad/include"
IncludeDir["ImGui"] ="YOTOEngine/vendor/imgui"
IncludeDir["glm"] ="YOTOEngine/vendor/glm"
--项目中包含某包
include "YOTOEngine/vendor/GLFW"
include "YOTOEngine/vendor/Glad"
include "YOTOEngine/vendor/imgui"project "YOTOEngine" --YOTOEngine项目location "YOTOEngine"--在sln所属文件夹下的YOTOEngine文件夹kind "SharedLib"--dll动态库language "C++"targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- 输出目录objdir ("bin-int/" .. outputdir .. "/%{prj.name}")-- 中间目录staticruntime "Off"pchheader "ytpch.h"pchsource "YOTOEngine/src/ytpch.cpp"-- 包含的所有h和cpp文件files{"%{prj.name}/src/**.h","%{prj.name}/src/**.cpp","%{prj.name}/vendor/glm/glm/**.hpp","%{prj.name}/vendor/glm/glm/**.inl"}-- 包含目录includedirs{"%{prj.name}/src","%{prj.name}/vendor/spdlog-1.x/include","%{IncludeDir.GLFW}","%{IncludeDir.Glad}","%{IncludeDir.ImGui}","%{IncludeDir.glm}"}links{"GLFW",-- GLFW.lib库链接到YOTOEngine项目中"Glad",-- Glad.lib库链接到YOTOEngine项目中"ImGui",-- ImGui.lib库链接到YOTOEngine项目中"opengl32.lib"}-- 如果是window系统filter "system:windows"cppdialect "C++17"-- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;-- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错systemversion "latest" -- windowSDK版本-- 预处理器定义defines{"YT_PLATFORM_WINDOWS","YT_BUILD_DLL",-- "YT_ENABLE_ASSERTS","GLFW_INCLUDE_NONE"-- 让GLFW不包含OpenGL}-- 编译好后移动Hazel.dll文件到Sandbox文件夹下postbuildcommands{("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")}-- 不同配置下的预定义不同filter "configurations:Debug"defines "YT_DEBUG"runtime "Debug"symbols "On"filter "configurations:Release"defines "YT_RELEASE"runtime "Release"optimize "On"filter "configurations:Dist"defines "YT_DIST"runtime "Release"optimize "On"project "Sandbox"location "Sandbox"kind "ConsoleApp"language "C++"staticruntime "Off"targetdir ("bin/" .. outputdir .. "/%{prj.name}")objdir ("bin-int/" .. outputdir .. "/%{prj.name}")files{"%{prj.name}/src/**.h","%{prj.name}/src/**.cpp"}-- 同样包含spdlog头文件includedirs{"YOTOEngine/vendor/spdlog-1.x/include","YOTOEngine/src","YOTOEngine/vendor","%{IncludeDir.glm}"}-- 引用YOTOEnginelinks{"YOTOEngine","GLFW","opengl32.lib"}filter "system:windows"cppdialect "C++17"systemversion "latest"defines{"YT_PLATFORM_WINDOWS"}filter "configurations:Debug"defines "YT_DEBUG"runtime "Debug"symbols "On"filter "configurations:Release"defines "YT_RELEASE"runtime "Release"optimize "On"filter "configurations:Dist"defines "YT_DIST"runtime "Release"optimize "On"
vendor/ImGui的premake5.la添加 defines { "IMGUI_API=__declspec(dllexport)" }
project "ImGui"kind "StaticLib"language "C++"staticruntime "off"targetdir ("bin/" .. outputdir .. "/%{prj.name}")objdir ("bin-int/" .. outputdir .. "/%{prj.name}")defines { "IMGUI_API=__declspec(dllexport)" }files{"imconfig.h","imgui.h","imgui.cpp","imgui_draw.cpp","imgui_internal.h","imgui_tables.cpp","imgui_widgets.cpp","imstb_rectpack.h","imstb_textedit.h","imstb_truetype.h","imgui_demo.cpp"}filter "system:windows"systemversion "latest"cppdialect "C++17"filter "system:linux"pic "On"systemversion "latest"cppdialect "C++17"filter "configurations:Debug"runtime "Debug"symbols "on"filter "configurations:Release"runtime "Release"optimize "on"filter "configurations:Dist"runtime "Release"optimize "on"symbols "off"
测试:
点dockspace
点出来几个窗口随便摆摆:
能拖出去: