make Window singleton & make ImGuiLayer more easily to use

This commit is contained in:
Nomango 2019-07-30 14:58:24 +08:00
parent df3b5e459e
commit 762a764917
24 changed files with 475 additions and 414 deletions

View File

@ -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"

View File

@ -3,8 +3,8 @@
<ItemGroup>
<ClInclude Include="kiwano-imgui.h" />
<ClInclude Include="src\ImGuiLayer.h" />
<ClInclude Include="src\ImGuiView.h" />
<ClInclude Include="src\imgui_impl.hpp" />
<ClInclude Include="src\ImGuiModule.h" />
<ClInclude Include="src\imgui_impl.h" />
<ClInclude Include="src\imgui_impl_dx10.h" />
<ClInclude Include="src\imgui_impl_dx11.h" />
<ClInclude Include="third-party\ImGui\imconfig.h" />
@ -16,7 +16,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\ImGuiLayer.cpp" />
<ClCompile Include="src\ImGuiView.cpp" />
<ClCompile Include="src\ImGuiModule.cpp" />
<ClCompile Include="src\imgui_impl_dx10.cpp" />
<ClCompile Include="src\imgui_impl_dx11.cpp" />
<ClCompile Include="third-party\ImGui\imgui.cpp" />

View File

@ -12,9 +12,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\imgui_impl.hpp">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="src\imgui_impl_dx10.h">
<Filter>src</Filter>
</ClInclude>
@ -24,9 +21,6 @@
<ClInclude Include="src\ImGuiLayer.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="src\ImGuiView.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="third-party\ImGui\imconfig.h">
<Filter>third-party\ImGui</Filter>
</ClInclude>
@ -46,6 +40,12 @@
<Filter>third-party\ImGui</Filter>
</ClInclude>
<ClInclude Include="kiwano-imgui.h" />
<ClInclude Include="src\imgui_impl.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="src\ImGuiModule.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\imgui_impl_dx10.cpp">
@ -57,9 +57,6 @@
<ClCompile Include="src\ImGuiLayer.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\ImGuiView.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="third-party\ImGui\imgui.cpp">
<Filter>third-party\ImGui</Filter>
</ClCompile>
@ -72,5 +69,8 @@
<ClCompile Include="third-party\ImGui\imgui_widgets.cpp">
<Filter>third-party\ImGui</Filter>
</ClCompile>
<ClCompile Include="src\ImGuiModule.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -24,146 +24,21 @@ namespace kiwano
{
namespace imgui
{
namespace
{
Map<int, int> 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)

View File

@ -28,14 +28,12 @@ namespace kiwano
using ImGuiPipeline = Closure<void()>;
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<String, ImGuiPipeline> pipelines_;
};
}

View File

@ -0,0 +1,305 @@
// Copyright (C) 2019 Nomango
#include "../kiwano-imgui.h"
#include "imgui_impl.h"
#include <XInput.h>
#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
}
}
}
}

View File

@ -24,21 +24,11 @@ namespace kiwano
{
namespace imgui
{
class ImGuiLayer;
class ImGuiView
: public Singleton<ImGuiView>
class ImGuiModule
: public Singleton<ImGuiModule>
, 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<Scene*, ImGuiLayer*> layers_;
bool has_gamepad_;
bool want_update_has_gamepad_;
HWND target_window_;
};
}
}

View File

@ -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<Scene*, Layer*>::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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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;
};
}

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="base\types.h" />
<ClInclude Include="kiwano.h" />
<ClInclude Include="config.h" />
<ClInclude Include="macros.h" />

View File

@ -258,6 +258,9 @@
<ClInclude Include="renderer\D3DDeviceResourcesBase.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="base\types.h">
<Filter>base</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ui\Button.cpp">

View File

@ -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) {}

View File

@ -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)

View File

@ -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();

71
kiwano/base/types.h Normal file
View File

@ -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;
};
}

View File

@ -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_;

View File

@ -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<Window>
{
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_;
};
}

View File

@ -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

View File

@ -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_();

View File

@ -20,7 +20,7 @@ public:
MainScene()
{
// 创建 ImGui 图层
ImGuiLayerPtr layer = ImGuiView::Instance().CreateLayer(this);
ImGuiLayerPtr layer = new ImGuiLayer;
AddChild(layer);
// 添加 ImGui 提供的 Demo 窗口

View File

@ -11,11 +11,10 @@ public:
ImGuiApp()
{
// 添加 ImGui 组件
Use(&ImGuiView::Instance());
Use(&ImGuiModule::Instance());
// 初始化
Options options(L"ImGui Demo", 1280, 800);
Init(options);
}