From 93e97c60c2cd0bb67350679e22be37a8de27e14e Mon Sep 17 00:00:00 2001 From: Nomango Date: Fri, 14 Feb 2020 17:12:13 +0800 Subject: [PATCH] Add Runner --- projects/kiwano/kiwano.vcxproj | 1 + projects/kiwano/kiwano.vcxproj.filters | 3 + src/kiwano-network/HttpClient.cpp | 2 +- src/kiwano/core/AsyncTask.cpp | 2 +- src/kiwano/core/Runner.h | 94 ++++++++++++++++++++++++ src/kiwano/platform/Application.cpp | 59 +++++++-------- src/kiwano/platform/Application.h | 36 +++------ src/kiwano/platform/Window.cpp | 5 ++ src/kiwano/platform/Window.h | 7 +- src/kiwano/platform/win32/WindowImpl.cpp | 68 +++++++++-------- src/kiwano/platform/win32/WindowImpl.h | 4 +- 11 files changed, 193 insertions(+), 88 deletions(-) create mode 100644 src/kiwano/core/Runner.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index 55aa2264..ddad3882 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -22,6 +22,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 5eeb04db..f1c594c4 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -300,6 +300,9 @@ render + + core + diff --git a/src/kiwano-network/HttpClient.cpp b/src/kiwano-network/HttpClient.cpp index 06b82aaf..fb2a1b59 100644 --- a/src/kiwano-network/HttpClient.cpp +++ b/src/kiwano-network/HttpClient.cpp @@ -235,7 +235,7 @@ void HttpClient::NetworkThread() response_queue_.push(response); response_mutex_.unlock(); - Application::PreformInMainThread(Closure(this, &HttpClient::DispatchResponseCallback)); + Application::GetInstance().PreformInMainThread(Closure(this, &HttpClient::DispatchResponseCallback)); } } diff --git a/src/kiwano/core/AsyncTask.cpp b/src/kiwano/core/AsyncTask.cpp index cd0fc277..b144cd9a 100644 --- a/src/kiwano/core/AsyncTask.cpp +++ b/src/kiwano/core/AsyncTask.cpp @@ -77,7 +77,7 @@ void AsyncTask::TaskThread() func_mutex_.unlock(); } - Application::PreformInMainThread(Closure(this, &AsyncTask::Complete)); + Application::GetInstance().PreformInMainThread(Closure(this, &AsyncTask::Complete)); } void AsyncTask::Complete() diff --git a/src/kiwano/core/Runner.h b/src/kiwano/core/Runner.h new file mode 100644 index 00000000..6752b5b9 --- /dev/null +++ b/src/kiwano/core/Runner.h @@ -0,0 +1,94 @@ +// 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 +{ +/** + * \~chinese + * @brief 程序运行器 + */ +class KGE_API Runner +{ +public: + typedef Function Callback; + + Runner(); + + /// \~chinese + /// @brief 构造程序运行器 + /// @param on_ready 应用程序初始化完成后执行的回调函数 + /// @param on_destroy 应用程序销毁时执行的回调函数 + Runner(const Callback& on_ready, const Callback& on_destroy = nullptr); + + /// \~chinese + /// @brief 初始化完成处理 + /// @details 重载该函数以在应用程序初始化完成后自动执行 + virtual void OnReady(); + + /// \~chinese + /// @brief 应用程序销毁处理 + /// @details 重载该函数以处理应用程序销毁时的行为,如完成资源回收等 + virtual void OnDestroy(); + + /// \~chinese + /// @brief 窗口关闭处理 + /// @details 重载该函数以处理用户关闭窗口时的行为,如保存用户数据等 + /// @return 返回true允许用户关闭窗口,否则阻止窗口关闭 + virtual bool OnClosing(); + +private: + Callback on_ready_; + Callback on_destroy_; +}; + + +inline Runner::Runner() {} + +inline Runner::Runner(const Callback& on_ready, const Callback& on_destroy) + : on_ready_(on_ready) + , on_destroy_(on_destroy) +{ +} + +inline void Runner::OnReady() +{ + if (on_ready_) + { + on_ready_(); + } +} + +inline void Runner::OnDestroy() +{ + if (on_destroy_) + { + on_destroy_(); + } +} + +inline bool Runner::OnClosing() +{ + return true; +} + +} // namespace kiwano diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index a4df6961..91dd7a81 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -18,40 +18,28 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include -#include #include #include +#include +#include #include #include -#include namespace kiwano { -namespace -{ - -using FunctionToPerform = Function; - -std::mutex perform_mutex_; -Queue functions_to_perform_; - -} // namespace Application::Application() - : time_scale_(1.f) + : quiting_(false) + , time_scale_(1.f) { Use(&Renderer::GetInstance()); Use(&Input::GetInstance()); Use(&Director::GetInstance()); } -Application::~Application() -{ - Destroy(); -} +Application::~Application() {} -void Application::Run(bool debug) +void Application::Run(Runner& runner, bool debug) { // Setup all components for (auto c : comps_) @@ -66,26 +54,43 @@ void Application::Run(bool debug) } // Everything is ready - OnReady(); + runner.OnReady(); + // Initialize variables + quiting_ = false; last_update_time_ = Time::Now(); Window& window = Window::GetInstance(); - while (!window.ShouldClose()) + while (!quiting_) { - while (EventPtr evt = window.PollEvent()) + if (window.ShouldClose()) { - DispatchEvent(evt.get()); + if (runner.OnClosing()) + break; + else + window.SetShouldClose(false); } - Update(); - Render(); + while (EventPtr evt = window.PollEvent()) + { + this->DispatchEvent(evt.get()); + } + + this->Update(); + this->Render(); } + + // Destroy all resources + runner.OnDestroy(); + this->Destroy(); + + // Destroy window + window.Destroy(); } void Application::Quit() { - Window::GetInstance().Destroy(); + quiting_ = true; } void Application::Destroy() @@ -99,10 +104,6 @@ void Application::Destroy() { (*iter)->DestroyComponent(); } - render_comps_.clear(); - update_comps_.clear(); - event_comps_.clear(); - comps_.clear(); } void Application::Use(ComponentBase* component) diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index d61e8285..36e36fad 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -19,13 +19,13 @@ // THE SOFTWARE. #pragma once +#include #include #include #include +#include +#include #include -#include -#include -#include #include #include @@ -35,35 +35,23 @@ namespace kiwano * \~chinese * @brief 应用程序,控制游戏的整个生命周期,包括初始化、启动、结束以及事件分发等 */ -class KGE_API Application : protected Noncopyable +class KGE_API Application : public Singleton { + friend Singleton; + public: Application(); virtual ~Application(); - /** - * \~chinese - * @brief 初始化完成处理 - * @details 重载该函数以在应用程序初始化完成后自动执行 - */ - virtual void OnReady(); - - /** - * \~chinese - * @brief 应用程序销毁处理 - * @details 重载该函数以处理应用程序销毁时的行为,如完成资源回收等 - */ - virtual void OnDestroy(); - /** * \~chinese * @brief 启动应用程序 - * @details 初始化所有功能组件后执行 OnReady 函数 + * @param[in] runner 程序运行器 * @param debug 是否启用调试模式 * @note 该函数是阻塞的,应用程序结束时函数返回 */ - void Run(bool debug = false); + void Run(Runner& runner, bool debug = false); /** * \~chinese @@ -107,7 +95,7 @@ public: * @details 提供在其他线程调用 Kiwano 函数的能力 * @param func 需要执行的函数 */ - static void PreformInMainThread(Function func); + void PreformInMainThread(Function func); private: /** @@ -123,15 +111,15 @@ private: void Render(); private: + bool quiting_; float time_scale_; Time last_update_time_; Vector comps_; Vector render_comps_; Vector update_comps_; Vector event_comps_; + std::mutex perform_mutex_; + Queue> functions_to_perform_; }; -inline void Application::OnReady() {} - -inline void Application::OnDestroy() {} } // namespace kiwano diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index 6e005868..01dd6820 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -70,6 +70,11 @@ bool Window::ShouldClose() return should_close_; } +void Window::SetShouldClose(bool should) +{ + should_close_ = should; +} + void Window::PushEvent(EventPtr evt) { event_queue_.push(evt); diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index e0365967..efcca5f6 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -21,7 +21,6 @@ #pragma once #include #include -#include #include namespace kiwano @@ -158,6 +157,12 @@ public: */ bool ShouldClose(); + /** + * \~chinese + * @brief 设置是否需要关闭 + */ + void SetShouldClose(bool should); + /** * \~chinese * @brief 销毁窗口 diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index 9fb74a68..12c38bee 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -166,7 +166,7 @@ void WindowImpl::Create(String const& title, uint32_t width, uint32_t height, ui wcex.cbSize = sizeof(WNDCLASSEX); wcex.lpszClassName = L"KiwanoAppWnd"; wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */; - wcex.lpfnWndProc = WindowImpl::WndProc; + wcex.lpfnWndProc = WindowImpl::StaticWndProc; wcex.hIcon = nullptr; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); @@ -437,25 +437,19 @@ void WindowImpl::SetActive(bool actived) } } -LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) +LRESULT WindowImpl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) { - WindowImpl* window = reinterpret_cast(static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA))); - if (window == nullptr) - { - return ::DefWindowProcW(hwnd, msg, wparam, lparam); - } - switch (msg) { case WM_KEYDOWN: case WM_SYSKEYDOWN: { - KeyCode key = window->key_map_[size_t(wparam)]; + KeyCode key = this->key_map_[size_t(wparam)]; if (key != KeyCode::Unknown) { KeyDownEventPtr evt = new KeyDownEvent; evt->code = key; - window->PushEvent(evt); + this->PushEvent(evt); } } break; @@ -463,12 +457,12 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_KEYUP: case WM_SYSKEYUP: { - KeyCode key = window->key_map_[size_t(wparam)]; + KeyCode key = this->key_map_[size_t(wparam)]; if (key != KeyCode::Unknown) { KeyUpEventPtr evt = new KeyUpEvent; evt->code = key; - window->PushEvent(evt); + this->PushEvent(evt); } } break; @@ -477,7 +471,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { KeyCharEventPtr evt = new KeyCharEvent; evt->value = char(wparam); - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -504,7 +498,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA evt->button = MouseButton::Middle; } - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -528,7 +522,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA evt->button = MouseButton::Middle; } - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -536,7 +530,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { MouseMoveEventPtr evt = new MouseMoveEvent; evt->pos = Point((float)GET_X_LPARAM(lparam), (float)GET_Y_LPARAM(lparam)); - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -545,7 +539,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA MouseWheelEventPtr evt = new MouseWheelEvent; evt->pos = Point((float)GET_X_LPARAM(lparam), (float)GET_Y_LPARAM(lparam)); evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA; - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -559,13 +553,13 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { // KGE_SYS_LOG("Window resized"); - window->width_ = ((uint32_t)(short)LOWORD(lparam)); - window->height_ = ((uint32_t)(short)HIWORD(lparam)); + this->width_ = ((uint32_t)(short)LOWORD(lparam)); + this->height_ = ((uint32_t)(short)HIWORD(lparam)); WindowResizedEventPtr evt = new WindowResizedEvent; - evt->width = window->GetWidth(); - evt->height = window->GetHeight(); - window->PushEvent(evt); + evt->width = this->GetWidth(); + evt->height = this->GetHeight(); + this->PushEvent(evt); } } break; @@ -575,7 +569,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA WindowMovedEventPtr evt = new WindowMovedEvent; evt->x = GET_X_LPARAM(lparam); evt->y = GET_Y_LPARAM(lparam); - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -583,11 +577,11 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { bool active = (LOWORD(wparam) != WA_INACTIVE); - window->SetActive(active); + this->SetActive(active); WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent; evt->focus = active; - window->PushEvent(evt); + this->PushEvent(evt); } break; @@ -595,11 +589,11 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA { KGE_SYS_LOG("Window title changed"); - window->title_ = WideToMultiByte(reinterpret_cast(lparam)); + this->title_ = WideToMultiByte(reinterpret_cast(lparam)); WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent; - evt->title = window->title_; - window->PushEvent(evt); + evt->title = this->title_; + this->PushEvent(evt); } break; @@ -619,7 +613,7 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA case WM_SETCURSOR: { - window->UpdateCursor(); + this->UpdateCursor(); } break; @@ -628,8 +622,9 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA KGE_SYS_LOG("Window is closing"); WindowClosedEventPtr evt = new WindowClosedEvent; - window->PushEvent(evt); - window->Destroy(); + this->PushEvent(evt); + this->SetShouldClose(true); + return 0; } break; @@ -646,6 +641,17 @@ LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA return ::DefWindowProcW(hwnd, msg, wparam, lparam); } +LRESULT CALLBACK WindowImpl::StaticWndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) +{ + LONG_PTR ptr = static_cast(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)); + if (ptr) + { + WindowImpl* window = reinterpret_cast(ptr); + return window->MessageProc(hwnd, msg, wparam, lparam); + } + return ::DefWindowProcW(hwnd, msg, wparam, lparam); +} + } // namespace kiwano #endif diff --git a/src/kiwano/platform/win32/WindowImpl.h b/src/kiwano/platform/win32/WindowImpl.h index c67f87a4..65fff529 100644 --- a/src/kiwano/platform/win32/WindowImpl.h +++ b/src/kiwano/platform/win32/WindowImpl.h @@ -62,7 +62,9 @@ private: void SetActive(bool actived); - static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM); + LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM); + + static LRESULT CALLBACK StaticWndProc(HWND, UINT32, WPARAM, LPARAM); private: bool resizable_;