From 762a7649170b2394fa26207810b249bbe8933ba4 Mon Sep 17 00:00:00 2001 From: Nomango Date: Tue, 30 Jul 2019 14:58:24 +0800 Subject: [PATCH] make Window singleton & make ImGuiLayer more easily to use --- kiwano-imgui/kiwano-imgui.h | 2 +- kiwano-imgui/kiwano-imgui.vcxproj | 6 +- kiwano-imgui/kiwano-imgui.vcxproj.filters | 18 +- kiwano-imgui/src/ImGuiLayer.cpp | 125 ------- kiwano-imgui/src/ImGuiLayer.h | 23 +- kiwano-imgui/src/ImGuiModule.cpp | 305 ++++++++++++++++++ .../src/{ImGuiView.h => ImGuiModule.h} | 38 ++- kiwano-imgui/src/ImGuiView.cpp | 117 ------- .../src/{imgui_impl.hpp => imgui_impl.h} | 0 kiwano/2d/Scene.cpp | 31 -- kiwano/2d/Scene.h | 11 - kiwano/2d/include-forwards.h | 50 +-- kiwano/Kiwano.vcxproj | 1 + kiwano/Kiwano.vcxproj.filters | 3 + kiwano/base/Component.h | 4 +- kiwano/base/Input.cpp | 22 +- kiwano/base/Input.h | 6 +- kiwano/base/types.h | 71 ++++ kiwano/base/window.cpp | 25 ++ kiwano/base/window.h | 11 +- kiwano/platform/Application.cpp | 10 +- kiwano/ui/Button.cpp | 5 +- samples/ImGuiSample/MainScene.h | 2 +- samples/ImGuiSample/main.cpp | 3 +- 24 files changed, 475 insertions(+), 414 deletions(-) create mode 100644 kiwano-imgui/src/ImGuiModule.cpp rename kiwano-imgui/src/{ImGuiView.h => ImGuiModule.h} (75%) delete mode 100644 kiwano-imgui/src/ImGuiView.cpp rename kiwano-imgui/src/{imgui_impl.hpp => imgui_impl.h} (100%) create mode 100644 kiwano/base/types.h diff --git a/kiwano-imgui/kiwano-imgui.h b/kiwano-imgui/kiwano-imgui.h index 1c947d2a..75111546 100644 --- a/kiwano-imgui/kiwano-imgui.h +++ b/kiwano-imgui/kiwano-imgui.h @@ -22,7 +22,7 @@ #include "kiwano/kiwano.h" #include "src/ImGuiLayer.h" -#include "src/ImGuiView.h" +#include "src/ImGuiModule.h" // ImGui #include "third-party/ImGui/imgui.h" diff --git a/kiwano-imgui/kiwano-imgui.vcxproj b/kiwano-imgui/kiwano-imgui.vcxproj index 3ce24ae7..38d06357 100644 --- a/kiwano-imgui/kiwano-imgui.vcxproj +++ b/kiwano-imgui/kiwano-imgui.vcxproj @@ -3,8 +3,8 @@ - - + + @@ -16,7 +16,7 @@ - + diff --git a/kiwano-imgui/kiwano-imgui.vcxproj.filters b/kiwano-imgui/kiwano-imgui.vcxproj.filters index 3ed53b00..4a6acaaf 100644 --- a/kiwano-imgui/kiwano-imgui.vcxproj.filters +++ b/kiwano-imgui/kiwano-imgui.vcxproj.filters @@ -12,9 +12,6 @@ - - src - src @@ -24,9 +21,6 @@ src - - src - third-party\ImGui @@ -46,6 +40,12 @@ third-party\ImGui + + src + + + src + @@ -57,9 +57,6 @@ src - - src - third-party\ImGui @@ -72,5 +69,8 @@ third-party\ImGui + + src + \ No newline at end of file diff --git a/kiwano-imgui/src/ImGuiLayer.cpp b/kiwano-imgui/src/ImGuiLayer.cpp index 7d67af02..8c5744fc 100644 --- a/kiwano-imgui/src/ImGuiLayer.cpp +++ b/kiwano-imgui/src/ImGuiLayer.cpp @@ -24,146 +24,21 @@ namespace kiwano { namespace imgui { - - namespace - { - Map mouse_buttons = - { - { MouseButton::Left, 0 }, - { MouseButton::Right, 1 }, - { MouseButton::Middle, 2 } - }; - } - ImGuiLayer::ImGuiLayer() { - target_window_ = Renderer::Instance().GetTargetWindow(); SetSwallowEvents(true); } ImGuiLayer::~ImGuiLayer() { - ImGuiView::Instance().RemoveLayer(this); - } - - void ImGuiLayer::OnMouseButtonDown(int btn, Point const& p) - { - if (!ImGui::IsAnyMouseDown() && ::GetCapture() == nullptr) - ::SetCapture(target_window_); - - KGE_ASSERT(mouse_buttons.find(btn) != mouse_buttons.end()); - ImGui::GetIO().MouseDown[mouse_buttons[btn]] = true; - } - - void ImGuiLayer::OnMouseButtonUp(int btn, Point const& p) - { - KGE_ASSERT(mouse_buttons.find(btn) != mouse_buttons.end()); - ImGui::GetIO().MouseDown[mouse_buttons[btn]] = false; - - if (!ImGui::IsAnyMouseDown() && ::GetCapture() == target_window_) - ::ReleaseCapture(); - } - - void ImGuiLayer::OnMouseWheel(float wheel) - { - ImGui::GetIO().MouseWheel += wheel; - } - - void ImGuiLayer::OnKeyDown(int key) - { - KGE_ASSERT(key < 256); - ImGui::GetIO().KeysDown[key] = 1; - } - - void ImGuiLayer::OnKeyUp(int key) - { - KGE_ASSERT(key < 256); - ImGui::GetIO().KeysDown[key] = 0; - } - - void ImGuiLayer::OnChar(char c) - { - ImGui::GetIO().AddInputCharacter(c); - } - - void ImGuiLayer::OnUpdate(Duration dt) - { - ImGuiIO& io = ImGui::GetIO(); - - // Setup time step - io.DeltaTime = dt.Seconds(); - - // Read keyboard modifiers inputs - io.KeyCtrl = Input::Instance().IsDown(KeyCode::Ctrl); - io.KeyShift = Input::Instance().IsDown(KeyCode::Shift); - io.KeyAlt = Input::Instance().IsDown(KeyCode::Alt); - io.KeySuper = false; - // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. - - // Update OS mouse position - UpdateMousePos(); - - // Update OS mouse cursor with the cursor requested by imgui - UpdateMouseCursor(); } void ImGuiLayer::OnRender() { - ImGuiView::Instance().NewFrame(); - for (const auto& pipeline : pipelines_) { pipeline.second(); } - - ImGuiView::Instance().Render(); - } - - void ImGuiLayer::UpdateMousePos() - { - ImGuiIO& io = ImGui::GetIO(); - - // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - if (io.WantSetMousePos) - { - POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; - HWND hwnd = target_window_; - ::ClientToScreen(hwnd, &pos); - ::SetCursorPos(pos.x, pos.y); - } - - Point pos = Input::Instance().GetMousePos(); - io.MousePos = ImVec2(pos.x, pos.y); - } - - void ImGuiLayer::UpdateMouseCursor() - { - static ImGuiMouseCursor last_mouse_cursor = ImGuiMouseCursor_COUNT; - - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - - if (last_mouse_cursor != imgui_cursor) - { - last_mouse_cursor = imgui_cursor; - - if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) - return; - - MouseCursor cursor = MouseCursor::Arrow; - switch (imgui_cursor) - { - case ImGuiMouseCursor_Arrow: cursor = MouseCursor::Arrow; break; - case ImGuiMouseCursor_TextInput: cursor = MouseCursor::TextInput; break; - case ImGuiMouseCursor_ResizeAll: cursor = MouseCursor::SizeAll; break; - case ImGuiMouseCursor_ResizeEW: cursor = MouseCursor::SizeWE; break; - case ImGuiMouseCursor_ResizeNS: cursor = MouseCursor::SizeNS; break; - case ImGuiMouseCursor_ResizeNESW: cursor = MouseCursor::SizeNESW; break; - case ImGuiMouseCursor_ResizeNWSE: cursor = MouseCursor::SizeNWSE; break; - case ImGuiMouseCursor_Hand: cursor = MouseCursor::Hand; break; - } - - GetScene()->SetMouseCursor(cursor); - } } void ImGuiLayer::AddItem(ImGuiPipeline const& item, String const& name) diff --git a/kiwano-imgui/src/ImGuiLayer.h b/kiwano-imgui/src/ImGuiLayer.h index 7188f82a..761f666b 100644 --- a/kiwano-imgui/src/ImGuiLayer.h +++ b/kiwano-imgui/src/ImGuiLayer.h @@ -28,14 +28,12 @@ namespace kiwano using ImGuiPipeline = Closure; - class ImGuiView; - class ImGuiLayer : public Layer { - friend class ImGuiView; - public: + ImGuiLayer(); + virtual ~ImGuiLayer(); // 添加 ImGui 元素 @@ -53,26 +51,9 @@ namespace kiwano void RemoveAllItems(); public: - void OnMouseButtonDown(int btn, Point const& p) override; - void OnMouseButtonUp(int btn, Point const& p) override; - void OnMouseWheel(float wheel) override; - - void OnKeyDown(int key) override; - void OnKeyUp(int key) override; - void OnChar(char c) override; - - public: - void OnUpdate(Duration dt) override; void OnRender() override; - void UpdateMousePos(); - void UpdateMouseCursor(); - protected: - ImGuiLayer(); - - protected: - HWND target_window_; Map pipelines_; }; } diff --git a/kiwano-imgui/src/ImGuiModule.cpp b/kiwano-imgui/src/ImGuiModule.cpp new file mode 100644 index 00000000..0d820192 --- /dev/null +++ b/kiwano-imgui/src/ImGuiModule.cpp @@ -0,0 +1,305 @@ +// Copyright (C) 2019 Nomango + +#include "../kiwano-imgui.h" +#include "imgui_impl.h" + +#include +#pragma comment(lib, "xinput") + +// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. +#ifndef WM_MOUSEHWHEEL +# define WM_MOUSEHWHEEL 0x020E +#endif + +#ifndef DBT_DEVNODES_CHANGED +# define DBT_DEVNODES_CHANGED 0x0007 +#endif + +namespace kiwano +{ + namespace imgui + { + ImGuiModule::ImGuiModule() + : has_gamepad_(false) + , want_update_has_gamepad_(false) + , target_window_(nullptr) + { + } + + void ImGuiModule::SetupComponent(Application* app) + { + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + + // Setup Platform/Renderer bindings + Init(app->GetWindow()->GetHandle()); + + target_window_ = Renderer::Instance().GetTargetWindow(); + } + + void ImGuiModule::DestroyComponent() + { + ImGui_Impl_Shutdown(); + ImGui::DestroyContext(); + } + + void ImGuiModule::BeforeUpdate(float dt) + { + ImGuiIO& io = ImGui::GetIO(); + + // Setup time step + io.DeltaTime = dt; + + // Read keyboard modifiers inputs + io.KeyCtrl = Input::Instance().IsDown(KeyCode::Ctrl); + io.KeyShift = Input::Instance().IsDown(KeyCode::Shift); + io.KeyAlt = Input::Instance().IsDown(KeyCode::Alt); + io.KeySuper = false; + // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. + + // Update OS mouse position + UpdateMousePos(); + + // Update OS mouse cursor with the cursor requested by imgui + UpdateMouseCursor(); + + // Update game controllers (if enabled and available) + UpdateGamepads(); + } + + void ImGuiModule::Init(HWND hwnd) + { + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_win32"; + io.ImeWindowHandle = hwnd; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_Tab] = KeyCode::Tab; + io.KeyMap[ImGuiKey_LeftArrow] = KeyCode::Left; + io.KeyMap[ImGuiKey_RightArrow] = KeyCode::Right; + io.KeyMap[ImGuiKey_UpArrow] = KeyCode::Up; + io.KeyMap[ImGuiKey_DownArrow] = KeyCode::Down; + io.KeyMap[ImGuiKey_Delete] = KeyCode::Delete; + io.KeyMap[ImGuiKey_Backspace] = KeyCode::Back; + io.KeyMap[ImGuiKey_Space] = KeyCode::Space; + io.KeyMap[ImGuiKey_Enter] = KeyCode::Enter; + io.KeyMap[ImGuiKey_Escape] = KeyCode::Esc; + io.KeyMap[ImGuiKey_A] = KeyCode::A; + io.KeyMap[ImGuiKey_C] = KeyCode::C; + io.KeyMap[ImGuiKey_V] = KeyCode::V; + io.KeyMap[ImGuiKey_X] = KeyCode::X; + io.KeyMap[ImGuiKey_Y] = KeyCode::Y; + io.KeyMap[ImGuiKey_Z] = KeyCode::Z; + + ImGui_Impl_Init(Renderer::Instance()); + } + + void ImGuiModule::BeforeRender() + { + NewFrame(); + } + + void ImGuiModule::AfterRender() + { + Render(); + } + + void ImGuiModule::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) + { + if (ImGui::GetCurrentContext() == NULL) + return; + + ImGuiIO& io = ImGui::GetIO(); + switch (msg) + { + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: + { + int button = 0; + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } + if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wparam) == XBUTTON1) ? 3 : 4; } + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + ::SetCapture(hwnd); + + io.MouseDown[button] = true; + break; + } + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + int button = 0; + if (msg == WM_LBUTTONUP) { button = 0; } + if (msg == WM_RBUTTONUP) { button = 1; } + if (msg == WM_MBUTTONUP) { button = 2; } + if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wparam) == XBUTTON1) ? 3 : 4; } + io.MouseDown[button] = false; + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + ::ReleaseCapture(); + break; + } + case WM_MOUSEWHEEL: + { + io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA; + break; + } + case WM_MOUSEHWHEEL: + { + io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA; + break; + } + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + if (wparam < 256) + io.KeysDown[wparam] = 1; + break; + } + case WM_KEYUP: + case WM_SYSKEYUP: + { + if (wparam < 256) + io.KeysDown[wparam] = 0; + break; + } + case WM_CHAR: + { + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + io.AddInputCharacter((unsigned int)wparam); + break; + } + case WM_SETCURSOR: + { + if (LOWORD(lparam) == HTCLIENT) + { + UpdateMouseCursor(); + } + break; + } + case WM_DEVICECHANGE: + { + if ((UINT)wparam == DBT_DEVNODES_CHANGED) + want_update_has_gamepad_ = true; + break; + } + } + } + + void ImGuiModule::NewFrame() + { + ImGui_Impl_NewFrame(); + + ImGuiIO& io = ImGui::GetIO(); + KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); + + // Setup display size (every frame to accommodate for window resizing) + Size display_size = Renderer::Instance().GetOutputSize(); + io.DisplaySize = ImVec2(display_size.x, display_size.y); + + ImGui::NewFrame(); + } + + void ImGuiModule::Render() + { + ImGui::Render(); + + ImGui_Impl_RenderDrawData(ImGui::GetDrawData()); + } + + void ImGuiModule::UpdateMousePos() + { + ImGuiIO& io = ImGui::GetIO(); + + // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + { + POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + ::ClientToScreen(target_window_, &pos); + ::SetCursorPos(pos.x, pos.y); + } + + Point pos = Input::Instance().GetMousePos(); + io.MousePos = ImVec2(pos.x, pos.y); + } + + void ImGuiModule::UpdateMouseCursor() + { + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return; + + MouseCursor cursor = MouseCursor::Arrow; + switch (ImGui::GetMouseCursor()) + { + case ImGuiMouseCursor_Arrow: cursor = MouseCursor::Arrow; break; + case ImGuiMouseCursor_TextInput: cursor = MouseCursor::TextInput; break; + case ImGuiMouseCursor_ResizeAll: cursor = MouseCursor::SizeAll; break; + case ImGuiMouseCursor_ResizeEW: cursor = MouseCursor::SizeWE; break; + case ImGuiMouseCursor_ResizeNS: cursor = MouseCursor::SizeNS; break; + case ImGuiMouseCursor_ResizeNESW: cursor = MouseCursor::SizeNESW; break; + case ImGuiMouseCursor_ResizeNWSE: cursor = MouseCursor::SizeNWSE; break; + case ImGuiMouseCursor_Hand: cursor = MouseCursor::Hand; break; + } + + Window::Instance().SetMouseCursor(cursor); + } + void ImGuiModule::UpdateGamepads() + { + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (want_update_has_gamepad_) + { + XINPUT_CAPABILITIES caps; + has_gamepad_ = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); + want_update_has_gamepad_ = false; + } + + XINPUT_STATE xinput_state; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (has_gamepad_ && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + +#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } +#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); +#undef MAP_BUTTON +#undef MAP_ANALOG + } + } + } +} \ No newline at end of file diff --git a/kiwano-imgui/src/ImGuiView.h b/kiwano-imgui/src/ImGuiModule.h similarity index 75% rename from kiwano-imgui/src/ImGuiView.h rename to kiwano-imgui/src/ImGuiModule.h index af5bbbb8..977ba357 100644 --- a/kiwano-imgui/src/ImGuiView.h +++ b/kiwano-imgui/src/ImGuiModule.h @@ -24,21 +24,11 @@ namespace kiwano { namespace imgui { - class ImGuiLayer; - - class ImGuiView - : public Singleton + class ImGuiModule + : public Singleton , public Component { - KGE_DECLARE_SINGLETON(ImGuiView); - - friend class ImGuiLayer; - - public: - // 创建 ImGui 图层 - ImGuiLayerPtr CreateLayer( - Scene* scene /* 指定场景 */ - ); + KGE_DECLARE_SINGLETON(ImGuiModule); private: void Init(HWND hwnd); @@ -47,15 +37,31 @@ namespace kiwano void Render(); - void RemoveLayer(ImGuiLayer* layer); - public: + ImGuiModule(); + void SetupComponent(Application* app) override; void DestroyComponent() override; + void BeforeUpdate(float dt) override; + + void BeforeRender() override; + + void AfterRender() override; + + void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override; + + void UpdateMousePos(); + + void UpdateMouseCursor(); + + void UpdateGamepads(); + private: - Map layers_; + bool has_gamepad_; + bool want_update_has_gamepad_; + HWND target_window_; }; } } diff --git a/kiwano-imgui/src/ImGuiView.cpp b/kiwano-imgui/src/ImGuiView.cpp deleted file mode 100644 index 27298556..00000000 --- a/kiwano-imgui/src/ImGuiView.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (C) 2019 Nomango - -#include "../kiwano-imgui.h" -#include "imgui_impl.hpp" - -namespace kiwano -{ - namespace imgui - { - - void ImGuiView::SetupComponent(Application* app) - { - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - - // Setup Platform/Renderer bindings - Init(app->GetWindow()->GetHandle()); - } - - void ImGuiView::DestroyComponent() - { - ImGui_Impl_Shutdown(); - ImGui::DestroyContext(); - } - - void ImGuiView::Init(HWND hwnd) - { - ImGuiIO& io = ImGui::GetIO(); - io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) - io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) - io.BackendPlatformName = "imgui_impl_win32"; - io.ImeWindowHandle = hwnd; - - // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. - io.KeyMap[ImGuiKey_Tab] = KeyCode::Tab; - io.KeyMap[ImGuiKey_LeftArrow] = KeyCode::Left; - io.KeyMap[ImGuiKey_RightArrow] = KeyCode::Right; - io.KeyMap[ImGuiKey_UpArrow] = KeyCode::Up; - io.KeyMap[ImGuiKey_DownArrow] = KeyCode::Down; - io.KeyMap[ImGuiKey_Delete] = KeyCode::Delete; - io.KeyMap[ImGuiKey_Backspace] = KeyCode::Back; - io.KeyMap[ImGuiKey_Space] = KeyCode::Space; - io.KeyMap[ImGuiKey_Enter] = KeyCode::Enter; - io.KeyMap[ImGuiKey_Escape] = KeyCode::Esc; - io.KeyMap[ImGuiKey_A] = KeyCode::A; - io.KeyMap[ImGuiKey_C] = KeyCode::C; - io.KeyMap[ImGuiKey_V] = KeyCode::V; - io.KeyMap[ImGuiKey_X] = KeyCode::X; - io.KeyMap[ImGuiKey_Y] = KeyCode::Y; - io.KeyMap[ImGuiKey_Z] = KeyCode::Z; - - ImGui_Impl_Init( - Renderer::Instance() - ); - } - - void ImGuiView::NewFrame() - { - ImGui_Impl_NewFrame(); - - ImGuiIO& io = ImGui::GetIO(); - KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); - - // Setup display size (every frame to accommodate for window resizing) - Size display_size = Renderer::Instance().GetOutputSize(); - io.DisplaySize = ImVec2(display_size.x, display_size.y); - - ImGui::NewFrame(); - } - - void ImGuiView::Render() - { - ImGui::Render(); - - ImGui_Impl_RenderDrawData(ImGui::GetDrawData()); - } - - ImGuiLayerPtr ImGuiView::CreateLayer(Scene* scene) - { - auto iter = layers_.find(scene); - if (iter == layers_.end()) - { - ImGuiLayerPtr layer = new (std::nothrow) ImGuiLayer; - if (layer) - { - layers_.insert(std::make_pair(scene, layer.Get())); - } - return layer; - } - else - { - return iter->second; - } - } - - void ImGuiView::RemoveLayer(ImGuiLayer* layer) - { - using value_type = Map::value_type; - - auto iter = std::find_if(layers_.begin(), layers_.end(), [=](value_type const& value) - { - return value.second == layer; - }); - if (iter != layers_.end()) - { - layers_.erase(iter); - } - } - } -} \ No newline at end of file diff --git a/kiwano-imgui/src/imgui_impl.hpp b/kiwano-imgui/src/imgui_impl.h similarity index 100% rename from kiwano-imgui/src/imgui_impl.hpp rename to kiwano-imgui/src/imgui_impl.h diff --git a/kiwano/2d/Scene.cpp b/kiwano/2d/Scene.cpp index c01e16cf..1cfe6b47 100644 --- a/kiwano/2d/Scene.cpp +++ b/kiwano/2d/Scene.cpp @@ -25,8 +25,6 @@ namespace kiwano { Scene::Scene() - : mouse_cursor_(MouseCursor::Arrow) - , last_mouse_cursor(MouseCursor(-1)) { scene_ = this; @@ -48,33 +46,4 @@ namespace kiwano KGE_LOG(L"Scene exited"); } - void Scene::Update(Duration dt) - { - Node::Update(dt); - - if (last_mouse_cursor != mouse_cursor_) - { - last_mouse_cursor = mouse_cursor_; - - LPTSTR win32_cursor = IDC_ARROW; - switch (mouse_cursor_) - { - case MouseCursor::Arrow: win32_cursor = IDC_ARROW; break; - case MouseCursor::TextInput: win32_cursor = IDC_IBEAM; break; - case MouseCursor::SizeAll: win32_cursor = IDC_SIZEALL; break; - case MouseCursor::SizeWE: win32_cursor = IDC_SIZEWE; break; - case MouseCursor::SizeNS: win32_cursor = IDC_SIZENS; break; - case MouseCursor::SizeNESW: win32_cursor = IDC_SIZENESW; break; - case MouseCursor::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; - case MouseCursor::Hand: win32_cursor = IDC_HAND; break; - } - ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); - } - } - - void Scene::SetMouseCursor(MouseCursor cursor) - { - mouse_cursor_ = cursor; - } - } diff --git a/kiwano/2d/Scene.h b/kiwano/2d/Scene.h index f3f2997d..3dbddae5 100644 --- a/kiwano/2d/Scene.h +++ b/kiwano/2d/Scene.h @@ -37,16 +37,5 @@ namespace kiwano // 退出场景 virtual void OnExit(); - - public: - void Update(Duration dt); - - void SetMouseCursor( - MouseCursor cursor - ); - - protected: - MouseCursor mouse_cursor_; - MouseCursor last_mouse_cursor; }; } diff --git a/kiwano/2d/include-forwards.h b/kiwano/2d/include-forwards.h index 9fdb85b0..fe502288 100644 --- a/kiwano/2d/include-forwards.h +++ b/kiwano/2d/include-forwards.h @@ -30,6 +30,7 @@ #include "../base/SmartPtr.hpp" #include "../base/Object.h" #include "../math/helper.h" +#include "../base/types.h" namespace kiwano { @@ -80,52 +81,3 @@ namespace kiwano KGE_DECLARE_SMART_PTR(Button); KGE_DECLARE_SMART_PTR(Menu); } - -namespace kiwano -{ - // 画笔样式 - enum class StrokeStyle : int - { - Miter = 0, /* 斜切 */ - Bevel = 1, /* 斜角 */ - Round = 2 /* 圆角 */ - }; - - // 方向 - enum class Direction : int - { - Up, /* 上 */ - Down, /* 下 */ - Left, /* 左 */ - Right /* 右 */ - }; - - // 鼠标指针 - enum class MouseCursor : int - { - Arrow, /* 指针 */ - TextInput, /* 输入文本 */ - Hand, /* 手指 */ - SizeAll, - SizeNESW, - SizeNS, - SizeNWSE, - SizeWE, - }; - - // 文字抗锯齿属性 - enum class TextAntialias - { - Default, // 系统默认 - ClearType, // ClearType 抗锯齿 - GrayScale, // 灰度抗锯齿 - None // 不启用抗锯齿 - }; - - // 图层属性 - struct LayerProperties - { - Rect area; - float opacity; - }; -} diff --git a/kiwano/Kiwano.vcxproj b/kiwano/Kiwano.vcxproj index e516a13e..15c1e667 100644 --- a/kiwano/Kiwano.vcxproj +++ b/kiwano/Kiwano.vcxproj @@ -1,6 +1,7 @@ + diff --git a/kiwano/Kiwano.vcxproj.filters b/kiwano/Kiwano.vcxproj.filters index b5373957..925203e2 100644 --- a/kiwano/Kiwano.vcxproj.filters +++ b/kiwano/Kiwano.vcxproj.filters @@ -258,6 +258,9 @@ renderer + + base + diff --git a/kiwano/base/Component.h b/kiwano/base/Component.h index b76efe7c..7759351f 100644 --- a/kiwano/base/Component.h +++ b/kiwano/base/Component.h @@ -30,12 +30,10 @@ namespace kiwano virtual void SetupComponent(Application*) = 0; virtual void DestroyComponent() = 0; - virtual void BeforeUpdate() {} - virtual void OnUpdate(float dt) {} + virtual void BeforeUpdate(float dt) {} virtual void AfterUpdate() {} virtual void BeforeRender() {} - virtual void OnRender() {} virtual void AfterRender() {} virtual void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {} diff --git a/kiwano/base/Input.cpp b/kiwano/base/Input.cpp index d9caf178..ba52a7f5 100644 --- a/kiwano/base/Input.cpp +++ b/kiwano/base/Input.cpp @@ -38,17 +38,6 @@ namespace kiwano { } - void Input::Update() - { - if (want_update_) - { - want_update_ = false; - - ZeroMemory(keys_pressed_, sizeof(keys_pressed_)); - ZeroMemory(keys_released_, sizeof(keys_released_)); - } - } - void Input::UpdateKey(int key, bool down) { if (down && !keys_[key]) @@ -67,6 +56,17 @@ namespace kiwano mouse_pos_y_ = y; } + void Input::AfterUpdate() + { + if (want_update_) + { + want_update_ = false; + + ZeroMemory(keys_pressed_, sizeof(keys_pressed_)); + ZeroMemory(keys_released_, sizeof(keys_released_)); + } + } + void Input::HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) diff --git a/kiwano/base/Input.h b/kiwano/base/Input.h index 23b42ef7..c9d37658 100644 --- a/kiwano/base/Input.h +++ b/kiwano/base/Input.h @@ -63,14 +63,14 @@ namespace kiwano void DestroyComponent() override {} - void Update(); + void AfterUpdate() override; + + void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override; void UpdateKey(int, bool); void UpdateMousePos(float, float); - void HandleMessage(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) override; - protected: Input(); diff --git a/kiwano/base/types.h b/kiwano/base/types.h new file mode 100644 index 00000000..28e139e0 --- /dev/null +++ b/kiwano/base/types.h @@ -0,0 +1,71 @@ +// Copyright (c) 2016-2019 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "../math/Rect.hpp" + +namespace kiwano +{ + // 画笔样式 + enum class StrokeStyle : int + { + Miter = 0, /* 斜切 */ + Bevel = 1, /* 斜角 */ + Round = 2 /* 圆角 */ + }; + + // 方向 + enum class Direction : int + { + Up, /* 上 */ + Down, /* 下 */ + Left, /* 左 */ + Right /* 右 */ + }; + + // 鼠标指针 + enum class MouseCursor : int + { + Arrow, /* 指针 */ + TextInput, /* 输入文本 */ + Hand, /* 手指 */ + SizeAll, + SizeNESW, + SizeNS, + SizeNWSE, + SizeWE, + }; + + // 文字抗锯齿属性 + enum class TextAntialias + { + Default, // 系统默认 + ClearType, // ClearType 抗锯齿 + GrayScale, // 灰度抗锯齿 + None // 不启用抗锯齿 + }; + + // 图层属性 + struct LayerProperties + { + Rect area; + float opacity; + }; +} \ No newline at end of file diff --git a/kiwano/base/window.cpp b/kiwano/base/window.cpp index c02811ed..98ef3f6b 100644 --- a/kiwano/base/window.cpp +++ b/kiwano/base/window.cpp @@ -44,6 +44,7 @@ namespace kiwano , height_(0) , device_name_(nullptr) , is_fullscreen_(false) + , mouse_cursor_(MouseCursor(-1)) { } @@ -163,6 +164,8 @@ namespace kiwano GetClientRect(handle_, &rc); width_ = rc.right - rc.left; height_ = rc.bottom - rc.top; + + SetMouseCursor(MouseCursor::Arrow); return S_OK; } @@ -290,6 +293,28 @@ namespace kiwano } } + void Window::SetMouseCursor(MouseCursor cursor) + { + if (mouse_cursor_ != cursor) + { + mouse_cursor_ = cursor; + + LPTSTR win32_cursor = IDC_ARROW; + switch (cursor) + { + case MouseCursor::Arrow: win32_cursor = IDC_ARROW; break; + case MouseCursor::TextInput: win32_cursor = IDC_IBEAM; break; + case MouseCursor::SizeAll: win32_cursor = IDC_SIZEALL; break; + case MouseCursor::SizeWE: win32_cursor = IDC_SIZEWE; break; + case MouseCursor::SizeNS: win32_cursor = IDC_SIZENS; break; + case MouseCursor::SizeNESW: win32_cursor = IDC_SIZENESW; break; + case MouseCursor::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case MouseCursor::Hand: win32_cursor = IDC_HAND; break; + } + ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); + } + } + HWND Window::GetHandle() const { return handle_; diff --git a/kiwano/base/window.h b/kiwano/base/window.h index 185d47ea..58dbdc32 100644 --- a/kiwano/base/window.h +++ b/kiwano/base/window.h @@ -22,11 +22,16 @@ #include "../macros.h" #include "../common/helper.h" #include "../math/helper.h" +#include "../common/Singleton.hpp" +#include "types.h" namespace kiwano { class KGE_API Window + : public Singleton { + KGE_DECLARE_SINGLETON(Window); + public: // 获取标题 String GetTitle() const; @@ -52,6 +57,9 @@ namespace kiwano // 设置全屏模式 void SetFullscreen(bool fullscreen, int width, int height); + // 设置鼠标指针 + void SetMouseCursor(MouseCursor cursor); + public: HRESULT Create( String const& title, @@ -72,7 +80,7 @@ namespace kiwano void SetActive(bool actived); - public: + protected: Window(); ~Window(); @@ -83,5 +91,6 @@ namespace kiwano int width_; int height_; WCHAR* device_name_; + MouseCursor mouse_cursor_; }; } diff --git a/kiwano/platform/Application.cpp b/kiwano/platform/Application.cpp index 78e2c4bb..43297563 100644 --- a/kiwano/platform/Application.cpp +++ b/kiwano/platform/Application.cpp @@ -56,7 +56,7 @@ namespace kiwano ::CoInitialize(nullptr) ); - main_window_ = new Window; + main_window_ = &Window::Instance(); Use(&Renderer::Instance()); Use(&Input::Instance()); @@ -146,12 +146,6 @@ namespace kiwano { (*iter)->DestroyComponent(); } - - if (main_window_) - { - delete main_window_; - main_window_ = nullptr; - } } } @@ -247,7 +241,7 @@ namespace kiwano // Before update for (Component* c : components_) { - c->BeforeUpdate(); + c->BeforeUpdate(dt.Seconds()); } // Updating diff --git a/kiwano/ui/Button.cpp b/kiwano/ui/Button.cpp index 29923e48..7497bd30 100644 --- a/kiwano/ui/Button.cpp +++ b/kiwano/ui/Button.cpp @@ -20,6 +20,7 @@ #include "Button.h" #include "../2d/Scene.h" +#include "../base/window.h" namespace kiwano { @@ -111,7 +112,7 @@ namespace kiwano if (evt.type == Event::MouseHover) { SetStatus(Status::Hover); - GetScene()->SetMouseCursor(MouseCursor::Hand); + Window::Instance().SetMouseCursor(MouseCursor::Hand); if (mouse_over_callback_) mouse_over_callback_(); @@ -119,7 +120,7 @@ namespace kiwano else if (evt.type == Event::MouseOut) { SetStatus(Status::Normal); - GetScene()->SetMouseCursor(MouseCursor::Arrow); + Window::Instance().SetMouseCursor(MouseCursor::Arrow); if (mouse_out_callback_) mouse_out_callback_(); diff --git a/samples/ImGuiSample/MainScene.h b/samples/ImGuiSample/MainScene.h index 44bb494e..e9a2d0cd 100644 --- a/samples/ImGuiSample/MainScene.h +++ b/samples/ImGuiSample/MainScene.h @@ -20,7 +20,7 @@ public: MainScene() { // 创建 ImGui 图层 - ImGuiLayerPtr layer = ImGuiView::Instance().CreateLayer(this); + ImGuiLayerPtr layer = new ImGuiLayer; AddChild(layer); // 添加 ImGui 提供的 Demo 窗口 diff --git a/samples/ImGuiSample/main.cpp b/samples/ImGuiSample/main.cpp index 47e7c0d9..b821cc61 100644 --- a/samples/ImGuiSample/main.cpp +++ b/samples/ImGuiSample/main.cpp @@ -11,11 +11,10 @@ public: ImGuiApp() { // 添加 ImGui 组件 - Use(&ImGuiView::Instance()); + Use(&ImGuiModule::Instance()); // 初始化 Options options(L"ImGui Demo", 1280, 800); - Init(options); }