![]()
引言
上一节我们讨论了 ImGUI 并运行了官方示例,今天我们来为我们的引擎编写 ImGUI 事件。
事件声明
在头文件 ImGuiLayer.h 声明 ImGUI 的交互事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #pragma once
#include "../Layer.h"
#include "../Events/KeyEvent.h" #include "../Events/MouseEvent.h" #include "../Events/ApplicationEvent.h"
namespace Infinite {
class INFINITE_API ImGuiLayer : public Layer { public: ImGuiLayer(); ~ImGuiLayer();
void OnAttach(); void OnDetach(); void OnUpdate(); void OnEvent(Event& event); private: + bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e); + bool OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e); + bool OnMouseMovedEvent(MouseMovedEvent& e); + bool OnMouseScrolledEvent(MouseScrolledEvent& e); + bool OnKeyPressedEvent(KeyPressedEvent& e); + bool OnKeyReleasedEvent(KeyReleasedEvent& e); + bool OnKeyTypedEvent(KeyTypedEvent& e); + bool OnWindowResizeEvent(WindowResizeEvent& e);
private: float m_Time = 0.0f;
}; }
|
事件实现
在 ImGuiLayer.cpp 中添加头文件和事件的模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| #include "ifnpch.h" #include "ImGuiLayer.h"
#include "../imgui.h" #include "Platform/OpenGL/ImGuiOpenGLRenderer.h"
// TEMPORARY +#include <GLFW/glfw3.h> +#include <glad/glad.h>
#include "../Application.h"
namespace Infinite {
ImGuiLayer::ImGuiLayer() : Layer("ImGuiLayer") {
}
ImGuiLayer::~ImGuiLayer() {
}
void ImGuiLayer::OnAttach() { ImGui::CreateContext(); ImGui::StyleColorsDark();
ImGuiIO& io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
// TEMPORARY: should eventually use Infinite key codes io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
ImGui_ImplOpenGL3_Init("#version 410"); }
void ImGuiLayer::OnDetach() {
}
void ImGuiLayer::OnUpdate() { ImGuiIO& io = ImGui::GetIO(); Application& app = Application::Get(); io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
float time = (float)glfwGetTime(); io.DeltaTime = m_Time > 0.0f ? (time - m_Time) : (1.0f / 60.0f); m_Time = time;
ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame();
static bool show = true; ImGui::ShowDemoWindow(&show);
ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); }
+ void ImGuiLayer::OnEvent(Event& event) + { + + }
+ bool ImGuiLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e) + { + + }
+ bool ImGuiLayer::OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e) + { + + }
+ bool ImGuiLayer::OnMouseMovedEvent(MouseMovedEvent& e) + { + + }
+ bool ImGuiLayer::OnMouseScrolledEvent(MouseScrolledEvent& e) + { + + }
+ bool ImGuiLayer::OnKeyPressedEvent(KeyPressedEvent& e) + { + + }
+ bool ImGuiLayer::OnKeyReleasedEvent(KeyReleasedEvent& e) + { + + }
+ bool ImGuiLayer::OnKeyTypedEvent(KeyTypedEvent& e) + { + + }
+ bool ImGuiLayer::OnWindowResizeEvent(WindowResizeEvent& e) + { + + } }
|
下面我们依次实现这些事件:
Event
1 2 3 4 5 6 7 8 9 10 11 12
| void ImGuiLayer::OnEvent(Event& event) { EventDispatcher dispatcher(event); dispatcher.Dispatch<MouseButtonPressedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonPressedEvent)); dispatcher.Dispatch<MouseButtonReleasedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonReleasedEvent)); dispatcher.Dispatch<MouseMovedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnMouseMovedEvent)); dispatcher.Dispatch<MouseScrolledEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnMouseScrolledEvent)); dispatcher.Dispatch<KeyPressedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnKeyPressedEvent)); dispatcher.Dispatch<KeyTypedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnKeyTypedEvent)); dispatcher.Dispatch<KeyReleasedEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnKeyReleasedEvent)); dispatcher.Dispatch<WindowResizeEvent>(IFN_BIND_EVENT_FN(ImGuiLayer::OnWindowResizeEvent)); }
|
这里的 IFN_BIND_EVENT_FN 则在 Core.h 中定义:
1
| #define IFN_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)
|
Mouse
1 2 3 4 5 6 7
| bool ImGuiLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.MouseDown[e.GetMouseButton()] = true;
return false; }
|
1 2 3 4 5 6 7
| bool ImGuiLayer::OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.MouseDown[e.GetMouseButton()] = false;
return false; }
|
MouseMoved
1 2 3 4 5 6 7
| bool ImGuiLayer::OnMouseMovedEvent(MouseMovedEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.MousePos = ImVec2(e.GetX(), e.GetY());
return false; }
|
1 2 3 4 5 6 7 8
| bool ImGuiLayer::OnMouseScrolledEvent(MouseScrolledEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.MouseWheelH += e.GetXOffset(); io.MouseWheel += e.GetYOffset();
return false; }
|
Key
KeyPressed
1 2 3 4 5 6 7 8 9 10 11
| bool ImGuiLayer::OnKeyPressedEvent(KeyPressedEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.KeysDown[e.GetKeyCode()] = true;
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; return false; }
|
KeyReleased
1 2 3 4 5 6 7
| bool ImGuiLayer::OnKeyReleasedEvent(KeyReleasedEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.KeysDown[e.GetKeyCode()] = false;
return false; }
|
KeyTyped
KeyTyped 的实现比较复杂,首先我们需要先在 Event.h 添加 KeyTyped 枚举类型:
1 2 3 4 5 6 7 8
| enum class EventType { None = 0, WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved, AppTick, AppUpdate, AppRender, + KeyPressed, KeyReleased, KeyTyped, MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled };
|
接着在 KeyEvent.h 中添加事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class INFINITE_API KeyTypedEvent : public KeyEvent { public: KeyTypedEvent(int keycode) : KeyEvent(keycode) {}
std::string ToString() const override { std::stringstream ss; ss << "KeyTypedEvent: " << m_KeyCode; return ss.str(); }
EVENT_CLASS_TYPE(KeyTyped) };
|
最后回到 ImGuiLayer.cpp 实现事件:
1 2 3 4 5 6 7 8 9
| bool ImGuiLayer::OnKeyTypedEvent(KeyTypedEvent& e) { ImGuiIO& io = ImGui::GetIO(); int keycode = e.GetKeyCode(); if (keycode > 0 && keycode < 0x10000) io.AddInputCharacter((unsigned short)keycode);
return false; }
|
Windows
1 2 3 4 5 6 7 8 9
| bool ImGuiLayer::OnWindowResizeEvent(WindowResizeEvent& e) { ImGuiIO& io = ImGui::GetIO(); io.DisplaySize = ImVec2(e.GetWidth(), e.GetHeight()); io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); glViewport(0, 0 , e.GetWidth(), e.GetHeight());
return false; }
|
预生成文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| workspace "Infinite" architecture "x64" startproject "Sandbox"
configurations { "Debug", "Release", "Dist" }
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
-- Include directories relative to root folder (solution directory) IncludeDir = {} IncludeDir["GLFW"] = "Infinite/vendor/GLFW/include" IncludeDir["GLAD"] = "Infinite/vendor/GLAD/include" IncludeDir["ImGui"] = "Infinite/vendor/imgui/include"
include "Infinite/vendor/GLFW" include "Infinite/vendor/GLAD" include "Infinite/vendor/imgui"
project "Infinite" location "Infinite" kind "SharedLib" language "C++" + staticruntime "off"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
pchheader "ifnpch.h" pchsource "Infinite/src/ifnpch.cpp"
files { "%{prj.name}/src/**.h", "%{prj.name}/src/**.cpp" }
includedirs { "%{prj.name}/src", "%{prj.name}/vendor/spdlog/include", "%{IncludeDir.GLFW}", "%{IncludeDir.GLAD}", "%{IncludeDir.ImGui}" }
links { "GLFW", "GLAD", "ImGui", "opengl32.lib" }
filter "system:windows" cppdialect "C++17" systemversion "latest"
defines { "IFN_PLATFORM_WINDOWS", "IFN_BUILD_DLL", "GLFW_INCLUDE_NONE" }
postbuildcommands { + ("{COPY} %{cfg.buildtarget.relpath} \"../bin/" .. outputdir .. "/Sandbox/\"") }
filter "configurations:Debug" defines "IFN_DEBUG" + runtime "Debug" symbols "On"
filter "configurations:Release" defines "IFN_RELEASE" + runtime "Release" optimize "On"
filter "configurations:Dist" defines "IFN_DIST" + runtime "Release" optimize "On"
project "Sandbox" location "Sandbox" kind "ConsoleApp" + staticruntime "off"
language "C++"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
files { "%{prj.name}/src/**.h", "%{prj.name}/src/**.cpp" }
includedirs { "Infinite/vendor/spdlog/include", "Infinite/src/Infinite", "Infinite/src/Events", "Infinite/src/**.h", "Infinite/src/**.cpp" }
links { "Infinite" }
filter "system:windows" cppdialect "C++17" systemversion "latest"
defines { "IFN_PLATFORM_WINDOWS" }
filter "configurations:Debug" defines "IFN_DEBUG" + runtime "Debug" symbols "On"
filter "configurations:Release" defines "IFN_RELEASE" + runtime "Release" optimize "On"
filter "configurations:Dist" defines "IFN_DIST" + runtime "Release" optimize "On"
|
调试
在调试过程中由于没有给事件实现添加作用域,运行时报错外部符号无法解析,以后需要多加注意。
Mouse
![]()
![]()
Key
![]()