Update Window & ImGuiModule

This commit is contained in:
Nomango 2020-01-16 18:33:42 +08:00
parent 88d61df5c0
commit 831c6c83e9
47 changed files with 699 additions and 804 deletions

View File

@ -13,6 +13,7 @@
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
<ClInclude Include="..\..\src\kiwano\core\common.h" />
<ClInclude Include="..\..\src\kiwano\core\Director.h" />
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
<ClInclude Include="..\..\src\kiwano\core\event\EventType.h" />
<ClInclude Include="..\..\src\kiwano\core\event\KeyEvent.h" />
@ -55,7 +56,6 @@
<ClInclude Include="..\..\src\kiwano\math\scalar.h" />
<ClInclude Include="..\..\src\kiwano\math\Vec2.hpp" />
<ClInclude Include="..\..\src\kiwano\platform\Application.h" />
<ClInclude Include="..\..\src\kiwano\platform\Director.h" />
<ClInclude Include="..\..\src\kiwano\platform\FileSystem.h" />
<ClInclude Include="..\..\src\kiwano\platform\Input.h" />
<ClInclude Include="..\..\src\kiwano\platform\win32\ComPtr.hpp" />
@ -111,6 +111,7 @@
<ClCompile Include="..\..\src\kiwano\2d\Transition.cpp" />
<ClCompile Include="..\..\src\kiwano\core\AsyncTask.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Component.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Director.cpp" />
<ClCompile Include="..\..\src\kiwano\core\EventDispatcher.cpp" />
<ClCompile Include="..\..\src\kiwano\core\EventListener.cpp" />
<ClCompile Include="..\..\src\kiwano\core\event\Event.cpp" />
@ -126,7 +127,6 @@
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
<ClCompile Include="..\..\src\kiwano\core\time.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Application.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\FileSystem.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />

View File

@ -231,9 +231,6 @@
<ClInclude Include="..\..\src\kiwano\platform\Window.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\platform\Director.h">
<Filter>platform</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h">
<Filter>2d</Filter>
</ClInclude>
@ -282,6 +279,9 @@
<ClInclude Include="..\..\src\kiwano\renderer\RenderContext.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\core\Director.h">
<Filter>core</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -440,9 +440,6 @@
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp">
<Filter>platform</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\Director.cpp">
<Filter>platform</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\TextActor.cpp">
<Filter>2d</Filter>
</ClCompile>
@ -479,5 +476,8 @@
<ClCompile Include="..\..\src\kiwano\renderer\RenderContext.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\core\Director.cpp">
<Filter>core</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -35,14 +35,18 @@ namespace kiwano
void ImGuiLayer::OnRender(RenderContext& ctx)
{
PrepareToRender(ctx);
for (const auto& pipeline : pipelines_)
{
pipeline.second();
}
}
void ImGuiLayer::AddItem(ImGuiPipeline const& item, String const& name)
bool ImGuiLayer::CheckVisibility(RenderContext& ctx) const
{
return true;
}
void ImGuiLayer::AddItem(String const& name, ImGuiPipeline const& item)
{
pipelines_.insert(std::make_pair(name, item));
}

View File

@ -45,9 +45,9 @@ namespace kiwano
/// \~chinese
/// @brief Ìí¼Ó ImGui ÔªËØ
/// @param item ¹ÜµÀ
/// @param name ÔªËØÃû³Æ
void AddItem(ImGuiPipeline const& item, String const& name);
/// @param item ¹ÜµÀ
void AddItem(String const& name, ImGuiPipeline const& item);
/// \~chinese
/// @brief ÒÆ³ý ImGui ÔªËØ
@ -62,6 +62,8 @@ namespace kiwano
public:
void OnRender(RenderContext& ctx) override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
Map<String, ImGuiPipeline> pipelines_;
};

View File

@ -1,32 +1,20 @@
// Copyright (C) 2019 Nomango
#include <kiwano/core/common.h>
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/MouseEvent.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/Input.h>
#include <kiwano/renderer/Renderer.h>
#include <kiwano-imgui/ImGuiModule.h>
#include <kiwano-imgui/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)
: target_window_(nullptr)
{
}
@ -36,55 +24,17 @@ namespace kiwano
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(Window::instance().GetHandle());
target_window_ = Renderer::instance().GetTargetWindow();
}
void ImGuiModule::DestroyComponent()
{
ImGui_Impl_Shutdown();
ImGui::DestroyContext();
}
void ImGuiModule::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();
// 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;
io.ImeWindowHandle = target_window_;
// 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;
@ -104,7 +54,34 @@ namespace kiwano
io.KeyMap[ImGuiKey_Y] = KeyCode::Y;
io.KeyMap[ImGuiKey_Z] = KeyCode::Z;
ImGui_Impl_Init(&Renderer::instance());
ImGui_Impl_Init(Renderer::instance());
}
void ImGuiModule::DestroyComponent()
{
ImGui_Impl_Shutdown();
ImGui::DestroyContext();
}
void ImGuiModule::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 = Input::instance().IsDown(KeyCode::Super);
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the HandleEvent function below.
// Update OS mouse position
UpdateMousePos();
// Update OS mouse cursor with the cursor requested by imgui
UpdateMouseCursor();
}
void ImGuiModule::BeforeRender()
@ -117,89 +94,56 @@ namespace kiwano
Render();
}
void ImGuiModule::HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
void ImGuiModule::HandleEvent(Event* evt)
{
if (ImGui::GetCurrentContext() == NULL)
return;
ImGuiIO& io = ImGui::GetIO();
switch (msg)
if (evt->IsType<MouseEvent>())
{
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((uint32_t)wparam);
break;
}
case WM_SETCURSOR:
{
if (LOWORD(lparam) == HTCLIENT)
if (evt->IsType<MouseDownEvent>())
{
UpdateMouseCursor();
int button = dynamic_cast<MouseDownEvent*>(evt)->button;
int index = 0;
if (button == MouseButton::Left) index = 0;
else if (button == MouseButton::Right) index = 1;
else if (button == MouseButton::Middle) index = 2;
io.MouseDown[index] = true;
}
else if (evt->IsType<MouseUpEvent>())
{
int button = dynamic_cast<MouseUpEvent*>(evt)->button;
int index = 0;
if (button == MouseButton::Left) index = 0;
else if (button == MouseButton::Right) index = 1;
else if (button == MouseButton::Middle) index = 2;
io.MouseDown[index] = false;
}
else if (evt->IsType<MouseWheelEvent>())
{
float wheel = dynamic_cast<MouseWheelEvent*>(evt)->wheel;
io.MouseWheel += wheel;
}
break;
}
case WM_DEVICECHANGE:
else if (evt->IsType<KeyEvent>())
{
if ((uint32_t)wparam == DBT_DEVNODES_CHANGED)
want_update_has_gamepad_ = true;
break;
}
if (evt->IsType<KeyDownEvent>())
{
int key = dynamic_cast<KeyDownEvent*>(evt)->code;
io.KeysDown[key] = true;
}
else if (evt->IsType<KeyUpEvent>())
{
int key = dynamic_cast<KeyUpEvent*>(evt)->code;
io.KeysDown[key] = false;
}
else if (evt->IsType<KeyCharEvent>())
{
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
char ch = dynamic_cast<KeyCharEvent*>(evt)->value;
io.AddInputCharacter(static_cast<ImWchar>(ch));
}
}
}
@ -260,50 +204,6 @@ namespace kiwano
Window::instance().SetCursor(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

@ -49,13 +49,11 @@ namespace kiwano
void AfterRender() override;
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
void HandleEvent(Event* evt) override;
void OnUpdate(Duration dt) override;
private:
void Init(HWND hwnd);
void NewFrame();
void Render();
@ -64,12 +62,8 @@ namespace kiwano
void UpdateMouseCursor();
void UpdateGamepads();
private:
bool has_gamepad_;
bool want_update_has_gamepad_;
HWND target_window_;
WindowHandle target_window_;
};
}
}

View File

@ -8,7 +8,7 @@
#include <kiwano-imgui/imgui_impl_dx11.h>
inline bool ImGui_Impl_Init(::kiwano::Renderer* renderer) { return ImGui_ImplDX11_Init(renderer->GetD3DDeviceResources()->GetDevice(), renderer->GetD3DDeviceResources()->GetDeviceContext()); }
inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer) { return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(), renderer.GetD3DDeviceResources()->GetDeviceContext()); }
inline void ImGui_Impl_Shutdown() { ImGui_ImplDX11_Shutdown(); }
inline void ImGui_Impl_NewFrame() { ImGui_ImplDX11_NewFrame(); }
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) { ImGui_ImplDX11_RenderDrawData(draw_data); }
@ -20,7 +20,7 @@ inline bool ImGui_Impl_CreateDeviceObjects() { return ImGui_ImplDX11_Cre
#include <kiwano-imgui/imgui_impl_dx10.h>
inline bool ImGui_Impl_Init(::kiwano::Renderer* renderer) { return ImGui_ImplDX10_Init(renderer->GetD3DDeviceResources()->GetDevice()); }
inline bool ImGui_Impl_Init(::kiwano::Renderer& renderer) { return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice()); }
inline void ImGui_Impl_Shutdown() { ImGui_ImplDX10_Shutdown(); }
inline void ImGui_Impl_NewFrame() { ImGui_ImplDX10_NewFrame(); }
inline void ImGui_Impl_RenderDrawData(ImDrawData* draw_data) { ImGui_ImplDX10_RenderDrawData(draw_data); }

View File

@ -26,6 +26,9 @@ namespace kiwano
{
namespace physics
{
KGE_DECLARE_SMART_PTR(ContactBeginEvent);
KGE_DECLARE_SMART_PTR(ContactEndEvent);
/**
* \addtogroup Events
* @{

View File

@ -67,14 +67,14 @@ namespace kiwano
void BeginContact(b2Contact* contact) override
{
ContactBeginEvent evt(contact);
world_->DispatchEvent(evt);
ContactBeginEventPtr evt = new ContactBeginEvent(contact);
world_->DispatchEvent(evt.get());
}
void EndContact(b2Contact* contact) override
{
ContactEndEvent evt(contact);
world_->DispatchEvent(evt);
ContactEndEventPtr evt = new ContactEndEvent(contact);
world_->DispatchEvent(evt.get());
}
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override { KGE_NOT_USED(contact); KGE_NOT_USED(oldManifold); }

View File

@ -97,7 +97,7 @@ namespace kiwano
if (children_.empty())
{
if (CheckVisibilty(ctx))
if (CheckVisibility(ctx))
{
PrepareToRender(ctx);
OnRender(ctx);
@ -116,7 +116,7 @@ namespace kiwano
child = child->next_item().get();
}
if (CheckVisibilty(ctx))
if (CheckVisibility(ctx))
{
PrepareToRender(ctx);
OnRender(ctx);
@ -157,7 +157,7 @@ namespace kiwano
}
}
bool Actor::CheckVisibilty(RenderContext& ctx) const
bool Actor::CheckVisibility(RenderContext& ctx) const
{
if (dirty_visibility_)
{
@ -175,7 +175,7 @@ namespace kiwano
return visible_in_rt_;
}
bool Actor::DispatchEvent(Event& evt)
bool Actor::DispatchEvent(Event* evt)
{
if (!visible_)
return true;
@ -208,54 +208,48 @@ namespace kiwano
return true;
}
void Actor::HandleEvent(Event& evt)
void Actor::HandleEvent(Event* evt)
{
if (responsible_)
{
if (evt.IsType<MouseMoveEvent>())
if (evt->IsType<MouseMoveEvent>())
{
auto& mouse_evt = evt.SafeCast<MouseMoveEvent>();
bool contains = ContainsPoint(mouse_evt.pos);
auto mouse_evt = dynamic_cast<MouseMoveEvent*>(evt);
bool contains = ContainsPoint(mouse_evt->pos);
if (!hover_ && contains)
{
hover_ = true;
MouseHoverEvent hover;
hover.pos = mouse_evt.pos;
hover.left_btn_down = mouse_evt.left_btn_down;
hover.right_btn_down = mouse_evt.right_btn_down;
EventDispatcher::DispatchEvent(hover);
MouseHoverEventPtr hover = new MouseHoverEvent;
hover->pos = mouse_evt->pos;
EventDispatcher::DispatchEvent(hover.get());
}
else if (hover_ && !contains)
{
hover_ = false;
pressed_ = false;
MouseOutEvent out;
out.pos = mouse_evt.pos;
out.left_btn_down = mouse_evt.left_btn_down;
out.right_btn_down = mouse_evt.right_btn_down;
EventDispatcher::DispatchEvent(out);
MouseOutEventPtr out = new MouseOutEvent;
out->pos = mouse_evt->pos;
EventDispatcher::DispatchEvent(out.get());
}
}
if (evt.IsType<MouseDownEvent>() && hover_)
if (evt->IsType<MouseDownEvent>() && hover_)
{
pressed_ = true;
}
if (evt.IsType<MouseUpEvent>() && pressed_)
if (evt->IsType<MouseUpEvent>() && pressed_)
{
pressed_ = false;
auto& mouse_up_evt = evt.SafeCast<MouseUpEvent>();
auto mouse_up_evt = dynamic_cast<MouseUpEvent*>(evt);
MouseClickEvent click;
click.pos = mouse_up_evt.pos;
click.left_btn_down = mouse_up_evt.left_btn_down;
click.right_btn_down = mouse_up_evt.right_btn_down;
click.button = mouse_up_evt.button;
EventDispatcher::DispatchEvent(click);
MouseClickEventPtr click = new MouseClickEvent;
click->pos = mouse_up_evt->pos;
click->button = mouse_up_evt->button;
EventDispatcher::DispatchEvent(click.get());
}
}
}

View File

@ -395,7 +395,7 @@ namespace kiwano
/// @brief 分发事件
/// @param evt 事件
/// @return 是否继续分发该事件
virtual bool DispatchEvent(Event& evt);
virtual bool DispatchEvent(Event* evt);
/// \~chinese
/// @brief 设置默认锚点
@ -416,10 +416,10 @@ namespace kiwano
/// \~chinese
/// @brief 检查是否在渲染上下文的视区内
virtual bool CheckVisibilty(RenderContext& ctx) const;
virtual bool CheckVisibility(RenderContext& ctx) const;
/// \~chinese
/// @brief 渲染前初始化渲染上下文状态,仅当 CheckVisibilty 返回真时调用该函数
/// @brief 渲染前初始化渲染上下文状态,仅当 CheckVisibility 返回真时调用该函数
virtual void PrepareToRender(RenderContext& ctx);
/// \~chinese
@ -440,7 +440,7 @@ namespace kiwano
/// \~chinese
/// @brief 处理事件
void HandleEvent(Event& evt);
void HandleEvent(Event* evt);
private:
bool visible_;

View File

@ -130,28 +130,28 @@ namespace kiwano
return status_;
}
void Button::UpdateStatus(Event& evt)
void Button::UpdateStatus(Event* evt)
{
if (!enabled_)
return;
if (evt.IsType<MouseHoverEvent>())
if (evt->IsType<MouseHoverEvent>())
{
SetStatus(Status::Hover);
}
else if (evt.IsType<MouseOutEvent>())
else if (evt->IsType<MouseOutEvent>())
{
SetStatus(Status::Normal);
}
else if (evt.IsType<MouseDownEvent>() && status_ == Status::Hover)
else if (evt->IsType<MouseDownEvent>() && status_ == Status::Hover)
{
SetStatus(Status::Pressed);
}
else if (evt.IsType<MouseUpEvent>() && status_ == Status::Pressed)
else if (evt->IsType<MouseUpEvent>() && status_ == Status::Pressed)
{
SetStatus(Status::Hover);
}
else if (evt.IsType<MouseClickEvent>())
else if (evt->IsType<MouseClickEvent>())
{
if (click_callback_)
click_callback_(this);

View File

@ -105,7 +105,7 @@ namespace kiwano
protected:
/// \~chinese
/// @brief 更新按钮状态
void UpdateStatus(Event& evt);
void UpdateStatus(Event* evt);
private:
bool enabled_;

View File

@ -67,8 +67,8 @@ namespace kiwano
style.fill_brush = fill_brush;
debug_text_.SetStyle(style);
AddListener<MouseHoverEvent>([=](Event&) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](Event&) { SetOpacity(1.f); });
AddListener<MouseHoverEvent>([=](Event*) { SetOpacity(0.4f); });
AddListener<MouseOutEvent>([=](Event*) { SetOpacity(1.f); });
}
DebugActor::~DebugActor()
@ -139,7 +139,7 @@ namespace kiwano
}
}
bool DebugActor::CheckVisibilty(RenderContext& ctx) const
bool DebugActor::CheckVisibility(RenderContext& ctx) const
{
return true;
}

View File

@ -46,7 +46,7 @@ namespace kiwano
void OnUpdate(Duration dt) override;
protected:
bool CheckVisibilty(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
std::locale comma_locale_;

View File

@ -72,7 +72,7 @@ namespace kiwano
void GifSprite::OnRender(RenderContext& ctx)
{
if (frame_to_render_ && CheckVisibilty(ctx))
if (frame_to_render_ && CheckVisibility(ctx))
{
PrepareToRender(ctx);

View File

@ -54,7 +54,7 @@ namespace kiwano
area_.SetMaskTransform(transform);
}
bool Layer::DispatchEvent(Event& evt)
bool Layer::DispatchEvent(Event* evt)
{
if (!IsVisible())
return true;
@ -75,7 +75,7 @@ namespace kiwano
ctx.PopLayer();
}
bool Layer::CheckVisibilty(RenderContext& ctx) const
bool Layer::CheckVisibility(RenderContext& ctx) const
{
// Do not need to render Layer
return false;

View File

@ -82,12 +82,12 @@ namespace kiwano
/// @brief 获取图层区域
LayerArea const& GetArea() const;
bool DispatchEvent(Event& evt) override;
bool DispatchEvent(Event* evt) override;
protected:
void Render(RenderContext& ctx) override;
bool CheckVisibilty(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
bool swallow_;

View File

@ -99,9 +99,9 @@ namespace kiwano
ctx.FillGeometry(geo_);
}
bool ShapeActor::CheckVisibilty(RenderContext& ctx) const
bool ShapeActor::CheckVisibility(RenderContext& ctx) const
{
return geo_.IsValid() && Actor::CheckVisibilty(ctx);
return geo_.IsValid() && Actor::CheckVisibility(ctx);
}
//-------------------------------------------------------

View File

@ -122,7 +122,7 @@ namespace kiwano
void OnRender(RenderContext& ctx) override;
protected:
bool CheckVisibilty(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
BrushPtr fill_brush_;

View File

@ -79,8 +79,8 @@ namespace kiwano
ctx.DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
}
bool Sprite::CheckVisibilty(RenderContext& ctx) const
bool Sprite::CheckVisibility(RenderContext& ctx) const
{
return frame_ && frame_->IsValid() && Actor::CheckVisibilty(ctx);
return frame_ && frame_->IsValid() && Actor::CheckVisibility(ctx);
}
}

View File

@ -70,7 +70,7 @@ namespace kiwano
void OnRender(RenderContext& ctx) override;
protected:
bool CheckVisibilty(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
FramePtr frame_;

View File

@ -106,9 +106,9 @@ namespace kiwano
}
}
bool TextActor::CheckVisibilty(RenderContext& ctx) const
bool TextActor::CheckVisibility(RenderContext& ctx) const
{
return text_layout_.IsValid() && Actor::CheckVisibilty(ctx);
return text_layout_.IsValid() && Actor::CheckVisibility(ctx);
}
void TextActor::SetFillColor(Color const& color)

View File

@ -175,7 +175,7 @@ namespace kiwano
void OnUpdate(Duration dt) override;
protected:
bool CheckVisibilty(RenderContext& ctx) const override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
bool show_underline_;

View File

@ -119,11 +119,7 @@ namespace kiwano
/// \~chinese
/// @brief 事件处理
/// @param evt 事件
virtual void HandleEvent(Event& evt) {}
/// \~chinese
/// @brief 处理 Windows 消息
virtual void HandleMessage(HWND, UINT32, WPARAM, LPARAM) {}
virtual void HandleEvent(Event* evt) {}
public:
static const int flag;

View File

@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/platform/Director.h>
#include <kiwano/core/Director.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/Stage.h>
#include <kiwano/2d/Transition.h>
@ -179,7 +179,7 @@ namespace kiwano
}
}
void Director::HandleEvent(Event& evt)
void Director::HandleEvent(Event* evt)
{
if (current_stage_)
current_stage_->DispatchEvent(evt);

View File

@ -108,7 +108,7 @@ namespace kiwano
void OnRender(RenderContext& ctx) override;
void HandleEvent(Event& evt) override;
void HandleEvent(Event* evt) override;
private:
Director();

View File

@ -23,7 +23,7 @@
namespace kiwano
{
bool EventDispatcher::DispatchEvent(Event& evt)
bool EventDispatcher::DispatchEvent(Event* evt)
{
if (listeners_.empty())
return true;

View File

@ -132,7 +132,7 @@ namespace kiwano
/// @brief 分发事件
/// @param evt 事件
/// @return 是否继续分发该事件
bool DispatchEvent(Event& evt);
bool DispatchEvent(Event* evt);
private:
Listeners listeners_;

View File

@ -47,7 +47,7 @@ namespace kiwano
public:
/// \~chinese
/// @brief 监听器回调函数
using Callback = Function<void(Event&)>;
using Callback = Function<void(Event*)>;
/// \~chinese
/// @brief 构造空监听器
@ -154,7 +154,7 @@ namespace kiwano
/// \~chinese
/// @brief 接收消息
void Receive(Event& evt);
void Receive(Event* evt);
private:
bool running_;
@ -220,9 +220,11 @@ namespace kiwano
type_ = type;
}
inline void EventListener::Receive(Event& evt)
inline void EventListener::Receive(Event* evt)
{
if (type_ == evt.GetType() && callback_)
KGE_ASSERT(evt != nullptr);
if (type_ == evt->GetType() && callback_)
{
callback_(evt);
}

View File

@ -19,12 +19,15 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/event/EventType.h>
#include <kiwano/math/math.h>
#include <kiwano/core/SmartPtr.hpp>
#include <kiwano/core/keys.h>
#include <kiwano/core/event/EventType.h>
namespace kiwano
{
KGE_DECLARE_SMART_PTR(Event);
/**
* \~chinese
* \defgroup Events
@ -38,6 +41,7 @@ namespace kiwano
/// \~chinese
/// @brief 事件
class KGE_API Event
: public RefCounter
{
public:
/// \~chinese
@ -66,7 +70,7 @@ namespace kiwano
typename _Ty,
typename = typename std::enable_if<std::is_base_of<Event, _Ty>::value, int>::type
>
const _Ty& SafeCast() const;
const _Ty* SafeCast() const;
/// \~chinese
/// @brief 安全转换为其他类型事件
@ -75,7 +79,7 @@ namespace kiwano
typename _Ty,
typename = typename std::enable_if<std::is_base_of<Event, _Ty>::value, int>::type
>
_Ty& SafeCast();
_Ty* SafeCast();
private:
const EventType type_;
@ -93,9 +97,9 @@ namespace kiwano
template <typename _Ty, typename = typename std::enable_if<IsEvent<_Ty>::value, int>::type>
struct IsEventType
{
inline bool operator()(const Event& evt) const
inline bool operator()(const Event* evt) const
{
return evt.GetType() == KGE_EVENT(_Ty);
return evt->GetType() == KGE_EVENT(_Ty);
}
};
@ -109,21 +113,21 @@ namespace kiwano
template <typename _Ty, typename>
inline bool Event::IsType() const
{
return kiwano::IsEventType<_Ty>()(*this);
return kiwano::IsEventType<_Ty>()(this);
}
template <typename _Ty, typename>
inline const _Ty& Event::SafeCast() const
inline const _Ty* Event::SafeCast() const
{
return const_cast<Event*>(this)->SafeCast<_Ty>();
}
template <typename _Ty, typename>
inline _Ty* Event::SafeCast()
{
if (!IsType<_Ty>())
throw std::bad_cast();
return dynamic_cast<const _Ty&>(*this);
}
template <typename _Ty, typename>
inline _Ty& Event::SafeCast()
{
return const_cast<_Ty&>(const_cast<const Event*>(this)->SafeCast<_Ty>());
return dynamic_cast<_Ty*>(this);
}
}

View File

@ -2,20 +2,26 @@
namespace kiwano
{
KeyEvent::KeyEvent(const EventType& type)
: Event(type)
{
}
KeyDownEvent::KeyDownEvent()
: Event(KGE_EVENT(KeyDownEvent))
: KeyEvent(KGE_EVENT(KeyDownEvent))
, code(0)
{
}
KeyUpEvent::KeyUpEvent()
: Event(KGE_EVENT(KeyUpEvent))
: KeyEvent(KGE_EVENT(KeyUpEvent))
, code(0)
{
}
KeyCharEvent::KeyCharEvent()
: Event(KGE_EVENT(KeyCharEvent))
: KeyEvent(KGE_EVENT(KeyCharEvent))
, value()
{
}

View File

@ -24,6 +24,11 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(KeyEvent);
KGE_DECLARE_SMART_PTR(KeyDownEvent);
KGE_DECLARE_SMART_PTR(KeyUpEvent);
KGE_DECLARE_SMART_PTR(KeyCharEvent);
/**
* \addtogroup Events
* @{
@ -34,12 +39,14 @@ namespace kiwano
class KGE_API KeyEvent
: public Event
{
public:
KeyEvent(const EventType& type);
};
/// \~chinese
/// @brief 键盘按下事件
class KGE_API KeyDownEvent
: public Event
: public KeyEvent
{
public:
KeyCode::Value code; ///< 键值
@ -50,7 +57,7 @@ namespace kiwano
/// \~chinese
/// @brief 键盘抬起事件
class KGE_API KeyUpEvent
: public Event
: public KeyEvent
{
public:
KeyCode::Value code; ///< 键值
@ -61,7 +68,7 @@ namespace kiwano
/// \~chinese
/// @brief 键盘字符事件
class KGE_API KeyCharEvent
: public Event
: public KeyEvent
{
public:
char value; ///< 字符
@ -74,11 +81,11 @@ namespace kiwano
template <>
struct IsEventType<KeyEvent>
{
inline bool operator()(const Event& evt) const
inline bool operator()(const Event* evt) const
{
return evt.GetType() == KGE_EVENT(KeyDownEvent)
|| evt.GetType() == KGE_EVENT(KeyUpEvent)
|| evt.GetType() == KGE_EVENT(KeyCharEvent);
return evt->GetType() == KGE_EVENT(KeyDownEvent)
|| evt->GetType() == KGE_EVENT(KeyUpEvent)
|| evt->GetType() == KGE_EVENT(KeyCharEvent);
}
};

View File

@ -5,8 +5,6 @@ namespace kiwano
MouseEvent::MouseEvent(EventType const& type)
: Event(type)
, pos()
, left_btn_down(false)
, right_btn_down(false)
{
}

View File

@ -25,6 +25,15 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(MouseEvent);
KGE_DECLARE_SMART_PTR(MouseMoveEvent);
KGE_DECLARE_SMART_PTR(MouseDownEvent);
KGE_DECLARE_SMART_PTR(MouseUpEvent);
KGE_DECLARE_SMART_PTR(MouseClickEvent);
KGE_DECLARE_SMART_PTR(MouseHoverEvent);
KGE_DECLARE_SMART_PTR(MouseOutEvent);
KGE_DECLARE_SMART_PTR(MouseWheelEvent);
/**
* \addtogroup Events
* @{
@ -37,8 +46,6 @@ namespace kiwano
{
public:
Point pos; ///< 報炎了崔
bool left_btn_down; ///< 鼠标左键是否按下
bool right_btn_down; ///< 鼠标右键是否按下
MouseEvent(EventType const& type);
};
@ -119,15 +126,15 @@ namespace kiwano
template <>
struct IsEventType<MouseEvent>
{
inline bool operator()(const Event& evt) const
inline bool operator()(const Event* evt) const
{
return evt.GetType() == KGE_EVENT(MouseMoveEvent)
|| evt.GetType() == KGE_EVENT(MouseDownEvent)
|| evt.GetType() == KGE_EVENT(MouseUpEvent)
|| evt.GetType() == KGE_EVENT(MouseClickEvent)
|| evt.GetType() == KGE_EVENT(MouseHoverEvent)
|| evt.GetType() == KGE_EVENT(MouseOutEvent)
|| evt.GetType() == KGE_EVENT(MouseWheelEvent);
return evt->GetType() == KGE_EVENT(MouseMoveEvent)
|| evt->GetType() == KGE_EVENT(MouseDownEvent)
|| evt->GetType() == KGE_EVENT(MouseUpEvent)
|| evt->GetType() == KGE_EVENT(MouseClickEvent)
|| evt->GetType() == KGE_EVENT(MouseHoverEvent)
|| evt->GetType() == KGE_EVENT(MouseOutEvent)
|| evt->GetType() == KGE_EVENT(MouseWheelEvent);
}
};

View File

@ -2,34 +2,40 @@
namespace kiwano
{
WindowEvent::WindowEvent(const EventType& type)
: Event(type)
{
}
WindowMovedEvent::WindowMovedEvent()
: Event(KGE_EVENT(WindowMovedEvent))
: WindowEvent(KGE_EVENT(WindowMovedEvent))
, x(0)
, y(0)
{
}
WindowResizedEvent::WindowResizedEvent()
: Event(KGE_EVENT(WindowResizedEvent))
: WindowEvent(KGE_EVENT(WindowResizedEvent))
, width(0)
, height(0)
{
}
WindowFocusChangedEvent::WindowFocusChangedEvent()
: Event(KGE_EVENT(WindowFocusChangedEvent))
: WindowEvent(KGE_EVENT(WindowFocusChangedEvent))
, focus(false)
{
}
WindowTitleChangedEvent::WindowTitleChangedEvent()
: Event(KGE_EVENT(WindowTitleChangedEvent))
: WindowEvent(KGE_EVENT(WindowTitleChangedEvent))
, title()
{
}
WindowClosedEvent::WindowClosedEvent()
: Event(KGE_EVENT(WindowClosedEvent))
: WindowEvent(KGE_EVENT(WindowClosedEvent))
{
}

View File

@ -23,6 +23,13 @@
namespace kiwano
{
KGE_DECLARE_SMART_PTR(WindowEvent);
KGE_DECLARE_SMART_PTR(WindowMovedEvent);
KGE_DECLARE_SMART_PTR(WindowResizedEvent);
KGE_DECLARE_SMART_PTR(WindowFocusChangedEvent);
KGE_DECLARE_SMART_PTR(WindowTitleChangedEvent);
KGE_DECLARE_SMART_PTR(WindowClosedEvent);
/**
* \addtogroup Events
* @{
@ -33,12 +40,14 @@ namespace kiwano
class KGE_API WindowEvent
: public Event
{
public:
WindowEvent(const EventType& type);
};
/// \~chinese
/// @brief 窗口移动事件
class KGE_API WindowMovedEvent
: public Event
: public WindowEvent
{
public:
int x; ///< 窗口左上角 x 坐标
@ -50,11 +59,11 @@ namespace kiwano
/// \~chinese
/// @brief 窗口大小变化事件
class KGE_API WindowResizedEvent
: public Event
: public WindowEvent
{
public:
int width; ///< 窗口宽度
int height; ///< 窗口高度
uint32_t width; ///< ´°¿Ú¿í¶È
uint32_t height; ///< ´°¿Ú¸ß¶È
WindowResizedEvent();
};
@ -62,7 +71,7 @@ namespace kiwano
/// \~chinese
/// @brief 窗口焦点变化事件
class KGE_API WindowFocusChangedEvent
: public Event
: public WindowEvent
{
public:
bool focus; ///< 是否获取到焦点
@ -73,7 +82,7 @@ namespace kiwano
/// \~chinese
/// @brief 窗口标题更改事件
class KGE_API WindowTitleChangedEvent
: public Event
: public WindowEvent
{
public:
String title; ///< 标题
@ -84,7 +93,7 @@ namespace kiwano
/// \~chinese
/// @brief 窗口关闭事件
class KGE_API WindowClosedEvent
: public Event
: public WindowEvent
{
public:
WindowClosedEvent();
@ -95,13 +104,13 @@ namespace kiwano
template <>
struct IsEventType<WindowEvent>
{
inline bool operator()(const Event& evt) const
inline bool operator()(const Event* evt) const
{
return evt.GetType() == KGE_EVENT(WindowMovedEvent)
|| evt.GetType() == KGE_EVENT(WindowResizedEvent)
|| evt.GetType() == KGE_EVENT(WindowFocusChangedEvent)
|| evt.GetType() == KGE_EVENT(WindowTitleChangedEvent)
|| evt.GetType() == KGE_EVENT(WindowClosedEvent);
return evt->GetType() == KGE_EVENT(WindowMovedEvent)
|| evt->GetType() == KGE_EVENT(WindowResizedEvent)
|| evt->GetType() == KGE_EVENT(WindowFocusChangedEvent)
|| evt->GetType() == KGE_EVENT(WindowTitleChangedEvent)
|| evt->GetType() == KGE_EVENT(WindowClosedEvent);
}
};

View File

@ -60,6 +60,7 @@ namespace kiwano
Tab = VK_TAB, ///< TAB¼ü
Delete = VK_DELETE, ///< ɾ³ý¼ü
Back = VK_BACK, ///< Í˸ñ¼ü
Super = VK_LWIN, ///< Cmd/Super/Windows¼ü
A = 0x41, ///< A¼ü
B, ///< B¼ü

View File

@ -59,6 +59,7 @@
#include <kiwano/core/TimerManager.h>
#include <kiwano/core/AsyncTask.h>
#include <kiwano/core/Resource.h>
#include <kiwano/core/Director.h>
//
@ -112,7 +113,6 @@
#include <kiwano/platform/FileSystem.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/Director.h>
#include <kiwano/platform/Application.h>

View File

@ -19,19 +19,13 @@
// THE SOFTWARE.
#include <mutex>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Application.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Director.h>
#include <kiwano/core/Director.h>
#include <kiwano/core/Logger.h>
#include <kiwano/renderer/TextureCache.h>
#include <kiwano/utils/ResourceCache.h>
#include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib")
namespace kiwano
{
namespace
@ -62,12 +56,8 @@ namespace kiwano
namespace kiwano
{
Application::Application()
: end_(true)
, inited_(false)
, time_scale_(1.f)
: time_scale_(1.f)
{
::CoInitialize(nullptr);
Use(&Renderer::instance());
Use(&Input::instance());
Use(&Director::instance());
@ -76,13 +66,11 @@ namespace kiwano
Application::~Application()
{
Destroy();
::CoUninitialize();
}
void Application::Init(const Config& config)
void Application::Run(const Config& config)
{
Window::instance().Init(config.window, Application::WndProc);
Window::instance().Init(config.window);
Renderer::instance().Init(config.render);
// Setup all components
@ -100,33 +88,24 @@ namespace kiwano
// Everything is ready
OnReady();
HWND hwnd = Window::instance().GetHandle();
last_update_time_ = Time::Now();
// disable imm
::ImmAssociateContext(hwnd, nullptr);
// use Application instance in message loop
::SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(this));
inited_ = true;
}
void Application::Run()
{
KGE_ASSERT(inited_ && "Calling Application::Run before Application::Init");
end_ = false;
Window::instance().Prepare();
while (!end_)
Window& window = Window::instance();
while (!window.ShouldClose())
{
Window::instance().PollEvents();
while (EventPtr evt = window.PollEvent())
{
DispatchEvent(evt.get());
}
Update();
Render();
}
}
void Application::Quit()
{
end_ = true;
Window::instance().Destroy();
}
void Application::Destroy()
@ -136,18 +115,11 @@ namespace kiwano
ResourceCache::instance().Clear();
TextureCache::instance().Clear();
if (inited_)
for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter)
{
inited_ = false;
for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter)
{
(*iter)->DestroyComponent();
}
comps_.clear();
(*iter)->DestroyComponent();
}
Window::instance().Destroy();
comps_.clear();
}
void Application::Use(ComponentBase* component)
@ -210,11 +182,10 @@ namespace kiwano
// Updating
{
static auto last = Time::Now();
const Time now = Time::Now();
const Duration dt = (now - last_update_time_) * time_scale_;
const auto now = Time::Now();
const auto dt = (now - last) * time_scale_;
last = now;
last_update_time_ = now;
for (auto c : update_comps_)
{
@ -251,7 +222,7 @@ namespace kiwano
}
}
void Application::DispatchEvent(Event& evt)
void Application::DispatchEvent(Event* evt)
{
for (auto c : event_comps_)
{
@ -264,215 +235,4 @@ namespace kiwano
std::lock_guard<std::mutex> lock(perform_mutex_);
functions_to_perform_.push(func);
}
LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
{
Application* app = reinterpret_cast<Application*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (app == nullptr)
{
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
// Handle Message
for (auto c : app->event_comps_)
{
c->HandleMessage(hwnd, msg, wparam, lparam);
}
switch (msg)
{
case WM_PAINT:
{
app->Update();
app->Render();
::InvalidateRect(hwnd, NULL, FALSE);
return 0;
}
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
{
bool down = msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN;
if (down)
{
KeyDownEvent evt;
evt.code = static_cast<int>(wparam);
app->DispatchEvent(evt);
}
else
{
KeyUpEvent evt;
evt.code = static_cast<int>(wparam);
app->DispatchEvent(evt);
}
}
break;
case WM_CHAR:
{
KeyCharEvent evt;
evt.value = static_cast<char>(wparam);
app->DispatchEvent(evt);
}
break;
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
//case WM_LBUTTONDBLCLK:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
//case WM_MBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
//case WM_RBUTTONDBLCLK:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
auto UpdateMouseData = [&](MouseEvent& evt)
{
evt.pos = Point(static_cast<float>(GET_X_LPARAM(lparam)), static_cast<float>(GET_Y_LPARAM(lparam)));
evt.left_btn_down = !!(wparam & MK_LBUTTON);
evt.left_btn_down = !!(wparam & MK_RBUTTON);
};
if (msg == WM_MOUSEMOVE)
{
MouseMoveEvent evt;
UpdateMouseData(evt);
app->DispatchEvent(evt);
}
else if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN)
{
MouseDownEvent evt;
UpdateMouseData(evt);
if (msg == WM_LBUTTONDOWN) { evt.button = MouseButton::Left; }
else if (msg == WM_RBUTTONDOWN) { evt.button = MouseButton::Right; }
else if (msg == WM_MBUTTONDOWN) { evt.button = MouseButton::Middle; }
app->DispatchEvent(evt);
}
else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP)
{
MouseUpEvent evt;
UpdateMouseData(evt);
if (msg == WM_LBUTTONUP) { evt.button = MouseButton::Left; }
else if (msg == WM_RBUTTONUP) { evt.button = MouseButton::Right; }
else if (msg == WM_MBUTTONUP) { evt.button = MouseButton::Middle; }
app->DispatchEvent(evt);
}
else if (msg == WM_MOUSEWHEEL)
{
MouseWheelEvent evt;
UpdateMouseData(evt);
evt.wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
app->DispatchEvent(evt);
}
}
break;
case WM_SIZE:
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
KGE_SYS_LOG(L"Window minimized");
}
else
{
// KGE_SYS_LOG(L"Window resized");
Window::instance().UpdateWindowRect();
WindowResizedEvent evt;
evt.width = LOWORD(lparam);
evt.height = HIWORD(lparam);
app->DispatchEvent(evt);
}
}
break;
case WM_MOVE:
{
int x = (int)(short)LOWORD(lparam);
int y = (int)(short)HIWORD(lparam);
WindowMovedEvent evt;
evt.x = x;
evt.y = y;
app->DispatchEvent(evt);
}
break;
case WM_ACTIVATE:
{
bool active = (LOWORD(wparam) != WA_INACTIVE);
Window::instance().SetActive(active);
WindowFocusChangedEvent evt;
evt.focus = active;
app->DispatchEvent(evt);
}
break;
case WM_SETTEXT:
{
KGE_SYS_LOG(L"Window title changed");
WindowTitleChangedEvent evt;
evt.title = reinterpret_cast<const wchar_t*>(lparam);
app->DispatchEvent(evt);
}
break;
case WM_SETICON:
{
KGE_SYS_LOG(L"Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
KGE_SYS_LOG(L"The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE);
}
break;
case WM_SETCURSOR:
{
Window::instance().UpdateCursor();
}
break;
case WM_CLOSE:
{
KGE_SYS_LOG(L"Window is closing");
if (!app->OnClosing())
{
WindowClosedEvent evt;
app->DispatchEvent(evt);
return 0;
}
}
break;
case WM_DESTROY:
{
KGE_SYS_LOG(L"Window was destroyed");
app->Quit();
app->OnDestroy();
::PostQuitMessage(0);
return 0;
}
break;
}
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
}

View File

@ -80,15 +80,6 @@ namespace kiwano
virtual ~Application();
/**
* \~chinese
* @brief
* @details OnReady
* @param config
* @attention 使
*/
void Init(Config const& config = Config());
/**
* \~chinese
* @brief
@ -96,14 +87,6 @@ namespace kiwano
*/
virtual void OnReady() {}
/**
* \~chinese
* @brief
* @details
* @return true
*/
virtual bool OnClosing() { return true; }
/**
* \~chinese
* @brief
@ -114,9 +97,11 @@ namespace kiwano
/**
* \~chinese
* @brief
* @details OnReady
* @param config
* @note
*/
void Run();
void Run(Config const& config = Config());
/**
* \~chinese
@ -152,7 +137,7 @@ namespace kiwano
* @details
* @param evt
*/
void DispatchEvent(Event& evt);
void DispatchEvent(Event* evt);
/**
* \~chinese
@ -167,13 +152,9 @@ namespace kiwano
void Update();
static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
private:
bool end_;
bool inited_;
float time_scale_;
float time_scale_;
Time last_update_time_;
Vector<ComponentBase*> comps_;
Vector<RenderComponent*> render_comps_;
Vector<UpdateComponent*> update_comps_;

View File

@ -20,24 +20,73 @@
#include <kiwano/platform/Input.h>
#include <kiwano/core/Logger.h>
#include <windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/MouseEvent.h>
namespace kiwano
{
Input::Input()
: want_update_(false)
, mouse_pos_x_(0.f)
, mouse_pos_y_(0.f)
, keys_{}
, keys_pressed_{}
, keys_released_{}
{
ZeroMemory(keys_, sizeof(keys_));
ZeroMemory(keys_pressed_, sizeof(keys_pressed_));
ZeroMemory(keys_released_, sizeof(keys_released_));
}
Input::~Input()
{
}
void Input::AfterUpdate()
{
if (want_update_)
{
want_update_ = false;
keys_pressed_.fill(false);
keys_released_.fill(false);
}
}
bool Input::IsDown(int key_or_btn) const
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_[key_or_btn];
return false;
}
bool Input::WasPressed(int key_or_btn) const
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_pressed_[key_or_btn];
return false;
}
bool Input::WasReleased(int key_or_btn) const
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_released_[key_or_btn];
return false;
}
float Input::GetMouseX() const
{
return mouse_pos_.x;
}
float Input::GetMouseY() const
{
return mouse_pos_.y;
}
Point Input::GetMousePos() const
{
return mouse_pos_;
}
void Input::UpdateKey(int key, bool down)
{
if (down && !keys_[key])
@ -50,94 +99,38 @@ namespace kiwano
want_update_ = true;
}
void Input::UpdateMousePos(float x, float y)
void Input::UpdateMousePos(const Point& pos)
{
mouse_pos_x_ = x;
mouse_pos_y_ = y;
mouse_pos_ = pos;
}
void Input::AfterUpdate()
void Input::HandleEvent(Event* evt)
{
if (want_update_)
if (evt->IsType<MouseEvent>())
{
want_update_ = false;
ZeroMemory(keys_pressed_, sizeof(keys_pressed_));
ZeroMemory(keys_released_, sizeof(keys_released_));
if (evt->IsType<MouseMoveEvent>())
{
UpdateMousePos(dynamic_cast<MouseMoveEvent*>(evt)->pos);
}
else if (evt->IsType<MouseDownEvent>())
{
UpdateKey(dynamic_cast<MouseDownEvent*>(evt)->button, true);
}
else if (evt->IsType<MouseUpEvent>())
{
UpdateKey(dynamic_cast<MouseUpEvent*>(evt)->button, false);
}
}
}
void Input::HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
else if (evt->IsType<KeyEvent>())
{
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
//case WM_LBUTTONDBLCLK:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
//case WM_MBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
//case WM_RBUTTONDBLCLK:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { UpdateKey(VK_LBUTTON, (msg == WM_LBUTTONDOWN) ? true : false); }
else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP) { UpdateKey(VK_RBUTTON, (msg == WM_RBUTTONDOWN) ? true : false); }
else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP) { UpdateKey(VK_MBUTTON, (msg == WM_MBUTTONDOWN) ? true : false); }
else if (msg == WM_MOUSEMOVE) { UpdateMousePos(static_cast<float>(GET_X_LPARAM(lparam)), static_cast<float>(GET_Y_LPARAM(lparam))); }
break;
if (evt->IsType<KeyDownEvent>())
{
UpdateKey(dynamic_cast<KeyDownEvent*>(evt)->code, true);
}
else if (evt->IsType<KeyUpEvent>())
{
UpdateKey(dynamic_cast<KeyUpEvent*>(evt)->code, false);
}
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
{
bool down = msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN;
UpdateKey((int)wparam, down);
}
}
}
bool Input::IsDown(int key_or_btn)
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_[key_or_btn];
return false;
}
bool Input::WasPressed(int key_or_btn)
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_pressed_[key_or_btn];
return false;
}
bool Input::WasReleased(int key_or_btn)
{
KGE_ASSERT(key_or_btn >= 0 && key_or_btn < KEY_NUM);
if (key_or_btn >= 0 && key_or_btn < KEY_NUM)
return keys_released_[key_or_btn];
return false;
}
float Input::GetMouseX()
{
return mouse_pos_x_;
}
float Input::GetMouseY()
{
return mouse_pos_y_;
}
Point Input::GetMousePos()
{
return Point{ mouse_pos_x_, mouse_pos_y_ };
}
}

View File

@ -20,9 +20,9 @@
#pragma once
#include <kiwano/macros.h>
#include <kiwano/core/common.h>
#include <kiwano/math/math.h>
#include <kiwano/core/keys.h>
#include <kiwano/core/common.h>
#include <kiwano/core/event/Event.h>
#include <kiwano/core/Component.h>
namespace kiwano
@ -46,7 +46,7 @@ namespace kiwano
* @return
* @see kiwano::KeyCode kiwano::MouseButton
*/
bool IsDown(int key_or_btn);
bool IsDown(int key_or_btn) const;
/**
* \~chinese
@ -55,7 +55,7 @@ namespace kiwano
* @return
* @see kiwano::KeyCode kiwano::MouseButton
*/
bool WasPressed(int key_or_btn);
bool WasPressed(int key_or_btn) const;
/**
* \~chinese
@ -64,28 +64,28 @@ namespace kiwano
* @return
* @see kiwano::KeyCode kiwano::MouseButton
*/
bool WasReleased(int key_or_btn);
bool WasReleased(int key_or_btn) const;
/**
* \~chinese
* @brief x
* @return x
*/
float GetMouseX();
float GetMouseX() const;
/**
* \~chinese
* @brief y
* @return y
*/
float GetMouseY();
float GetMouseY() const;
/**
* \~chinese
* @brief
* @return
*/
Point GetMousePos();
Point GetMousePos() const;
public:
void SetupComponent() override {}
@ -94,25 +94,24 @@ namespace kiwano
void AfterUpdate() override;
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
void UpdateKey(int, bool);
void UpdateMousePos(float, float);
void HandleEvent(Event* evt) override;
private:
Input();
~Input();
void UpdateKey(int, bool);
void UpdateMousePos(const Point& pos);
private:
static const int KEY_NUM = 256;
bool want_update_;
bool keys_[KEY_NUM];
bool keys_pressed_[KEY_NUM];
bool keys_released_[KEY_NUM];
float mouse_pos_x_;
float mouse_pos_y_;
Point mouse_pos_;
std::array<bool, KEY_NUM> keys_;
std::array<bool, KEY_NUM> keys_pressed_;
std::array<bool, KEY_NUM> keys_released_;
};
}

View File

@ -19,8 +19,14 @@
// THE SOFTWARE.
#include <kiwano/platform/Window.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Application.h>
#include <kiwano/core/event/MouseEvent.h>
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/core/Logger.h>
#include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib")
#define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
#define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX
@ -65,19 +71,19 @@ namespace kiwano
{
}
void Window::Init(WindowConfig const& config, WNDPROC proc)
void Window::Init(WindowConfig const& config)
{
HINSTANCE hinst = GetModuleHandleW(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = KGE_WND_CLASS_NAME;
wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */;
wcex.lpfnWndProc = proc;
wcex.lpfnWndProc = Window::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinst;
wcex.hbrBackground = nullptr;
wcex.hbrBackground = (HBRUSH)(::GetStockObject(BLACK_BRUSH));
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW);
@ -155,18 +161,18 @@ namespace kiwano
{
::UnregisterClass(KGE_WND_CLASS_NAME, hinst);
win32::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
return;
}
else
{
RECT rc;
GetClientRect(handle_, &rc);
width_ = rc.right - rc.left;
height_ = rc.bottom - rc.top;
}
}
void Window::Prepare()
{
width_ = width;
height_ = height;
// disable imm
::ImmAssociateContext(handle_, nullptr);
// use Application instance in message loop
::SetWindowLongPtr(handle_, GWLP_USERDATA, LONG_PTR(this));
::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_);
@ -176,15 +182,22 @@ namespace kiwano
}
}
void Window::PollEvents()
EventPtr Window::PollEvent()
{
static MSG msg = {};
if (::GetMessageW(&msg, nullptr, 0, 0))
MSG msg;
while (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
EventPtr evt;
if (!event_queue_.empty())
{
evt = event_queue_.front();
event_queue_.pop();
}
return evt;
}
String Window::GetTitle() const
@ -293,7 +306,12 @@ namespace kiwano
::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle());
::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, win_width, win_height, SWP_DRAWFRAME | SWP_FRAMECHANGED);
UpdateWindowRect();
// Update window rect
RECT rc;
::GetClientRect(handle_, &rc);
width_ = static_cast<uint32_t>(rc.right - rc.left);
height_ = static_cast<uint32_t>(rc.bottom - rc.top);
}
::ShowWindow(handle_, SW_SHOWNORMAL);
@ -305,28 +323,46 @@ namespace kiwano
mouse_cursor_ = cursor;
}
HWND Window::GetHandle() const
WindowHandle Window::GetHandle() const
{
return handle_;
}
bool Window::ShouldClose()
{
return handle_ == nullptr;
}
void Window::PushEvent(EventPtr evt)
{
event_queue_.push(evt);
}
void Window::Destroy()
{
if (is_fullscreen_)
RestoreResolution(device_name_);
if (device_name_)
{
delete[] device_name_;
device_name_ = nullptr;
}
if (handle_)
{
::DestroyWindow(handle_);
handle_ = nullptr;
}
}
#if defined(KGE_WIN32)
DWORD Window::GetWindowStyle() const
{
return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE));
}
void Window::UpdateWindowRect()
{
if (!handle_)
return;
RECT rc;
::GetClientRect(handle_, &rc);
width_ = rc.right - rc.left;
height_ = rc.bottom - rc.top;
}
void Window::UpdateCursor()
{
LPTSTR win32_cursor = IDC_ARROW;
@ -368,22 +404,185 @@ namespace kiwano
}
}
void Window::Destroy()
LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
{
if (is_fullscreen_)
RestoreResolution(device_name_);
if (device_name_)
Window* window = reinterpret_cast<Window*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (window == nullptr)
{
delete[] device_name_;
device_name_ = nullptr;
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
if (handle_)
switch (msg)
{
::DestroyWindow(handle_);
handle_ = nullptr;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
KeyDownEventPtr evt = new KeyDownEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
KeyUpEventPtr evt = new KeyUpEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_CHAR:
{
KeyCharEventPtr evt = new KeyCharEvent;
evt->value = static_cast<char>(wparam);
window->PushEvent(evt);
}
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
{
MouseDownEventPtr evt = new MouseDownEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
MouseUpEventPtr evt = new MouseUpEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONUP) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONUP) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONUP) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_MOUSEMOVE:
{
MouseMoveEventPtr evt = new MouseMoveEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
window->PushEvent(evt);
}
break;
case WM_MOUSEWHEEL:
{
MouseWheelEventPtr evt = new MouseWheelEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
window->PushEvent(evt);
}
break;
case WM_SIZE:
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
KGE_SYS_LOG(L"Window minimized");
}
else
{
// KGE_SYS_LOG(L"Window resized");
window->width_ = ((uint32_t)(short)LOWORD(lparam));
window->height_ = ((uint32_t)(short)HIWORD(lparam));
WindowResizedEventPtr evt = new WindowResizedEvent;
evt->width = window->width_;
evt->height = window->height_;
window->PushEvent(evt);
}
}
break;
case WM_MOVE:
{
int x = ((int)(short)LOWORD(lparam));
int y = ((int)(short)HIWORD(lparam));
WindowMovedEventPtr evt = new WindowMovedEvent;
evt->x = x;
evt->y = y;
window->PushEvent(evt);
}
break;
case WM_ACTIVATE:
{
bool active = (LOWORD(wparam) != WA_INACTIVE);
window->SetActive(active);
WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent;
evt->focus = active;
window->PushEvent(evt);
}
break;
case WM_SETTEXT:
{
KGE_SYS_LOG(L"Window title changed");
WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent;
evt->title.assign(reinterpret_cast<const wchar_t*>(lparam));
window->PushEvent(evt);
}
break;
case WM_SETICON:
{
KGE_SYS_LOG(L"Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
KGE_SYS_LOG(L"The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE);
}
break;
case WM_SETCURSOR:
{
window->UpdateCursor();
}
break;
case WM_CLOSE:
{
KGE_SYS_LOG(L"Window is closing");
WindowClosedEventPtr evt = new WindowClosedEvent;
window->PushEvent(evt);
window->Destroy();
}
break;
case WM_DESTROY:
{
KGE_SYS_LOG(L"Window was destroyed");
::PostQuitMessage(0);
return 0;
}
break;
}
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
namespace
@ -441,4 +640,6 @@ namespace kiwano
}
}
#endif
}

View File

@ -20,8 +20,9 @@
#pragma once
#include <kiwano/macros.h>
#include <kiwano/core/common.h>
#include <kiwano/math/math.h>
#include <kiwano/core/common.h>
#include <kiwano/core/event/Event.h>
namespace kiwano
{
@ -74,6 +75,10 @@ namespace kiwano
);
};
#if defined(KGE_WIN32)
typedef HWND WindowHandle;
#endif
/**
* \~chinese
@ -85,6 +90,13 @@ namespace kiwano
friend Singleton<Window>;
public:
/**
* \~chinese
* @brief
* @param config
*/
void Init(WindowConfig const& config);
/**
* \~chinese
* @brief ťńČĄ´°żÚąęĚâ
@ -151,39 +163,56 @@ namespace kiwano
*/
void SetCursor(CursorType cursor);
#ifdef KGE_WIN32
public:
void Init(WindowConfig const& config, WNDPROC proc);
/**
* \~chinese
* @brief
* @return
*/
EventPtr PollEvent();
void Prepare();
/**
* \~chinese
* @brief
*/
WindowHandle GetHandle() const;
void PollEvents();
HWND GetHandle() const;
DWORD GetWindowStyle() const;
void UpdateWindowRect();
void UpdateCursor();
void SetActive(bool actived);
/**
* \~chinese
* @brief
*/
bool ShouldClose();
/**
* \~chinese
* @brief
*/
void Destroy();
#endif
private:
Window();
~Window();
void PushEvent(EventPtr evt);
#if defined(KGE_WIN32)
DWORD GetWindowStyle() const;
void UpdateCursor();
void SetActive(bool actived);
static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
#endif
private:
bool resizable_;
bool is_fullscreen_;
HWND handle_;
int width_;
int height_;
wchar_t* device_name_;
CursorType mouse_cursor_;
bool resizable_;
bool is_fullscreen_;
WindowHandle handle_;
uint32_t width_;
uint32_t height_;
wchar_t* device_name_;
CursorType mouse_cursor_;
std::queue<EventPtr> event_queue_;
};
}

View File

@ -20,8 +20,8 @@
#include <kiwano/renderer/Renderer.h>
#include <kiwano/renderer/GeometrySink.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/Window.h>
#include <kiwano/platform/FileSystem.h>
namespace kiwano
@ -33,7 +33,7 @@ namespace kiwano
}
Renderer::Renderer()
: hwnd_(nullptr)
: target_window_(nullptr)
, vsync_(true)
, clear_color_(Color::Black)
{
@ -53,19 +53,21 @@ namespace kiwano
{
KGE_SYS_LOG(L"Creating device resources");
hwnd_ = Window::instance().GetHandle();
win32::ThrowIfFailed(::CoInitialize(nullptr));
target_window_ = Window::instance().GetHandle();
output_size_ = Window::instance().GetSize();
d2d_res_ = nullptr;
d3d_res_ = nullptr;
drawing_state_block_ = nullptr;
HRESULT hr = hwnd_ ? S_OK : E_FAIL;
HRESULT hr = target_window_ ? S_OK : E_FAIL;
// Direct3D device resources
if (SUCCEEDED(hr))
{
hr = ID3DDeviceResources::Create(&d3d_res_, hwnd_);
hr = ID3DDeviceResources::Create(&d3d_res_, target_window_);
// Direct2D device resources
if (SUCCEEDED(hr))
@ -136,6 +138,8 @@ namespace kiwano
drawing_state_block_.reset();
d2d_res_.reset();
d3d_res_.reset();
::CoUninitialize();
}
void Renderer::BeforeRender()
@ -171,18 +175,12 @@ namespace kiwano
win32::ThrowIfFailed(hr);
}
void Renderer::HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
void Renderer::HandleEvent(Event* evt)
{
switch (msg)
if (evt->IsType<WindowResizedEvent>())
{
case WM_SIZE:
{
uint32_t width = LOWORD(lparam);
uint32_t height = HIWORD(lparam);
ResizeTarget(width, height);
break;
}
auto window_evt = dynamic_cast<WindowResizedEvent*>(evt);
ResizeTarget(window_evt->width, window_evt->height);
}
}

View File

@ -25,6 +25,7 @@
#include <kiwano/renderer/GifImage.h>
#include <kiwano/renderer/Font.h>
#include <kiwano/renderer/TextStyle.hpp>
#include <kiwano/platform/Window.h>
#if defined(KGE_USE_DIRECTX10)
# include "win32/D3D10DeviceResources.h"
@ -278,7 +279,7 @@ namespace kiwano
public:
/// \~chinese
/// @brief 获取目标窗口
HWND GetTargetWindow() const;
WindowHandle GetTargetWindow() const;
/// \~chinese
/// @brief 获取渲染输出大小
@ -303,7 +304,7 @@ namespace kiwano
void AfterRender() override;
void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override;
void HandleEvent(Event* evt) override;
private:
Renderer();
@ -315,10 +316,10 @@ namespace kiwano
void ResizeTarget(uint32_t width, uint32_t height);
private:
bool vsync_;
HWND hwnd_;
Color clear_color_;
Size output_size_;
bool vsync_;
WindowHandle target_window_;
Color clear_color_;
Size output_size_;
ComPtr<ID2DDeviceResources> d2d_res_;
ComPtr<ID3DDeviceResources> d3d_res_;
@ -330,7 +331,7 @@ namespace kiwano
/** @} */
inline HWND Renderer::GetTargetWindow() const { return hwnd_; }
inline WindowHandle Renderer::GetTargetWindow() const { return target_window_; }
inline Size const& Renderer::GetOutputSize() const { return output_size_; }