From 091a05e8fdf05afdfcc872bf5754d4657ae46653 Mon Sep 17 00:00:00 2001 From: Nomango Date: Wed, 3 Jun 2020 22:07:07 +0800 Subject: [PATCH 01/11] update frame ticker & fix window frozen when minimized --- src/kiwano/platform/Application.cpp | 47 +++++++++++------------- src/kiwano/platform/Application.h | 55 +++++++++++------------------ src/kiwano/platform/Runner.cpp | 31 +++++++++++----- src/kiwano/platform/Runner.h | 41 ++++++++++++++++----- 4 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 5a9edfc8..1a8ba46e 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -48,9 +48,10 @@ Application::~Application() void Application::Run(RunnerPtr runner) { KGE_ASSERT(runner); - runner_ = runner; - running_ = true; + running_ = true; is_paused_ = false; + runner_ = runner; + timer_ = Timer::Create(); // Initialize runner runner->InitSettings(); @@ -64,29 +65,17 @@ void Application::Run(RunnerPtr runner) // Everything is ready runner->OnReady(); + // Update everything + this->Update(0); + + // Start the loop while (running_) { - if (!frame_ticker_) - { - frame_ticker_ = Ticker::Create(0); - } + timer_->Tick(); - if (frame_ticker_->Tick()) - { - // Execute main loop - if (!runner->MainLoop(frame_ticker_->GetDeltaTime())) - running_ = false; - } - else - { - // Releases CPU - Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime(); - Duration sleep_dt = frame_ticker_->GetInterval() - total_dt; - if (sleep_dt.Milliseconds() > 1LL) - { - sleep_dt.Sleep(); - } - } + // Execute main loop + if (!runner->MainLoop(timer_->GetDeltaTime())) + running_ = false; } this->Destroy(); @@ -96,16 +85,16 @@ void Application::Pause() { is_paused_ = true; - if (frame_ticker_) - frame_ticker_->Pause(); + if (timer_) + timer_->Pause(); } void Application::Resume() { is_paused_ = false; - if (frame_ticker_) - frame_ticker_->Resume(); + if (timer_) + timer_->Resume(); } void Application::Quit() @@ -113,6 +102,12 @@ void Application::Quit() running_ = false; } +void Application::UpdateFrame(Duration dt) +{ + this->Render(); + this->Update(dt); +} + void Application::Destroy() { if (runner_) diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 1107cde5..670440c3 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include namespace kiwano { @@ -103,18 +103,6 @@ public: */ WindowPtr GetWindow() const; - /** - * \~chinese - * @brief 获取帧报时器 - */ - TickerPtr GetFrameTicker() const; - - /** - * \~chinese - * @brief 设置帧报时器 - */ - void SetFrameTicker(TickerPtr ticker); - /** * \~chinese * @brief 设置时间缩放因子 @@ -150,16 +138,10 @@ public: /** * \~chinese - * @brief 更新所有模块 + * @brief 更新一帧 * @param dt 时间间隔 */ - void Update(Duration dt); - - /** - * \~chinese - * @brief 创建渲染上下文并渲染画面 - */ - void Render(); + void UpdateFrame(Duration dt); /** * \~chinese @@ -167,12 +149,26 @@ public: */ void Destroy(); +private: + /** + * \~chinese + * @brief 更新所有模块 + * @param dt 时间间隔 + */ + void Update(Duration dt); + + /** + * \~chinese + * @brief 渲染画面 + */ + void Render(); + private: bool running_; bool is_paused_; float time_scale_; RunnerPtr runner_; - TickerPtr frame_ticker_; + TimerPtr timer_; List modules_; std::mutex perform_mutex_; Queue> functions_to_perform_; @@ -185,18 +181,9 @@ inline RunnerPtr Application::GetRunner() const inline WindowPtr Application::GetWindow() const { - KGE_ASSERT(runner_); - return runner_->GetWindow(); -} - -inline TickerPtr Application::GetFrameTicker() const -{ - return frame_ticker_; -} - -inline void Application::SetFrameTicker(TickerPtr ticker) -{ - frame_ticker_ = ticker; + if (runner_) + return runner_->GetWindow(); + return nullptr; } inline bool Application::IsPaused() const diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index a289b6a5..175a0c07 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -101,6 +101,9 @@ void Runner::InitSettings() Director::GetInstance().ShowDebugInfo(true); Renderer::GetInstance().GetContext().SetCollectingStatus(true); } + + // Create frame ticker + frame_ticker_ = Ticker::Create(settings_.frame_interval, -1); } bool Runner::MainLoop(Duration dt) @@ -118,9 +121,6 @@ bool Runner::MainLoop(Duration dt) Application& app = Application::GetInstance(); - // Update modules before poll events - app.Update(dt); - // Poll events main_window_->PumpEvents(); while (EventPtr evt = main_window_->PollEvent()) @@ -128,12 +128,27 @@ bool Runner::MainLoop(Duration dt) app.DispatchEvent(evt.Get()); } - app.Render(); - - if (app.IsPaused()) + // Update frame ticker + if (frame_ticker_) { - // Slow down when the application is paused - Duration(5).Sleep(); + if (frame_ticker_->Tick(dt)) + { + app.UpdateFrame(frame_ticker_->GetDeltaTime()); + } + else + { + // Releases CPU + Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime(); + Duration sleep_dt = frame_ticker_->GetInterval() - total_dt; + if (sleep_dt.Milliseconds() > 1LL) + { + sleep_dt.Sleep(); + } + } + } + else + { + app.UpdateFrame(dt); } return true; } diff --git a/src/kiwano/platform/Runner.h b/src/kiwano/platform/Runner.h index db1a6d38..20c0c4b7 100644 --- a/src/kiwano/platform/Runner.h +++ b/src/kiwano/platform/Runner.h @@ -24,6 +24,8 @@ #include #include #include +#include + namespace kiwano { @@ -38,14 +40,15 @@ KGE_DECLARE_SMART_PTR(Runner); */ struct Settings { - uint32_t width; ///< 窗口宽度 - uint32_t height; ///< 窗口高度 - String title; ///< 窗口标题 - uint32_t icon; ///< 窗口图标 - bool resizable; ///< 窗口大小可调整 - Color bg_color; ///< 窗口背景色 - bool vsync_enabled; ///< 垂直同步 - bool debug_mode; ///< 调试模式 + uint32_t width; ///< 窗口宽度 + uint32_t height; ///< 窗口高度 + String title; ///< 窗口标题 + uint32_t icon; ///< 窗口图标 + bool resizable; ///< 窗口大小可调整 + Color bg_color; ///< 窗口背景色 + Duration frame_interval; ///< 帧间隔 + bool vsync_enabled; ///< 垂直同步 + bool debug_mode; ///< 调试模式 Settings() : width(800) @@ -54,7 +57,8 @@ struct Settings , icon() , resizable(false) , bg_color(Color::Black) - , vsync_enabled(true) + , frame_interval(16) + , vsync_enabled(false) , debug_mode(false) { } @@ -118,6 +122,14 @@ public: /// @brief 获取设置 Settings GetSettings() const; + /// \~chinese + /// @brief 获取帧报时器 + TickerPtr GetFrameTicker() const; + + /// \~chinese + /// @brief 设置帧报时器 + void SetFrameTicker(TickerPtr ticker); + protected: /// \~chinese /// @brief 修改设置 @@ -131,6 +143,7 @@ private: private: Settings settings_; WindowPtr main_window_; + TickerPtr frame_ticker_; }; inline void Runner::OnReady() {} @@ -162,4 +175,14 @@ inline void Runner::SetSettings(Settings settings) settings_ = settings; } +inline TickerPtr Runner::GetFrameTicker() const +{ + return frame_ticker_; +} + +inline void Runner::SetFrameTicker(TickerPtr ticker) +{ + frame_ticker_ = ticker; +} + } // namespace kiwano From a7948944523b1f6bee7b7508ee67464f1c5f1cd1 Mon Sep 17 00:00:00 2001 From: Nomango Date: Thu, 4 Jun 2020 17:01:12 +0800 Subject: [PATCH 02/11] add ObjectPool --- projects/kiwano/kiwano.vcxproj | 2 + projects/kiwano/kiwano.vcxproj.filters | 6 ++ src/kiwano/base/ObjectBase.cpp | 6 ++ src/kiwano/base/ObjectBase.h | 4 ++ src/kiwano/base/ObjectPool.cpp | 86 ++++++++++++++++++++++++++ src/kiwano/base/ObjectPool.h | 72 +++++++++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 src/kiwano/base/ObjectPool.cpp create mode 100644 src/kiwano/base/ObjectPool.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index 8883793a..a0ca2a9c 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -17,6 +17,7 @@ + @@ -132,6 +133,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 9d5619f2..94ab0a18 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -351,6 +351,9 @@ utils + + base + @@ -575,6 +578,9 @@ utils + + base + diff --git a/src/kiwano/base/ObjectBase.cpp b/src/kiwano/base/ObjectBase.cpp index 588e0a6e..629b9ef5 100644 --- a/src/kiwano/base/ObjectBase.cpp +++ b/src/kiwano/base/ObjectBase.cpp @@ -19,6 +19,7 @@ // THE SOFTWARE. #include +#include #include #include #include @@ -56,6 +57,11 @@ ObjectBase::~ObjectBase() #endif } +void ObjectBase::AutoRelease() +{ + ObjectPool::GetInstance().AddObject(this); +} + const Any& ObjectBase::GetUserData() const { return user_data_; diff --git a/src/kiwano/base/ObjectBase.h b/src/kiwano/base/ObjectBase.h index 6761c77c..927e2549 100644 --- a/src/kiwano/base/ObjectBase.h +++ b/src/kiwano/base/ObjectBase.h @@ -44,6 +44,10 @@ public: virtual ~ObjectBase(); + /// \~chinese + /// @brief 自动释放 + void AutoRelease(); + /// \~chinese /// @brief 设置对象名 void SetName(const String& name); diff --git a/src/kiwano/base/ObjectPool.cpp b/src/kiwano/base/ObjectPool.cpp new file mode 100644 index 00000000..66ba259c --- /dev/null +++ b/src/kiwano/base/ObjectPool.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2016-2018 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. + +#include + +namespace kiwano +{ + +List ObjectPool::pools_; + +ObjectPool& ObjectPool::GetInstance() +{ + static ObjectPool instance; + return *pools_.back(); +} + +ObjectPool::ObjectPool() +{ + pools_.push_back(this); +} + +ObjectPool::~ObjectPool() +{ + Clear(); + + auto iter = std::find(pools_.begin(), pools_.end(), this); + if (iter != pools_.end()) + pools_.erase(iter); +} + +void ObjectPool::AddObject(ObjectBase* obj) +{ + if (obj) + { + if (!Contains(obj)) + { + obj->Retain(); + + std::lock_guard lock(mutex_); + objects_.push_back(obj); + } + } +} + +bool ObjectPool::Contains(ObjectBase* obj) const +{ + std::lock_guard lock(const_cast(mutex_)); + + for (auto iter = pools_.rbegin(); iter != pools_.rend(); iter++) + for (const auto o : (*iter)->objects_) + if (obj == o) + return true; + return false; +} + +void ObjectPool::Clear() +{ + Vector copied; + + { + std::lock_guard lock(mutex_); + copied = std::move(objects_); + } + + for (auto obj : copied) + obj->Release(); +} + +} // namespace kiwano diff --git a/src/kiwano/base/ObjectPool.h b/src/kiwano/base/ObjectPool.h new file mode 100644 index 00000000..72ac3d5b --- /dev/null +++ b/src/kiwano/base/ObjectPool.h @@ -0,0 +1,72 @@ +// Copyright (c) 2016-2018 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 +#include + +namespace kiwano +{ +/** + * \~chinese + * @brief 对象池 + */ +class KGE_API ObjectPool + : public Noncopyable +{ +public: + static ObjectPool& GetInstance(); + + ObjectPool(); + + virtual ~ObjectPool(); + + /** + * \~chinese + * @brief 添加对象到内存池 + * @param[in] obj 基础对象 + */ + void AddObject(ObjectBase* obj); + + /** + * \~chinese + * @brief 判断对象是否在对象池中 + * @param[in] obj 基础对象 + */ + bool Contains(ObjectBase* obj) const; + + /** + * \~chinese + * @brief 清空所有对象 + */ + void Clear(); + +private: + ObjectPool(const ObjectPool&) = delete; + + ObjectPool& operator=(const ObjectPool&) = delete; + +private: + std::mutex mutex_; + Vector objects_; + + static List pools_; +}; +} // namespace kiwano From f786ab67ef7ae394ffb419ebae4ab7f9a0e3de2f Mon Sep 17 00:00:00 2001 From: Nomango Date: Mon, 8 Jun 2020 20:20:06 +0800 Subject: [PATCH 03/11] update singleton --- src/kiwano-audio/AudioModule.h | 4 ++-- src/kiwano/base/Director.h | 4 ++-- src/kiwano/core/Singleton.h | 35 ++++++++++++++++++++++++-------- src/kiwano/platform/FileSystem.h | 4 ++-- src/kiwano/platform/Input.h | 4 ++-- src/kiwano/render/TextureCache.h | 4 ++-- src/kiwano/utils/Logger.h | 4 ++-- src/kiwano/utils/ResourceCache.h | 4 ++-- 8 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/kiwano-audio/AudioModule.h b/src/kiwano-audio/AudioModule.h index a97e4078..0e51eb72 100644 --- a/src/kiwano-audio/AudioModule.h +++ b/src/kiwano-audio/AudioModule.h @@ -68,11 +68,11 @@ public: void DestroyModule() override; + ~AudioModule(); + private: AudioModule(); - ~AudioModule(); - private: IXAudio2* x_audio2_; IXAudio2MasteringVoice* mastering_voice_; diff --git a/src/kiwano/base/Director.h b/src/kiwano/base/Director.h index fd054672..6a775670 100644 --- a/src/kiwano/base/Director.h +++ b/src/kiwano/base/Director.h @@ -102,11 +102,11 @@ public: void HandleEvent(Event* evt) override; + virtual ~Director(); + private: Director(); - virtual ~Director(); - private: bool render_border_enabled_; Stack stages_; diff --git a/src/kiwano/core/Singleton.h b/src/kiwano/core/Singleton.h index 7ed4e853..c067e1d4 100644 --- a/src/kiwano/core/Singleton.h +++ b/src/kiwano/core/Singleton.h @@ -19,12 +19,13 @@ // THE SOFTWARE. #pragma once +#include namespace kiwano { template -struct Singleton +class Singleton { protected: Singleton() = default; @@ -32,29 +33,47 @@ protected: Singleton& operator=(const Singleton&) = delete; private: - struct ObjectCreator + struct InstanceCreator { - ObjectCreator() + InstanceCreator() { - (void)Singleton<_Ty>::GetInstance(); + (void)Singleton<_Ty>::GetInstancePtr(); } inline void Dummy() const {} }; - static ObjectCreator creator_; + static InstanceCreator creator_; public: using object_type = _Ty; + static std::unique_ptr instance_ptr_; + static inline object_type& GetInstance() { - static object_type instance; + return *GetInstancePtr(); + } + + static inline object_type* GetInstancePtr() + { creator_.Dummy(); - return instance; + if (!instance_ptr_) + { + instance_ptr_.reset(new object_type); + } + return instance_ptr_.get(); + } + + static inline void DestroyInstance() + { + instance_ptr_.reset(); } }; template -typename Singleton<_Ty>::ObjectCreator Singleton<_Ty>::creator_; +typename Singleton<_Ty>::InstanceCreator Singleton<_Ty>::creator_; + +template +typename std::unique_ptr<_Ty> Singleton<_Ty>::instance_ptr_; } // namespace kiwano diff --git a/src/kiwano/platform/FileSystem.h b/src/kiwano/platform/FileSystem.h index 943fed7a..a012ff78 100644 --- a/src/kiwano/platform/FileSystem.h +++ b/src/kiwano/platform/FileSystem.h @@ -102,11 +102,11 @@ public: */ bool ExtractResourceToFile(const Resource& res, const String& dest_file_name) const; + ~FileSystem(); + private: FileSystem(); - ~FileSystem(); - private: Vector search_paths_; UnorderedMap file_lookup_dict_; diff --git a/src/kiwano/platform/Input.h b/src/kiwano/platform/Input.h index d2a72793..2bd4ad84 100644 --- a/src/kiwano/platform/Input.h +++ b/src/kiwano/platform/Input.h @@ -112,11 +112,11 @@ public: void HandleEvent(Event* evt) override; + ~Input(); + private: Input(); - ~Input(); - void UpdateKey(KeyCode key, bool down); void UpdateButton(MouseButton btn, bool down); diff --git a/src/kiwano/render/TextureCache.h b/src/kiwano/render/TextureCache.h index 76caef85..4f82832c 100644 --- a/src/kiwano/render/TextureCache.h +++ b/src/kiwano/render/TextureCache.h @@ -74,11 +74,11 @@ public: /// @brief 清空缓存 void Clear(); + virtual ~TextureCache(); + private: TextureCache(); - virtual ~TextureCache(); - private: using TextureMap = UnorderedMap; TextureMap texture_cache_; diff --git a/src/kiwano/utils/Logger.h b/src/kiwano/utils/Logger.h index b4177507..d35fdc35 100644 --- a/src/kiwano/utils/Logger.h +++ b/src/kiwano/utils/Logger.h @@ -126,11 +126,11 @@ public: /// @note 此操作会重定向输出流到标准输出流 void ShowConsole(bool show); + ~Logger(); + private: Logger(); - ~Logger(); - void Prepare(Level level, StringStream& sstream); void Output(Level level, StringStream& sstream); diff --git a/src/kiwano/utils/ResourceCache.h b/src/kiwano/utils/ResourceCache.h index e6aaa9e8..58430b32 100644 --- a/src/kiwano/utils/ResourceCache.h +++ b/src/kiwano/utils/ResourceCache.h @@ -88,11 +88,11 @@ public: /// @brief 清空所有资源 void Clear(); + virtual ~ResourceCache(); + private: ResourceCache(); - virtual ~ResourceCache(); - private: UnorderedMap object_cache_; }; From 4946246f0f1c93b20e679b76dae7ec6594051ceb Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 01:55:17 +0800 Subject: [PATCH 04/11] minor fix --- src/kiwano/platform/Application.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 1a8ba46e..98921da9 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -42,7 +42,6 @@ Application::Application() Application::~Application() { - this->Destroy(); } void Application::Run(RunnerPtr runner) @@ -62,6 +61,25 @@ void Application::Run(RunnerPtr runner) c->SetupModule(); } + // Ensure resources are destroyed before exiting + class DestroyHelper + { + Function f; + + public: + DestroyHelper(Function f) + : f(f) + { + } + + ~DestroyHelper() + { + f(); + } + }; + + DestroyHelper helper([=]() { this->Destroy(); }); + // Everything is ready runner->OnReady(); @@ -77,8 +95,6 @@ void Application::Run(RunnerPtr runner) if (!runner->MainLoop(timer_->GetDeltaTime())) running_ = false; } - - this->Destroy(); } void Application::Pause() From ff0234559bb1152601780f278cc71244ddd01be1 Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 01:56:02 +0800 Subject: [PATCH 05/11] Window fullscreen mode supported --- src/kiwano/platform/Runner.cpp | 4 +- src/kiwano/platform/Runner.h | 2 + src/kiwano/platform/Window.cpp | 5 + src/kiwano/platform/Window.h | 9 +- src/kiwano/platform/win32/WindowImpl.cpp | 178 +++++++++++------- .../render/DirectX/D3D10DeviceResources.cpp | 10 +- .../render/DirectX/D3D11DeviceResources.cpp | 10 +- .../render/DirectX/D3DDeviceResourcesBase.h | 2 +- src/kiwano/render/DirectX/RendererImpl.cpp | 9 +- 9 files changed, 136 insertions(+), 93 deletions(-) diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index 175a0c07..90099f3a 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -82,8 +82,8 @@ void Runner::InitSettings() } // Create game window - WindowPtr window = - Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable); + WindowPtr window = Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, + settings_.resizable, settings_.fullscreen); SetWindow(window); // Update renderer settings diff --git a/src/kiwano/platform/Runner.h b/src/kiwano/platform/Runner.h index 20c0c4b7..68743408 100644 --- a/src/kiwano/platform/Runner.h +++ b/src/kiwano/platform/Runner.h @@ -45,6 +45,7 @@ struct Settings String title; ///< 窗口标题 uint32_t icon; ///< 窗口图标 bool resizable; ///< 窗口大小可调整 + bool fullscreen; ///< 窗口全屏 Color bg_color; ///< 窗口背景色 Duration frame_interval; ///< 帧间隔 bool vsync_enabled; ///< 垂直同步 @@ -56,6 +57,7 @@ struct Settings , title("Kiwano") , icon() , resizable(false) + , fullscreen(false) , bg_color(Color::Black) , frame_interval(16) , vsync_enabled(false) diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index e92b7212..3501ab6c 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -71,6 +71,11 @@ uint32_t Window::GetHeight() const return height_; } +Resolution Window::GetCurrentResolution() const +{ + return resolution_; +} + WindowHandle Window::GetHandle() const { return handle_; diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index 08b9d25a..5a6c89b6 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -80,7 +80,7 @@ public: * @throw kiwano::SystemError 窗口创建失败时抛出 */ static WindowPtr Create(const String& title, uint32_t width, uint32_t height, uint32_t icon = 0, - bool resizable = false); + bool resizable = false, bool fullscreen = false); /** * \~chinese @@ -110,6 +110,12 @@ public: */ uint32_t GetHeight() const; + /** + * \~chinese + * @brief 获取当前分辨率 + */ + Resolution GetCurrentResolution() const; + /** * \~chinese * @brief 获取窗口句柄 @@ -214,6 +220,7 @@ protected: uint32_t min_height_; uint32_t max_width_; uint32_t max_height_; + Resolution resolution_; WindowHandle handle_; String title_; std::queue event_queue_; diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index 6cba0482..21634135 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include // GET_X_LPARAM, GET_Y_LPARAM #include // ImmAssociateContext #pragma comment(lib, "imm32.lib") @@ -49,7 +48,7 @@ public: virtual ~WindowWin32Impl(); - void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable); + void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen); void SetTitle(const String& title) override; @@ -69,6 +68,8 @@ public: DWORD GetStyle() const; + void SetActive(bool active); + void UpdateCursor(); LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM); @@ -86,12 +87,13 @@ private: std::array key_map_; }; -WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) +WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, + bool fullscreen) { WindowWin32ImplPtr ptr = memory::New(); if (ptr) { - ptr->Init(title, width, height, icon, resizable); + ptr->Init(title, width, height, icon, resizable, fullscreen); } return ptr; } @@ -103,6 +105,7 @@ namespace kiwano #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 +#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP namespace { @@ -202,7 +205,8 @@ WindowWin32Impl::~WindowWin32Impl() ::timeEndPeriod(0); } -void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) +void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, + bool fullscreen) { HINSTANCE hinst = GetModuleHandle(nullptr); WNDCLASSEXA wcex = { 0 }; @@ -249,10 +253,13 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, width = win_width; height = win_height; - width_ = width; - height_ = height; - resizable_ = resizable; - handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr, + width_ = width; + height_ = height; + resizable_ = resizable; + is_fullscreen_ = fullscreen; + resolution_ = Resolution{ width_, height_, 0 }; + + handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr, nullptr, hinst, nullptr); if (handle_ == nullptr) @@ -269,6 +276,19 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, ::ShowWindow(handle_, SW_SHOWNORMAL); ::UpdateWindow(handle_); + + if (is_fullscreen_) + { + MONITORINFOEXA info = GetMoniterInfoEx(handle_); + int x = (int)info.rcMonitor.left; + int y = (int)info.rcMonitor.top; + int cx = (int)(info.rcMonitor.right - info.rcMonitor.left); + int cy = (int)(info.rcMonitor.bottom - info.rcMonitor.top); + + // Top the window + ::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE); + ::ShowWindow(handle_, SW_SHOWNORMAL); + } } void WindowWin32Impl::PumpEvents() @@ -318,71 +338,78 @@ void WindowWin32Impl::SetCursor(CursorType cursor) void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen) { - auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); - - if (fullscreen) + if (is_fullscreen_ != fullscreen) { - HRESULT hr = d3d->ResizeTarget(width, height); - KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); + is_fullscreen_ = fullscreen; - hr = d3d->SetFullscreenState(fullscreen); - KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); + // Reset window style + ::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle()); + } + + if (is_fullscreen_) + { + MONITORINFOEXA info = GetMoniterInfoEx(handle_); + int x = (int)info.rcMonitor.left; + int y = (int)info.rcMonitor.top; + int cx = (int)(info.rcMonitor.right - info.rcMonitor.left); + int cy = (int)(info.rcMonitor.bottom - info.rcMonitor.top); + + // Top the window + ::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE); + ::ShowWindow(handle_, SW_SHOWNORMAL); } else { - HRESULT hr = d3d->SetFullscreenState(fullscreen); - KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); + // Adjust the rect of client area + RECT rc = { 0, 0, LONG(width), LONG(height) }; + ::AdjustWindowRect(&rc, GetStyle(), false); - hr = d3d->ResizeTarget(width, height); - KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); + width = uint32_t(rc.right - rc.left); + height = uint32_t(rc.bottom - rc.top); + + MONITORINFOEXA info = GetMoniterInfoEx(handle_); + uint32_t screenw = uint32_t(info.rcWork.right - info.rcWork.left); + uint32_t screenh = uint32_t(info.rcWork.bottom - info.rcWork.top); + int left = screenw > width ? ((screenw - width) / 2) : 0; + int top = screenh > height ? ((screenh - height) / 2) : 0; + + // Reset window style + ::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle()); + + // Unpin the window + ::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, width, height, SWP_DRAWFRAME | SWP_FRAMECHANGED); + ::ShowWindow(handle_, SW_SHOWNORMAL); } - is_fullscreen_ = fullscreen; + resolution_ = Resolution{ width, height, 0 }; + + // Resize render target + Renderer::GetInstance().Resize(width, height); } Vector WindowWin32Impl::GetResolutions() { if (resolutions_.empty()) { - auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); + Set resolution_list; - DXGI_MODE_DESC* mode_descs = nullptr; - int mode_num = 0; + DEVMODEA dmi; + ZeroMemory(&dmi, sizeof(dmi)); + dmi.dmSize = sizeof(dmi); - HRESULT hr = d3d->GetDisplaySettings(&mode_descs, &mode_num); - if (SUCCEEDED(hr)) + DWORD mode_count = 0; + while (EnumDisplaySettingsA(device_name_.c_str(), mode_count++, &dmi) != 0) { - std::unique_ptr mode_list(mode_descs); + StringStream ss; + ss << dmi.dmPelsWidth << 'x' << dmi.dmPelsHeight << ':' << dmi.dmDisplayFrequency; - if (mode_list) + if (resolution_list.find(ss.str()) == resolution_list.end()) { - for (int i = 0; i < mode_num; i++) - { - Resolution res; - res.width = mode_descs[i].Width; - res.height = mode_descs[i].Height; - res.refresh_rate = 0; - - if (mode_descs[i].RefreshRate.Denominator > 0) - { - res.refresh_rate = mode_descs[i].RefreshRate.Numerator / mode_descs[i].RefreshRate.Denominator; - } - - if (!resolutions_.empty()) - { - auto& back = resolutions_.back(); - if (back.width == res.width && back.height == res.height - && back.refresh_rate == res.refresh_rate) - continue; - } - - resolutions_.push_back(res); - } + resolution_list.insert(ss.str()); + resolutions_.push_back(Resolution{ uint32_t(dmi.dmPelsWidth), uint32_t(dmi.dmPelsHeight), + uint32_t(dmi.dmDisplayFrequency) }); } - } - else - { - KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!"); + ZeroMemory(&dmi, sizeof(dmi)); } } return resolutions_; @@ -390,7 +417,30 @@ Vector WindowWin32Impl::GetResolutions() DWORD WindowWin32Impl::GetStyle() const { - return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); + if (is_fullscreen_) + return WINDOW_FULLSCREEN_STYLE; + if (resizable_) + return WINDOW_RESIZABLE_STYLE; + return WINDOW_FIXED_STYLE; +} + +void WindowWin32Impl::SetActive(bool active) +{ + if (!handle_) + return; + + if (is_fullscreen_) + { + // Hide window when it is not active + if (active) + { + ::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + else + { + ::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } } void WindowWin32Impl::UpdateCursor() @@ -658,8 +708,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { if (is_fullscreen_) { - // TODO restore to fullscreen mode - // SetResolution(); + SetActive(true); } } break; @@ -668,8 +717,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { if (is_fullscreen_) { - // TODO exit fullscreen mode - // ::ShowWindow(handle_, SW_MINIMIZE); + SetActive(false); } } break; @@ -695,18 +743,6 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_DISPLAYCHANGE: { KGE_SYS_LOG("The display resolution has changed"); - - // Check fullscreen state - auto d3d_res = graphics::directx::GetD3DDeviceResources(); - auto swap_chain = d3d_res->GetDXGISwapChain(); - if (swap_chain) - { - BOOL is_fullscreen = FALSE; - if (SUCCEEDED(swap_chain->GetFullscreenState(&is_fullscreen, nullptr))) - { - is_fullscreen_ = !!is_fullscreen; - } - } } break; diff --git a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp index e10427db..9b388d44 100644 --- a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp @@ -68,7 +68,7 @@ inline bool SdkLayersAvailable() struct D3D10DeviceResources : public ID3D10DeviceResources { public: - HRESULT Initialize(HWND hwnd) override; + HRESULT Initialize(HWND hwnd, Size logical_size) override; HRESULT Present(bool vsync) override; @@ -138,14 +138,10 @@ D3D10DeviceResources::~D3D10DeviceResources() DiscardResources(); } -HRESULT D3D10DeviceResources::Initialize(HWND hwnd) +HRESULT D3D10DeviceResources::Initialize(HWND hwnd, Size logical_size) { - RECT rc; - ::GetClientRect(hwnd, &rc); - this->hwnd_ = hwnd; - this->logical_size_.x = float(rc.right - rc.left); - this->logical_size_.y = float(rc.bottom - rc.top); + this->logical_size_ = logical_size; HRESULT hr = this->CreateDeviceResources(); diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp index e767c848..31e0c3f4 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp @@ -60,7 +60,7 @@ inline bool SdkLayersAvailable() struct D3D11DeviceResources : public ID3D11DeviceResources { public: - HRESULT Initialize(HWND hwnd) override; + HRESULT Initialize(HWND hwnd, Size logical_size) override; HRESULT Present(bool vsync) override; @@ -133,14 +133,10 @@ D3D11DeviceResources::~D3D11DeviceResources() DiscardResources(); } -HRESULT D3D11DeviceResources::Initialize(HWND hwnd) +HRESULT D3D11DeviceResources::Initialize(HWND hwnd, Size logical_size) { - RECT rc; - ::GetClientRect(hwnd, &rc); - this->hwnd_ = hwnd; - this->logical_size_.x = float(rc.right - rc.left); - this->logical_size_.y = float(rc.bottom - rc.top); + this->logical_size_ = logical_size; HRESULT hr = this->CreateDeviceResources(); diff --git a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h index a14ab67b..75961d89 100644 --- a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h +++ b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h @@ -32,7 +32,7 @@ MIDL_INTERFACE("fb99fa64-d9cf-4e0e-9c75-90514797b01d") ID3DDeviceResourcesBase : public IUnknown { public: - virtual HRESULT Initialize(HWND hwnd) = 0; + virtual HRESULT Initialize(HWND hwnd, Size logical_size) = 0; virtual HRESULT Present(bool vsync) = 0; diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 571f9213..2e039848 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -55,17 +55,18 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed"); - HWND target_window = window->GetHandle(); - output_size_ = window->GetSize(); + HWND target_window = window->GetHandle(); + Resolution resolution = window->GetCurrentResolution(); + HRESULT hr = target_window ? S_OK : E_FAIL; - HRESULT hr = target_window ? S_OK : E_FAIL; + output_size_ = Size{ float(resolution.width), float(resolution.height) }; // Initialize Direct3D resources if (SUCCEEDED(hr)) { auto d3d_res = graphics::directx::GetD3DDeviceResources(); - hr = d3d_res->Initialize(target_window); + hr = d3d_res->Initialize(target_window, output_size_); if (FAILED(hr)) { d3d_res->DiscardResources(); From 5bebd422fb0bd6578a8bf8423a827b794451b7d8 Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 14:33:07 +0800 Subject: [PATCH 06/11] add defer macros --- projects/kiwano/kiwano.vcxproj | 1 + projects/kiwano/kiwano.vcxproj.filters | 3 ++ src/kiwano/core/Defer.h | 69 ++++++++++++++++++++++++++ src/kiwano/kiwano.h | 1 + src/kiwano/platform/Application.cpp | 20 ++------ 5 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 src/kiwano/core/Defer.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index a0ca2a9c..f7d520dd 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -23,6 +23,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 94ab0a18..7e28e439 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -354,6 +354,9 @@ base + + core + diff --git a/src/kiwano/core/Defer.h b/src/kiwano/core/Defer.h new file mode 100644 index 00000000..961c6c52 --- /dev/null +++ b/src/kiwano/core/Defer.h @@ -0,0 +1,69 @@ +// Copyright (c) 2016-2018 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 + +namespace kiwano +{ + +class Defer +{ +public: + Defer() = default; + + Defer(const Function& func) + : func_(func) + { + } + + Defer(Defer&& other) noexcept + : func_(other.func_) + { + other.func_ = nullptr; + } + + ~Defer() + { + if (func_) + func_(); + } + +private: + Defer(const Defer&) = delete; + Defer& operator=(const Defer&) = delete; + + Function func_; +}; + +class __DeferHelper +{ +public: + Defer operator-(const Function& func) const + { + return Defer{ func }; + } +}; + +#define KGE_DEFER auto __KGE_DEFER_VAR(__defer_line_, __LINE__, __) = ::kiwano::__DeferHelper() - +#define __KGE_DEFER_VAR(a, b, c) __KGE_DEFER_TOKEN_CONNECT(a, b, c) +#define __KGE_DEFER_TOKEN_CONNECT(a, b, c) a##b##c + +} // namespace kiwano diff --git a/src/kiwano/kiwano.h b/src/kiwano/kiwano.h index 1bd37f0f..d4630520 100644 --- a/src/kiwano/kiwano.h +++ b/src/kiwano/kiwano.h @@ -44,6 +44,7 @@ // #include +#include #include #include #include diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 98921da9..a117aa31 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -19,11 +19,12 @@ // THE SOFTWARE. #include -#include +#include #include #include #include #include +#include namespace kiwano { @@ -62,24 +63,11 @@ void Application::Run(RunnerPtr runner) } // Ensure resources are destroyed before exiting - class DestroyHelper + KGE_DEFER[=]() { - Function f; - - public: - DestroyHelper(Function f) - : f(f) - { - } - - ~DestroyHelper() - { - f(); - } + this->Destroy(); }; - DestroyHelper helper([=]() { this->Destroy(); }); - // Everything is ready runner->OnReady(); From 9fa8639d95654f46d7bd3b943d8e2ccc70bb32f0 Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 16:10:45 +0800 Subject: [PATCH 07/11] add EventListener::ShouldHandle function --- src/kiwano/event/Event.h | 17 +++++++++-------- src/kiwano/event/EventDispatcher.h | 4 ++-- src/kiwano/event/EventListener.cpp | 8 ++++++++ src/kiwano/event/EventListener.h | 21 +++++++++++++-------- src/kiwano/event/KeyEvent.h | 6 +++--- src/kiwano/event/MouseEvent.h | 6 +++--- src/kiwano/event/WindowEvent.h | 6 +++--- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/kiwano/event/Event.h b/src/kiwano/event/Event.h index 16242d27..80fa0b76 100644 --- a/src/kiwano/event/Event.h +++ b/src/kiwano/event/Event.h @@ -54,7 +54,7 @@ public: /// \~chinese /// @brief 判断事件类型 - /// @return 是否是指定事件类型 + /// @return 事件类型相同返回true,否则返回false template bool IsType() const; @@ -75,19 +75,20 @@ private: }; /// \~chinese -/// @brief 事件特性:判断指定类型是否是事件 +/// @brief 事件特性:判断是否是事件 template -struct IsEvent : public std::bool_constant::value || std::is_same::value> +struct IsBaseOfEvent : public std::bool_constant::value || std::is_same::value> { }; /// \~chinese -/// @brief 事件特性:判断一个事件能否安全转换到另一事件类型 -template ::value, int>::type> -struct IsEventType +/// @brief 事件特性:判断事件类型是否相同 +template +struct IsSameEventType { inline bool operator()(const Event* evt) const { + static_assert(kiwano::IsBaseOfEvent<_Ty>::value, "_Ty is not an event type."); return evt->GetType() == KGE_EVENT(_Ty); } }; @@ -102,8 +103,8 @@ inline const EventType& Event::GetType() const template inline bool Event::IsType() const { - static_assert(kiwano::IsEvent<_Ty>::value, "_Ty is not an event type."); - return kiwano::IsEventType<_Ty>()(this); + static_assert(kiwano::IsBaseOfEvent<_Ty>::value, "_Ty is not an event type."); + return IsSameEventType<_Ty>()(this); } template diff --git a/src/kiwano/event/EventDispatcher.h b/src/kiwano/event/EventDispatcher.h index 6e5a0861..6e46a9a4 100644 --- a/src/kiwano/event/EventDispatcher.h +++ b/src/kiwano/event/EventDispatcher.h @@ -59,7 +59,7 @@ public: template EventListener* AddListener(EventListener::Callback callback) { - static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); + static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); return AddListener(KGE_EVENT(_EventTy), callback); } @@ -71,7 +71,7 @@ public: template EventListener* AddListener(const String& name, EventListener::Callback callback) { - static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); + static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); return AddListener(name, KGE_EVENT(_EventTy), callback); } diff --git a/src/kiwano/event/EventListener.cpp b/src/kiwano/event/EventListener.cpp index 1549d5d3..060ba62d 100644 --- a/src/kiwano/event/EventListener.cpp +++ b/src/kiwano/event/EventListener.cpp @@ -58,4 +58,12 @@ EventListener::EventListener() EventListener::~EventListener() {} +void EventListener::Receive(Event* evt) +{ + if (ShouldHandle(evt) && callback_) + { + callback_(evt); + } +} + } // namespace kiwano diff --git a/src/kiwano/event/EventListener.h b/src/kiwano/event/EventListener.h index d179ba11..4baed41b 100644 --- a/src/kiwano/event/EventListener.h +++ b/src/kiwano/event/EventListener.h @@ -67,7 +67,7 @@ public: template static inline EventListenerPtr Create(const Callback& callback) { - static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); + static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); return EventListener::Create(KGE_EVENT(_EventTy), callback); } @@ -79,7 +79,7 @@ public: template static inline EventListenerPtr Create(const String& name, const Callback& callback) { - static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); + static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); return EventListener::Create(name, KGE_EVENT(_EventTy), callback); } @@ -132,12 +132,17 @@ public: /// @brief 设置监听的事件类型 void SetEventType(const EventType& type); + /// \~chinese + /// @brief 判断是否处理事件 + virtual bool ShouldHandle(Event* evt) const; + /// \~chinese /// @brief 设置监听的事件类型 /// @tparam _EventTy 事件类型 - template ::value, int>::type> + template inline void SetEventType() { + static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); SetEventType(KGE_EVENT(_EventTy)); } @@ -208,13 +213,13 @@ inline void EventListener::SetEventType(const EventType& type) type_ = type; } -inline void EventListener::Receive(Event* evt) +inline bool EventListener::ShouldHandle(Event* evt) const { - KGE_ASSERT(evt != nullptr); - - if (type_ == evt->GetType() && callback_) + if (evt) { - callback_(evt); + return evt->GetType() == type_; } + return false; } + } // namespace kiwano diff --git a/src/kiwano/event/KeyEvent.h b/src/kiwano/event/KeyEvent.h index a56ed119..390cd01d 100644 --- a/src/kiwano/event/KeyEvent.h +++ b/src/kiwano/event/KeyEvent.h @@ -72,10 +72,8 @@ public: KeyCharEvent(); }; -/** @} */ - template <> -struct IsEventType +struct IsSameEventType { inline bool operator()(const Event* evt) const { @@ -84,4 +82,6 @@ struct IsEventType } }; +/** @} */ + } // namespace kiwano diff --git a/src/kiwano/event/MouseEvent.h b/src/kiwano/event/MouseEvent.h index 29731d39..6a308d93 100644 --- a/src/kiwano/event/MouseEvent.h +++ b/src/kiwano/event/MouseEvent.h @@ -113,10 +113,8 @@ public: MouseWheelEvent(); }; -/** @} */ - template <> -struct IsEventType +struct IsSameEventType { inline bool operator()(const Event* evt) const { @@ -127,4 +125,6 @@ struct IsEventType } }; +/** @} */ + } // namespace kiwano diff --git a/src/kiwano/event/WindowEvent.h b/src/kiwano/event/WindowEvent.h index 4370422d..d0c5da83 100644 --- a/src/kiwano/event/WindowEvent.h +++ b/src/kiwano/event/WindowEvent.h @@ -93,10 +93,8 @@ public: WindowClosedEvent(); }; -/** @} */ - template <> -struct IsEventType +struct IsSameEventType { inline bool operator()(const Event* evt) const { @@ -107,4 +105,6 @@ struct IsEventType } }; +/** @} */ + } // namespace kiwano From e981457370e09c10aefd0a1b8b6303af31056eba Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 16:51:56 +0800 Subject: [PATCH 08/11] update ActionHelper --- src/kiwano/2d/action/ActionHelper.h | 68 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/kiwano/2d/action/ActionHelper.h b/src/kiwano/2d/action/ActionHelper.h index a3428dd9..072ae0b5 100644 --- a/src/kiwano/2d/action/ActionHelper.h +++ b/src/kiwano/2d/action/ActionHelper.h @@ -36,11 +36,9 @@ namespace kiwano /// @brief 动画辅助类 struct ActionHelper { - using DoneCallback = Action::DoneCallback; - /// \~chinese /// @brief 设置循环次数 - inline ActionHelper& SetLoops(int loops) + inline ActionHelper& Loops(int loops) { ptr->SetLoops(loops); return (*this); @@ -48,7 +46,7 @@ struct ActionHelper /// \~chinese /// @brief 设置动画延迟 - inline ActionHelper& SetDelay(Duration delay) + inline ActionHelper& Delay(Duration delay) { ptr->SetDelay(delay); return (*this); @@ -56,7 +54,7 @@ struct ActionHelper /// \~chinese /// @brief 设置动画结束回调函数 - inline ActionHelper& SetDoneCallback(const DoneCallback& cb) + inline ActionHelper& DoneCallback(const Action::DoneCallback& cb) { ptr->SetDoneCallback(cb); return (*this); @@ -64,7 +62,7 @@ struct ActionHelper /// \~chinese /// @brief 设置动画循环结束时的回调函数 - inline ActionHelper& SetLoopDoneCallback(const DoneCallback& cb) + inline ActionHelper& LoopDoneCallback(const Action::DoneCallback& cb) { ptr->SetLoopDoneCallback(cb); return (*this); @@ -80,7 +78,7 @@ struct ActionHelper /// \~chinese /// @brief 设置名称 - inline ActionHelper& SetName(const String& name) + inline ActionHelper& Name(const String& name) { ptr->SetName(name); return (*this); @@ -116,11 +114,9 @@ private: /// @brief 补间动画辅助类 struct TweenHelper { - using DoneCallback = Action::DoneCallback; - /// \~chinese /// @brief 设置动画持续时长 - inline TweenHelper& SetDuration(Duration dur) + inline TweenHelper& Dur(Duration dur) { ptr->SetDuration(dur); return (*this); @@ -128,7 +124,7 @@ struct TweenHelper /// \~chinese /// @brief 设置循环次数 - inline TweenHelper& SetLoops(int loops) + inline TweenHelper& Loops(int loops) { ptr->SetLoops(loops); return (*this); @@ -136,7 +132,7 @@ struct TweenHelper /// \~chinese /// @brief 设置缓动函数 - inline TweenHelper& SetEaseFunc(EaseFunc ease) + inline TweenHelper& EaseFunc(EaseFunc ease) { ptr->SetEaseFunc(ease); return (*this); @@ -144,7 +140,7 @@ struct TweenHelper /// \~chinese /// @brief 设置动画延迟 - inline TweenHelper& SetDelay(Duration delay) + inline TweenHelper& Delay(Duration delay) { ptr->SetDelay(delay); return (*this); @@ -152,7 +148,7 @@ struct TweenHelper /// \~chinese /// @brief 设置动画结束回调函数 - inline TweenHelper& SetDoneCallback(const DoneCallback& cb) + inline TweenHelper& DoneCallback(const Action::DoneCallback& cb) { ptr->SetDoneCallback(cb); return (*this); @@ -160,7 +156,7 @@ struct TweenHelper /// \~chinese /// @brief 设置动画循环结束时的回调函数 - inline TweenHelper& SetLoopDoneCallback(const DoneCallback& cb) + inline TweenHelper& LoopDoneCallback(const Action::DoneCallback& cb) { ptr->SetLoopDoneCallback(cb); return (*this); @@ -176,7 +172,7 @@ struct TweenHelper /// \~chinese /// @brief 设置名称 - inline TweenHelper& SetName(const String& name) + inline TweenHelper& Name(const String& name) { ptr->SetName(name); return (*this); @@ -220,7 +216,7 @@ struct Tween public: /// \~chinese /// @brief 构造相对位移动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param vector 移动向量 static inline TweenHelper MoveBy(Duration dur, const Point& vector) { @@ -229,7 +225,7 @@ public: /// \~chinese /// @brief 构造位移动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param pos 目的坐标 static inline TweenHelper MoveTo(Duration dur, const Point& pos) { @@ -238,29 +234,29 @@ public: /// \~chinese /// @brief 构造相对跳跃动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param vec 跳跃位移向量 /// @param height 跳跃高度 /// @param jumps 跳跃次数 - static inline TweenHelper JumpBy(Duration duration, const Vec2& vec, float height, int jumps = 1) + static inline TweenHelper JumpBy(Duration dur, const Vec2& vec, float height, int jumps = 1) { - return TweenHelper(ActionJumpBy::Create(duration, vec, height, jumps)); + return TweenHelper(ActionJumpBy::Create(dur, vec, height, jumps)); } /// \~chinese /// @brief 构造跳跃动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param pos 目的坐标 /// @param height 跳跃高度 /// @param jumps 跳跃次数 - static inline TweenHelper JumpTo(Duration duration, const Point& pos, float height, int jumps = 1) + static inline TweenHelper JumpTo(Duration dur, const Point& pos, float height, int jumps = 1) { - return TweenHelper(ActionJumpTo::Create(duration, pos, height, jumps)); + return TweenHelper(ActionJumpTo::Create(dur, pos, height, jumps)); } /// \~chinese /// @brief 构造相对缩放动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param scale_x 横向缩放相对变化值 /// @param scale_y 纵向缩放相对变化值 static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y) @@ -270,7 +266,7 @@ public: /// \~chinese /// @brief 构造缩放动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param scale_x 横向缩放目标值 /// @param scale_y 纵向缩放目标值 static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y) @@ -280,7 +276,7 @@ public: /// \~chinese /// @brief 构造透明度渐变动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param opacity 目标透明度 static inline TweenHelper FadeTo(Duration dur, float opacity) { @@ -289,7 +285,7 @@ public: /// \~chinese /// @brief 构造淡入动画 - /// @param duration 动画时长 + /// @param dur 动画时长 static inline TweenHelper FadeIn(Duration dur) { return TweenHelper(ActionFadeIn::Create(dur)); @@ -297,7 +293,7 @@ public: /// \~chinese /// @brief 构造淡出动画 - /// @param duration 动画时长 + /// @param dur 动画时长 static inline TweenHelper FadeOut(Duration dur) { return TweenHelper(ActionFadeOut::Create(dur)); @@ -305,7 +301,7 @@ public: /// \~chinese /// @brief 构造相对旋转动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param rotation 角度相对变化值 static inline TweenHelper RotateBy(Duration dur, float rotation) { @@ -314,7 +310,7 @@ public: /// \~chinese /// @brief 构造旋转动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param rotation 目标角度 static inline TweenHelper RotateTo(Duration dur, float rotation) { @@ -323,20 +319,20 @@ public: /// \~chinese /// @brief 构造路径行走动画 - /// @param duration 持续时长 + /// @param dur 持续时长 /// @param path 路径形状 /// @param rotating 是否沿路径切线方向旋转 /// @param start 路径起点(百分比) /// @param end 路径终点(百分比) - static inline TweenHelper Walk(Duration duration, ShapePtr path, bool rotating = false, float start = 0.f, + static inline TweenHelper Walk(Duration dur, ShapePtr path, bool rotating = false, float start = 0.f, float end = 1.f) { - return TweenHelper(ActionWalk::Create(duration, path, rotating, start, end)); + return TweenHelper(ActionWalk::Create(dur, path, rotating, start, end)); } /// \~chinese /// @brief 构建帧动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param[in] frame_seq 序列帧 static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames) { @@ -345,7 +341,7 @@ public: /// \~chinese /// @brief 构造自定义动画 - /// @param duration 动画时长 + /// @param dur 动画时长 /// @param tween_func 动画回调函数 static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func) { From 0f3b5ca47321d10350c67d86b218c1d39d9a78ba Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 18:02:33 +0800 Subject: [PATCH 09/11] update ComponentManager & remove Actor::GetPhysicBody --- src/kiwano-physics/PhysicBody.cpp | 25 +++- src/kiwano-physics/PhysicBody.h | 10 ++ src/kiwano-physics/PhysicWorld.cpp | 4 +- src/kiwano/2d/Actor.cpp | 1 - src/kiwano/2d/Actor.h | 25 ---- src/kiwano/base/component/Button.cpp | 2 +- src/kiwano/base/component/Component.h | 3 - .../base/component/ComponentManager.cpp | 113 ++++++++++-------- src/kiwano/base/component/ComponentManager.h | 29 +++-- 9 files changed, 120 insertions(+), 92 deletions(-) diff --git a/src/kiwano-physics/PhysicBody.cpp b/src/kiwano-physics/PhysicBody.cpp index b10f8fd2..e74675f0 100644 --- a/src/kiwano-physics/PhysicBody.cpp +++ b/src/kiwano-physics/PhysicBody.cpp @@ -21,6 +21,8 @@ #include #include +#define KGE_PHYSIC_COMP_NAME "__KGE_PHYSIC_BODY__" + namespace kiwano { namespace physics @@ -48,6 +50,25 @@ PhysicBodyPtr PhysicBody::Create(PhysicWorld* world, Type type) return nullptr; } +PhysicBody* PhysicBody::Get(Actor* actor) +{ + if (actor) + { + static size_t physic_comp_name_hash = 0; + if (physic_comp_name_hash == 0) + { + physic_comp_name_hash = std::hash{}(KGE_PHYSIC_COMP_NAME); + } + return (PhysicBody*)actor->GetComponent(physic_comp_name_hash); + } + return nullptr; +} + +PhysicBody* PhysicBody::Get(ActorPtr actor) +{ + return PhysicBody::Get(actor.Get()); +} + PhysicBody::PhysicBody() : body_(nullptr) , world_(nullptr) @@ -56,7 +77,7 @@ PhysicBody::PhysicBody() , mask_bits_(0xFFFF) , group_index_(0) { - SetName("KGE_PHYSIC_BODY"); + SetName(KGE_PHYSIC_COMP_NAME); } PhysicBody::~PhysicBody() {} @@ -65,8 +86,6 @@ void PhysicBody::InitComponent(Actor* actor) { Component::InitComponent(actor); - actor->SetPhysicBody(this); - UpdateFromActor(actor); } diff --git a/src/kiwano-physics/PhysicBody.h b/src/kiwano-physics/PhysicBody.h index 875e4a8a..638fd3ad 100644 --- a/src/kiwano-physics/PhysicBody.h +++ b/src/kiwano-physics/PhysicBody.h @@ -62,6 +62,16 @@ public: /// @param type 物体类型 static PhysicBodyPtr Create(PhysicWorld* world, Type type); + /// \~chinese + /// @brief 获取角色的物理身体 + /// @param actor 角色 + static PhysicBody* Get(Actor* actor); + + /// \~chinese + /// @brief 获取角色的物理身体 + /// @param actor 角色 + static PhysicBody* Get(ActorPtr actor); + PhysicBody(); virtual ~PhysicBody(); diff --git a/src/kiwano-physics/PhysicWorld.cpp b/src/kiwano-physics/PhysicWorld.cpp index e97384b7..d8e447ab 100644 --- a/src/kiwano-physics/PhysicWorld.cpp +++ b/src/kiwano-physics/PhysicWorld.cpp @@ -413,7 +413,7 @@ void PhysicWorld::BeforeSimulation(Actor* parent, const Matrix3x2& parent_to_wor { Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world; - PhysicBody* body = child->GetPhysicBody(); + PhysicBody* body = PhysicBody::Get(child); if (body) { body->BeforeSimulation(child.Get(), parent_to_world, child_to_world, parent_rotation); @@ -428,7 +428,7 @@ void PhysicWorld::AfterSimulation(Actor* parent, const Matrix3x2& parent_to_worl { for (auto child : parent->GetAllChildren()) { - PhysicBody* body = child->GetPhysicBody(); + PhysicBody* body = PhysicBody::Get(child); if (body) { body->AfterSimulation(child.Get(), parent_to_world, parent_rotation); diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 5f54647c..f206e223 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -66,7 +66,6 @@ Actor::Actor() , opacity_(1.f) , displayed_opacity_(1.f) , anchor_(default_anchor_x, default_anchor_y) - , physic_body_(nullptr) { } diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index f0e258a0..c9da9662 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -33,11 +33,6 @@ class Stage; class Director; class RenderContext; -namespace physics -{ -class PhysicBody; -} - KGE_DECLARE_SMART_PTR(Actor); /// \~chinese @@ -391,14 +386,6 @@ public: /// @brief 获取更新时的回调函数 UpdateCallback GetCallbackOnUpdate() const; - /// \~chinese - /// @brief 获取物理身体,仅当kiwano-physics包启用时生效 - physics::PhysicBody* GetPhysicBody() const; - - /// \~chinese - /// @brief 设置物理身体,仅当kiwano-physics包启用时生效 - void SetPhysicBody(physics::PhysicBody* body); - /// \~chinese /// @brief 判断点是否在角色内 virtual bool ContainsPoint(const Point& point) const; @@ -502,8 +489,6 @@ private: mutable Matrix3x2 transform_matrix_; mutable Matrix3x2 transform_matrix_inverse_; mutable Matrix3x2 transform_matrix_to_parent_; - - physics::PhysicBody* physic_body_; }; /** @} */ @@ -688,16 +673,6 @@ inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const return cb_update_; } -inline physics::PhysicBody* Actor::GetPhysicBody() const -{ - return physic_body_; -} - -inline void Actor::SetPhysicBody(physics::PhysicBody* body) -{ - physic_body_ = body; -} - inline void Actor::ShowBorder(bool show) { show_border_ = show; diff --git a/src/kiwano/base/component/Button.cpp b/src/kiwano/base/component/Button.cpp index a8150917..c8fbc49b 100644 --- a/src/kiwano/base/component/Button.cpp +++ b/src/kiwano/base/component/Button.cpp @@ -47,7 +47,7 @@ ButtonPtr Button::Create(const Callback& click, const Callback& pressed, const C Button::Button() : status_(Status::Normal) { - SetName("KGE_BUTTON"); + SetName("__KGE_BUTTON__"); } Button::~Button() diff --git a/src/kiwano/base/component/Component.h b/src/kiwano/base/component/Component.h index c48a168a..ccd31895 100644 --- a/src/kiwano/base/component/Component.h +++ b/src/kiwano/base/component/Component.h @@ -21,7 +21,6 @@ #pragma once #include #include -#include #include namespace kiwano @@ -49,10 +48,8 @@ KGE_DECLARE_SMART_PTR(Component); */ class KGE_API Component : public ObjectBase - , protected IntrusiveListValue { friend class ComponentManager; - friend IntrusiveList; public: /// \~chinese diff --git a/src/kiwano/base/component/ComponentManager.cpp b/src/kiwano/base/component/ComponentManager.cpp index 8f99ce75..5a77ec6b 100644 --- a/src/kiwano/base/component/ComponentManager.cpp +++ b/src/kiwano/base/component/ComponentManager.cpp @@ -19,6 +19,7 @@ // THE SOFTWARE. #include +#include namespace kiwano { @@ -35,45 +36,62 @@ Component* ComponentManager::AddComponent(ComponentPtr component) if (component) { component->InitComponent(target_); - components_.PushBack(component); + + size_t hash = std::hash{}(component->GetName()); + components_.insert(std::make_pair(hash, component)); } return component.Get(); } -ComponentList& ComponentManager::GetAllComponents() +Component* ComponentManager::GetComponent(const String& name) +{ + size_t hash = std::hash{}(name); + return GetComponent(hash); +} + +Component* ComponentManager::GetComponent(size_t name_hash) +{ + if (!components_.empty()) + { + auto iter = components_.find(name_hash); + if (iter != components_.end()) + { + return iter->second.Get(); + } + } + return nullptr; +} + +ComponentMap& ComponentManager::GetAllComponents() { return components_; } -const ComponentList& ComponentManager::GetAllComponents() const +const ComponentMap& ComponentManager::GetAllComponents() const { return components_; } void ComponentManager::RemoveComponent(ComponentPtr component) { - auto iter = std::find(components_.begin(), components_.end(), component); - if (iter != components_.end()) - { - component->DestroyComponent(); - components_.Remove(component); - } + RemoveComponent(component->GetName()); } -void ComponentManager::RemoveComponents(const String& name) +void ComponentManager::RemoveComponent(const String& name) { - if (!components_.IsEmpty()) - { - ComponentPtr next; - for (auto component = components_.GetFirst(); component; component = next) - { - next = component->GetNext(); + size_t hash = std::hash{}(name); + RemoveComponent(hash); +} - if (component->IsName(name)) - { - component->DestroyComponent(); - components_.Remove(component); - } +void ComponentManager::RemoveComponent(size_t name_hash) +{ + if (!components_.empty()) + { + auto iter = components_.find(name_hash); + if (iter != components_.end()) + { + iter->second->DestroyComponent(); + components_.erase(iter); } } } @@ -81,31 +99,28 @@ void ComponentManager::RemoveComponents(const String& name) void ComponentManager::RemoveAllComponents() { // Destroy all components - if (!components_.IsEmpty()) + if (!components_.empty()) { - ComponentPtr next; - for (auto component = components_.GetFirst(); component; component = next) + for (auto& p : components_) { - next = component->GetNext(); - - component->DestroyComponent(); + p.second->DestroyComponent(); } } - components_.Clear(); + components_.clear(); } void ComponentManager::Update(Duration dt) { - if (!components_.IsEmpty()) + if (!components_.empty()) { - ComponentPtr next; - for (auto component = components_.GetFirst(); component; component = next) + if (!components_.empty()) { - next = component->GetNext(); - - if (component->IsEnable()) + for (auto& p : components_) { - component->OnUpdate(dt); + if (p.second->IsEnable()) + { + p.second->OnUpdate(dt); + } } } } @@ -113,16 +128,16 @@ void ComponentManager::Update(Duration dt) void ComponentManager::Render(RenderContext& ctx) { - if (!components_.IsEmpty()) + if (!components_.empty()) { - ComponentPtr next; - for (auto component = components_.GetFirst(); component; component = next) + if (!components_.empty()) { - next = component->GetNext(); - - if (component->IsEnable()) + for (auto& p : components_) { - component->OnRender(ctx); + if (p.second->IsEnable()) + { + p.second->OnRender(ctx); + } } } } @@ -130,16 +145,16 @@ void ComponentManager::Render(RenderContext& ctx) void ComponentManager::DispatchToComponents(Event* evt) { - if (!components_.IsEmpty()) + if (!components_.empty()) { - ComponentPtr next; - for (auto component = components_.GetFirst(); component; component = next) + if (!components_.empty()) { - next = component->GetNext(); - - if (component->IsEnable()) + for (auto& p : components_) { - component->HandleEvent(evt); + if (p.second->IsEnable()) + { + p.second->HandleEvent(evt); + } } } } diff --git a/src/kiwano/base/component/ComponentManager.h b/src/kiwano/base/component/ComponentManager.h index 469e7eaa..6f3c6b70 100644 --- a/src/kiwano/base/component/ComponentManager.h +++ b/src/kiwano/base/component/ComponentManager.h @@ -31,8 +31,8 @@ namespace kiwano */ /// \~chinese -/// @brief 组件列表 -typedef IntrusiveList ComponentList; +/// @brief 组件映射 +typedef UnorderedMap ComponentMap; /** * \~chinese @@ -47,12 +47,20 @@ public: Component* AddComponent(ComponentPtr component); /// \~chinese - /// @brief 获取所有组件 - ComponentList& GetAllComponents(); + /// @brief 获取组件 + Component* GetComponent(const String& name); + + /// \~chinese + /// @brief 获取组件 + Component* GetComponent(size_t name_hash); /// \~chinese /// @brief 获取所有组件 - const ComponentList& GetAllComponents() const; + ComponentMap& GetAllComponents(); + + /// \~chinese + /// @brief 获取所有组件 + const ComponentMap& GetAllComponents() const; /// \~chinese /// @brief 移除组件 @@ -61,7 +69,12 @@ public: /// \~chinese /// @brief 移除组件 /// @param name 组件名称 - void RemoveComponents(const String& name); + void RemoveComponent(const String& name); + + /// \~chinese + /// @brief 移除组件 + /// @param name_hash 组件名称hash值 + void RemoveComponent(size_t name_hash); /// \~chinese /// @brief 移除所有组件 @@ -83,8 +96,8 @@ protected: ComponentManager(Actor* target); private: - Actor* target_; - ComponentList components_; + Actor* target_; + ComponentMap components_; }; /** @} */ From b90642fd15780b1139da50c8145b6e4ed36100ca Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 19:05:46 +0800 Subject: [PATCH 10/11] update ComponentManager --- src/kiwano/base/component/ComponentManager.cpp | 15 +++++++++++++-- src/kiwano/base/component/ComponentManager.h | 6 ++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/kiwano/base/component/ComponentManager.cpp b/src/kiwano/base/component/ComponentManager.cpp index 5a77ec6b..a0d3dbb7 100644 --- a/src/kiwano/base/component/ComponentManager.cpp +++ b/src/kiwano/base/component/ComponentManager.cpp @@ -33,12 +33,23 @@ Component* ComponentManager::AddComponent(ComponentPtr component) { KGE_ASSERT(component && "AddComponent failed, NULL pointer exception"); + if (component) + { + size_t hash = std::hash{}(component->GetName()); + AddComponent(hash, component); + } + return component.Get(); +} + +Component* ComponentManager::AddComponent(size_t index, ComponentPtr component) +{ + KGE_ASSERT(component && "AddComponent failed, NULL pointer exception"); + if (component) { component->InitComponent(target_); - size_t hash = std::hash{}(component->GetName()); - components_.insert(std::make_pair(hash, component)); + components_.insert(std::make_pair(index, component)); } return component.Get(); } diff --git a/src/kiwano/base/component/ComponentManager.h b/src/kiwano/base/component/ComponentManager.h index 6f3c6b70..139a2832 100644 --- a/src/kiwano/base/component/ComponentManager.h +++ b/src/kiwano/base/component/ComponentManager.h @@ -46,6 +46,12 @@ public: /// @param component 组件 Component* AddComponent(ComponentPtr component); + /// \~chinese + /// @brief 添加组件 + /// @param index 索引值 + /// @param component 组件 + Component* AddComponent(size_t index, ComponentPtr component); + /// \~chinese /// @brief 获取组件 Component* GetComponent(const String& name); From a224a6361aa0274d0686565ffec691a3627ce43e Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 21 Jun 2020 20:38:21 +0800 Subject: [PATCH 11/11] add Actor::SetEventDispatchEnabled() --- src/kiwano/2d/Actor.cpp | 8 +++++++- src/kiwano/2d/Actor.h | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index f206e223..62324ee1 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -59,6 +59,7 @@ Actor::Actor() , cascade_opacity_(false) , show_border_(false) , is_fast_transform_(true) + , evt_dispatch_enabled_(true) , parent_(nullptr) , stage_(nullptr) , hash_name_(0) @@ -191,7 +192,7 @@ bool Actor::CheckVisibility(RenderContext& ctx) const bool Actor::DispatchEvent(Event* evt) { - if (!visible_) + if (!visible_ || !evt_dispatch_enabled_) return true; // Dispatch to children those are greater than 0 in Z-Order @@ -220,6 +221,11 @@ bool Actor::DispatchEvent(Event* evt) return true; } +void Actor::SetEventDispatchEnabled(bool enabled) +{ + evt_dispatch_enabled_ = enabled; +} + void Actor::DoSerialize(Serializer* serializer) const { ObjectBase::DoSerialize(serializer); diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index c9da9662..1af54468 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -105,6 +105,10 @@ public: /// @brief 是否启用级联透明度 bool IsCascadeOpacityEnabled() const; + /// \~chinese + /// @brief 是否启用事件分发 + bool IsEventDispatchEnabled() const; + /// \~chinese /// @brief 获取名称的 Hash 值 size_t GetHashName() const; @@ -408,6 +412,11 @@ public: /// @return 是否继续分发该事件 virtual bool DispatchEvent(Event* evt); + /// \~chinese + /// @brief 开启或关闭事件分发功能 + /// @param enabled 是否开启 + void SetEventDispatchEnabled(bool enabled); + /// \~chinese /// @brief 序列化 void DoSerialize(Serializer* serializer) const override; @@ -469,6 +478,7 @@ private: bool hover_; bool pressed_; bool responsible_; + bool evt_dispatch_enabled_; int z_order_; float opacity_; float displayed_opacity_; @@ -518,6 +528,11 @@ inline bool Actor::IsCascadeOpacityEnabled() const return cascade_opacity_; } +inline bool Actor::IsEventDispatchEnabled() const +{ + return evt_dispatch_enabled_; +} + inline size_t Actor::GetHashName() const { return hash_name_;