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