Hazel game engine (022) Docking and Viewports of ImGui

If there are errors in the code, terminology, etc. in the text, please correct me

foreword

  • of this program

    In order to use the new features of imgui: docking and multiple sub-UI windows, you need to change what you did before 015016 (it is much more complicated to write the key ImGui code yourself to have the docking feature), so you need to use the cpp already written by ImGui to directly use ImGui new features. (probably wrong)

  • Modified class diagram

    Please add a picture description

    It can be seen that ExamplerLayer also depends on ImGUI, because it can also have ImGui windows, and each Layer can have one or more ImGui windows

project related

code change

  • delete

    ImGuiOpenGLRenderer class

  • ImGuiBuild

    Add ImGuiBuild.cpp

    #include "hzpch.h"
    
    #define IMGUI_IMPL_OPENGL_LOADER_GLAD
    #include "backends/imgui_impl_opengl3.cpp"
    #include "backends/imgui_impl_glfw.cpp"
    
  • LayerModification

    class HAZEL_API Layer
    {
          
          
        public:
        Layer(const std::string& name = "Layer");
        virtual ~Layer();
    
        virtual void OnAttach() {
          
          } // 应用添加此层执行
        virtual void OnDetach() {
          
          } // 应用分离此层执行
        virtual void OnUpdate() {
          
          } // 每层更新
        virtual void OnImGuiRender() {
          
          }// 每层都可以拥有自己的UI窗口 !
    
  • ImGuiLayer

    • Delete the event handler (016 done)
    • Delete the key-value correspondence between ImGui and GLFW (the code in the OnAttach function)
    • Delete the OnUpdate and OnEvent functions, no need
    • Add OnImGuiRender(), Begin(), End() to render ImGui
    #include "hzpch.h"
    #include "ImGuiLayer.h"
    #include "imgui.h"
    #include "Hazel/Application.h"
    #include "GLFW/glfw3.h"
    #include "glad/glad.h"
    #include "backends/imgui_impl_glfw.h"
    #include "backends/imgui_impl_opengl3.h"
    namespace Hazel {
          
          
    	ImGuiLayer::ImGuiLayer()
    		: Layer("ImGuiLayer"){
          
          }
    	ImGuiLayer::~ImGuiLayer(){
          
          }
    	// 初始化设置ImGui所有窗口的属性,使ImGui窗口能有停靠、独立的UI窗口特性
    	void ImGuiLayer::OnAttach(){
          
          
            // 不需要手动写ImGui的键值对应GLFW的键值、ImGui接收GLFW窗口事件,ImGui自动完成
    		// 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(app.GetWindow().GetWidth(), 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);// 当前OnImGuiRender层显示DemoUI窗口
    	}
    }
    
  • Application

    	private:
    		bool OnWindowClose(WindowCloseEvent& e); // 处理窗口关闭事件的函数
    	private:
    		std::unique_ptr<Window> m_Window;
    		ImGuiLayer* m_ImGuiLayer; // 拥有ImGuiLayer控制权
    		bool m_Running = true;
    		LayerStack m_LayerStack;
    	private:
    		static Application* s_Instance;
    
    Application::Application()
    {
          
          
        HZ_CORE_ASSERT(!s_Instance, "引用已经存在");
        s_Instance = this;
    
        // 1.1Application创建窗口
        m_Window = std::unique_ptr<Window>(Window::Create());
        // 1.2Application设置窗口事件的回调函数
        m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
    
        // 将ImGui层放在最后
        m_ImGuiLayer = new ImGuiLayer();
        PushOverlay(m_ImGuiLayer);
    }
    void Application::Run()
    {
          
          
        while (m_Running)
        {
          
          
            glClearColor(1, 0, 1, 1);
            glClear(GL_COLOR_BUFFER_BIT);
    
            // 从前往后顺序更新层
            for (Layer* layer : m_LayerStack)
                layer->OnUpdate();
    		
            // 从前往后顺序更新层的ImGui 新增///
            
            m_ImGuiLayer->Begin();
            for (Layer* layer : m_LayerStack)
                layer->OnImGuiRender();
            m_ImGuiLayer->End();
    
            m_Window->OnUpdate();	// 更新glfw
        }
    }
    

Fix LayerStack bug

When the position of the vector in memory changes, save the std::vector<Layer*>::iterator m_LayerInsert; iterator pointing to the head of the vector will be invalid, so use the int insert position subscript instead, and the PushLayer function is no longer inserted at the front , but in the back

		std::vector<Layer*>::iterator end() {
    
     return m_Layers.end(); }
	private:
		std::vector<Layer*> m_Layers;
		// std::vector<Layer*>::iterator m_LayerInsert;
		unsigned int m_LayerInsertIndex = 0;
	};
void LayerStack::PushLayer(Layer* layer)
{
    
    
	// m_LayerInsert = m_Layers.emplace(m_LayerInsert, layer);
    // emplace在vector容器指定位置之前插入一个新的元素。返回插入元素的位置
    // 插入 1 2 3,vector是 1 2 3
    m_Layers.emplace(m_Layers.begin() + m_LayerInsertIndex, layer);
    m_LayerInsertIndex++;
}
void LayerStack::PushOverlay(Layer* overlay)
{
    
    
    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_LayerInsert--;
        m_LayerInsertIndex--;
    }
}

Display DemoUI effect

Because the OnImGuiRender function of all Layers is traversed in the Application, and the OnImGuiRender of ImGuiLayer displays the DemoUI window, and the OnAttach function of ImGuiLayer initializes and sets the properties of all ImGui windows, so that the ImGui window can have docking and independent UI window characteristics

Please add a picture description

homework

  • question

    Although ImGui is statically linked to Hazel, and Hazel is loaded by Sandbox as a dll library , why does the ImGui function that uses Hazel link in the Sandbox project report that the function definition cannot be found?

    #include <Hazel.h>
    #include "imgui/imgui.h"
    class ExampleLayer : public Hazel::Layer{
          
          
    public:
    	ExampleLayer()
    		: Layer("Example"){
          
          }
    	void OnUpdate() override{
          
          
    		//HZ_INFO("ExampleLayer::Update");
    		if (Hazel::Input::IsKeyPressed(HZ_KEY_A)) {
          
          
    			HZ_TRACE("A键按下(poll)");
    		}
    	}
    	void OnEvent(Hazel::Event& event) override{
          
          
    		//HZ_TRACE("examplayer:{0}", event);
    		if (event.GetEventType() == Hazel::EventType::KeyPressed) {
          
          
    			Hazel::KeyPressedEvent& e = (Hazel::KeyPressedEvent&)event;
    			if (e.GetKeyCode() == HZ_KEY_A) {
          
          
    				HZ_TRACE("A键按下(event)");
    			}
    			HZ_TRACE("{0}",(char)e.GetKeyCode());
    		}
    	}
    	// 每个层都可以有自己的UI窗口// 会报错///
    	virtual void OnImGuiRender() override{
          
          
    		ImGui::Begin("Test");
    		ImGui::Text("Hello World");
    		ImGui::End();
    	}
    };
    
  • Answer 1 statement

    • Answer from the bottom of the YouTube video

      The Symbols from ImGui are not being export from Hazel into Sandbox. adding a defines to premake file of ImGui  `defines { "IMGUI_API=__declspec(dllexport)" }`  should export the symbols from ImGui to Hazel which will export all Hazel and ImGui symbols to Sandbox.
      

      Symbols in ImGui are not exported from Hazel to Sandbox. Adding definitions in ImGui's prefab file defines { "IMGUI_API=__declspec(dllexport)" }should export symbols from ImGui to Hazel, which will export all Hazel and ImGui symbols to Sandbox.

  • Answer 2 statement

    Section 025

    ImGui is statically linked to Hazel.dll, but Hazel.dll has the ability to delete the function definition content that is not exported in ImGui, so if the content of ImGui is used in the exe file of the linked dll file, the link error will occur.

    Simply put: the function definition content of ImGui is not exported

Guess you like

Origin blog.csdn.net/qq_34060370/article/details/131388699