From bcc92abbef8ccc6f8e20984bd2a080356f738082 Mon Sep 17 00:00:00 2001 From: Nomango Date: Fri, 17 Jan 2020 11:24:24 +0800 Subject: [PATCH] Add WindowImpl-Win32 --- projects/kiwano/kiwano.vcxproj | 2 + projects/kiwano/kiwano.vcxproj.filters | 6 + src/kiwano-audio/Sound.cpp | 8 +- src/kiwano-imgui/ImGuiModule.cpp | 18 +- src/kiwano/2d/Button.cpp | 4 +- src/kiwano/2d/Canvas.cpp | 2 +- src/kiwano/2d/DebugActor.cpp | 4 +- src/kiwano/2d/Frame.cpp | 4 +- src/kiwano/2d/GifSprite.cpp | 6 +- src/kiwano/2d/Stage.cpp | 2 +- src/kiwano/2d/Transition.cpp | 2 +- src/kiwano/core/Logger.cpp | 22 +- src/kiwano/core/Logger.h | 10 +- src/kiwano/core/Singleton.h | 61 +++ src/kiwano/core/common.h | 6 +- src/kiwano/platform/Application.cpp | 51 +- src/kiwano/platform/Application.h | 65 +-- src/kiwano/platform/Window.cpp | 569 +------------------- src/kiwano/platform/Window.h | 74 +-- src/kiwano/platform/win32/WindowImpl.cpp | 632 +++++++++++++++++++++++ src/kiwano/renderer/Brush.cpp | 6 +- src/kiwano/renderer/Font.cpp | 4 +- src/kiwano/renderer/Geometry.cpp | 10 +- src/kiwano/renderer/GeometrySink.cpp | 2 +- src/kiwano/renderer/GifImage.cpp | 6 +- src/kiwano/renderer/Renderer.cpp | 27 +- src/kiwano/renderer/Renderer.h | 17 - src/kiwano/renderer/StrokeStyle.cpp | 2 +- src/kiwano/renderer/TextLayout.cpp | 4 +- src/kiwano/renderer/Texture.cpp | 4 +- src/kiwano/utils/ResourceCache.cpp | 8 +- 31 files changed, 872 insertions(+), 766 deletions(-) create mode 100644 src/kiwano/core/Singleton.h create mode 100644 src/kiwano/platform/win32/WindowImpl.cpp diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index 1a09e2d1..5de1b87d 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -20,6 +20,7 @@ + @@ -131,6 +132,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 134c91ce..0aad2c21 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -282,6 +282,9 @@ core + + core + @@ -479,5 +482,8 @@ core + + platform\win32 + \ No newline at end of file diff --git a/src/kiwano-audio/Sound.cpp b/src/kiwano-audio/Sound.cpp index be9bcdc2..88e6d056 100644 --- a/src/kiwano-audio/Sound.cpp +++ b/src/kiwano-audio/Sound.cpp @@ -42,7 +42,7 @@ namespace kiwano bool Sound::Load(String const& file_path) { - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_WARN(L"Media file '%s' not found", file_path.c_str()); return false; @@ -53,7 +53,7 @@ namespace kiwano Close(); } - String full_path = FileSystem::instance().GetFullPathForFile(file_path); + String full_path = FileSystem::Instance().GetFullPathForFile(file_path); HRESULT hr = transcoder_.LoadMediaFile(full_path); if (FAILED(hr)) @@ -62,7 +62,7 @@ namespace kiwano return false; } - if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) + if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer())) { Close(); return false; @@ -86,7 +86,7 @@ namespace kiwano return false; } - if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) + if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer())) { Close(); return false; diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp index ac7ed61c..53a96b4b 100644 --- a/src/kiwano-imgui/ImGuiModule.cpp +++ b/src/kiwano-imgui/ImGuiModule.cpp @@ -29,7 +29,7 @@ namespace kiwano ImGui::StyleColorsDark(); // Setup Platform/Renderer bindings - target_window_ = Renderer::instance().GetTargetWindow(); + target_window_ = Renderer::Instance().GetTargetWindow(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) @@ -54,7 +54,7 @@ namespace kiwano io.KeyMap[ImGuiKey_Y] = KeyCode::Y; io.KeyMap[ImGuiKey_Z] = KeyCode::Z; - ImGui_Impl_Init(Renderer::instance()); + ImGui_Impl_Init(Renderer::Instance()); } void ImGuiModule::DestroyComponent() @@ -71,10 +71,10 @@ namespace kiwano io.DeltaTime = dt.Seconds(); // Read keyboard modifiers inputs - io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl); - io.KeyShift = Input::instance().IsDown(KeyCode::Shift); - io.KeyAlt = Input::instance().IsDown(KeyCode::Alt); - io.KeySuper = Input::instance().IsDown(KeyCode::Super); + io.KeyCtrl = Input::Instance().IsDown(KeyCode::Ctrl); + io.KeyShift = Input::Instance().IsDown(KeyCode::Shift); + io.KeyAlt = Input::Instance().IsDown(KeyCode::Alt); + io.KeySuper = Input::Instance().IsDown(KeyCode::Super); // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the HandleEvent function below. // Update OS mouse position @@ -155,7 +155,7 @@ namespace kiwano KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); // Setup display size (every frame to accommodate for window resizing) - Size display_size = Renderer::instance().GetOutputSize(); + Size display_size = Renderer::Instance().GetOutputSize(); io.DisplaySize = ImVec2(display_size.x, display_size.y); ImGui::NewFrame(); @@ -180,7 +180,7 @@ namespace kiwano ::SetCursorPos(pos.x, pos.y); } - Point pos = Input::instance().GetMousePos(); + Point pos = Input::Instance().GetMousePos(); io.MousePos = ImVec2(pos.x, pos.y); } @@ -202,7 +202,7 @@ namespace kiwano case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break; } - Window::instance().SetCursor(cursor); + Window::Instance().SetCursor(cursor); } } diff --git a/src/kiwano/2d/Button.cpp b/src/kiwano/2d/Button.cpp index a7b3a263..1e2d04c6 100644 --- a/src/kiwano/2d/Button.cpp +++ b/src/kiwano/2d/Button.cpp @@ -95,14 +95,14 @@ namespace kiwano if (status == Status::Normal) { - Window::instance().SetCursor(CursorType::Arrow); + Window::Instance().SetCursor(CursorType::Arrow); if (mouse_out_callback_) mouse_out_callback_(this); } else if (status == Status::Hover) { - Window::instance().SetCursor(CursorType::Hand); + Window::Instance().SetCursor(CursorType::Hand); if (old_status == Status::Pressed) { diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index 09a6bfb2..20d06830 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -318,7 +318,7 @@ namespace kiwano { if (!ctx_) { - Renderer::instance().CreateTextureRenderTarget(ctx_); + Renderer::Instance().CreateTextureRenderTarget(ctx_); } if (!stroke_brush_) diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index b4e7dbd6..7174d952 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -106,9 +106,9 @@ namespace kiwano } #endif - ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; + ss << "Render: " << Renderer::Instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; - ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl; + ss << "Primitives / sec: " << std::fixed << Renderer::Instance().GetStatus().primitives * frame_time_.size() << std::endl; ss << "Memory: "; { diff --git a/src/kiwano/2d/Frame.cpp b/src/kiwano/2d/Frame.cpp index babe077c..f20419c9 100644 --- a/src/kiwano/2d/Frame.cpp +++ b/src/kiwano/2d/Frame.cpp @@ -29,7 +29,7 @@ namespace kiwano bool Frame::Load(String const& file_path) { - TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path); + TexturePtr texture = TextureCache::Instance().AddOrGetTexture(file_path); if (texture->IsValid()) { SetTexture(texture); @@ -40,7 +40,7 @@ namespace kiwano bool Frame::Load(Resource const& res) { - TexturePtr texture = TextureCache::instance().AddOrGetTexture(res); + TexturePtr texture = TextureCache::Instance().AddOrGetTexture(res); if (texture->IsValid()) { SetTexture(texture); diff --git a/src/kiwano/2d/GifSprite.cpp b/src/kiwano/2d/GifSprite.cpp index e0cd31cd..b343d143 100644 --- a/src/kiwano/2d/GifSprite.cpp +++ b/src/kiwano/2d/GifSprite.cpp @@ -34,13 +34,13 @@ namespace kiwano bool GifSprite::Load(String const& file_path) { - GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path); + GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(file_path); return Load(image); } bool GifSprite::Load(Resource const& res) { - GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res); + GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(res); return Load(image); } @@ -58,7 +58,7 @@ namespace kiwano if (!frame_rt_) { - Renderer::instance().CreateTextureRenderTarget(frame_rt_); + Renderer::Instance().CreateTextureRenderTarget(frame_rt_); } if (gif_->GetFramesCount() > 0) diff --git a/src/kiwano/2d/Stage.cpp b/src/kiwano/2d/Stage.cpp index a880df93..6a6eedf7 100644 --- a/src/kiwano/2d/Stage.cpp +++ b/src/kiwano/2d/Stage.cpp @@ -29,7 +29,7 @@ namespace kiwano SetStage(this); SetAnchor(Vec2{ 0, 0 }); - SetSize(Renderer::instance().GetOutputSize()); + SetSize(Renderer::Instance().GetOutputSize()); } Stage::~Stage() diff --git a/src/kiwano/2d/Transition.cpp b/src/kiwano/2d/Transition.cpp index 5ba2411c..a25822d4 100644 --- a/src/kiwano/2d/Transition.cpp +++ b/src/kiwano/2d/Transition.cpp @@ -60,7 +60,7 @@ namespace kiwano out_stage_ = prev; in_stage_ = next; - window_size_ = Renderer::instance().GetOutputSize(); + window_size_ = Renderer::Instance().GetOutputSize(); if (in_stage_) { diff --git a/src/kiwano/core/Logger.cpp b/src/kiwano/core/Logger.cpp index 624e1276..608136f3 100644 --- a/src/kiwano/core/Logger.cpp +++ b/src/kiwano/core/Logger.cpp @@ -26,52 +26,66 @@ namespace { - std::streambuf* cout_buffer, * cerr_buffer; - std::fstream console_output, console_error; + std::streambuf* cin_buffer, * cout_buffer, * cerr_buffer; + std::fstream console_input, console_output, console_error; - std::wstreambuf* wcout_buffer, * wcerr_buffer; - std::wfstream wconsole_output, wconsole_error; + std::wstreambuf* wcin_buffer, * wcout_buffer, * wcerr_buffer; + std::wfstream wconsole_input, wconsole_output, wconsole_error; void RedirectStdIO() { + cin_buffer = std::cin.rdbuf(); cout_buffer = std::cout.rdbuf(); cerr_buffer = std::cerr.rdbuf(); + wcin_buffer = std::wcin.rdbuf(); wcout_buffer = std::wcout.rdbuf(); wcerr_buffer = std::wcerr.rdbuf(); + console_input.open("CONIN$", std::ios::in); console_output.open("CONOUT$", std::ios::out); console_error.open("CONOUT$", std::ios::out); + wconsole_input.open("CONIN$", std::ios::in); wconsole_output.open("CONOUT$", std::ios::out); wconsole_error.open("CONOUT$", std::ios::out); FILE* dummy; freopen_s(&dummy, "CONOUT$", "w+t", stdout); + freopen_s(&dummy, "CONIN$", "r+t", stdin); freopen_s(&dummy, "CONOUT$", "w+t", stderr); (void)dummy; + std::cin.rdbuf(console_input.rdbuf()); std::cout.rdbuf(console_output.rdbuf()); std::cerr.rdbuf(console_error.rdbuf()); + std::wcin.rdbuf(wconsole_input.rdbuf()); std::wcout.rdbuf(wconsole_output.rdbuf()); std::wcerr.rdbuf(wconsole_error.rdbuf()); } void ResetStdIO() { + console_input.close(); console_output.close(); console_error.close(); + wconsole_input.close(); wconsole_output.close(); wconsole_error.close(); + std::cin.rdbuf(cin_buffer); std::cout.rdbuf(cout_buffer); std::cerr.rdbuf(cerr_buffer); + std::wcin.rdbuf(wcin_buffer); std::wcout.rdbuf(wcout_buffer); std::wcerr.rdbuf(wcerr_buffer); fclose(stdout); + fclose(stdin); fclose(stderr); + cin_buffer = nullptr; cout_buffer = nullptr; cerr_buffer = nullptr; + wcin_buffer = nullptr; wcout_buffer = nullptr; wcerr_buffer = nullptr; } diff --git a/src/kiwano/core/Logger.h b/src/kiwano/core/Logger.h index 99b59364..3aedd7ec 100644 --- a/src/kiwano/core/Logger.h +++ b/src/kiwano/core/Logger.h @@ -26,26 +26,26 @@ #ifndef KGE_SYS_LOG # ifdef KGE_DEBUG -# define KGE_SYS_LOG(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__) +# define KGE_SYS_LOG(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__) # else # define KGE_SYS_LOG __noop # endif #endif #ifndef KGE_WARN -# define KGE_WARN(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__) +# define KGE_WARN(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__) #endif #ifndef KGE_ERROR -# define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__) +# define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__) #endif #ifndef KGE_LOG -# define KGE_LOG(...) ::kiwano::Logger::instance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__) +# define KGE_LOG(...) ::kiwano::Logger::Instance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__) #endif #ifndef KGE_LOGF -# define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__) +# define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__) #endif namespace kiwano diff --git a/src/kiwano/core/Singleton.h b/src/kiwano/core/Singleton.h new file mode 100644 index 00000000..ed96c6ba --- /dev/null +++ b/src/kiwano/core/Singleton.h @@ -0,0 +1,61 @@ +// Copyright (c) 2016-2020 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 + +namespace kiwano +{ + +template +struct Singleton +{ +protected: + Singleton() = default; + Singleton(const Singleton&) = delete; + Singleton& operator=(const Singleton&) = delete; + +private: + struct ObjectCreator + { + ObjectCreator() + { + (void)Singleton<_Ty>::Instance(); + } + + inline void Dummy() const {} + }; + static ObjectCreator creator_; + +public: + using object_type = _Ty; + + static inline object_type& Instance() + { + static object_type instance; + creator_.Dummy(); + return instance; + } +}; + +template +typename Singleton<_Ty>::ObjectCreator Singleton<_Ty>::creator_; + + +} // namespace kiwano diff --git a/src/kiwano/core/common.h b/src/kiwano/core/common.h index 7d72c318..88670cee 100644 --- a/src/kiwano/core/common.h +++ b/src/kiwano/core/common.h @@ -30,6 +30,7 @@ #include <3rd-party/OuterC/oc/oc.h> #include +#include namespace kiwano { @@ -113,11 +114,6 @@ namespace kiwano /// @brief JSON对象容器 using Json = oc::basic_json; - /// \~chinese - /// @brief 单例模板 - template - using Singleton = oc::singleton<_Ty>; - /// \~chinese /// @brief 侵入式链表容器 template diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 28b6a485..b32f98ab 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -36,31 +36,12 @@ namespace kiwano Queue functions_to_perform_; } - Config::Config(String const& title, uint32_t width, uint32_t height, uint32_t icon) - : debug(false) - { - window.title = title; - window.width = width; - window.height = height; - window.icon = icon; - } - - Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config) - : debug(false) - { - window = wnd_config; - render = render_config; - } -} - -namespace kiwano -{ Application::Application() : time_scale_(1.f) { - Use(&Renderer::instance()); - Use(&Input::instance()); - Use(&Director::instance()); + Use(&Renderer::Instance()); + Use(&Input::Instance()); + Use(&Director::Instance()); } Application::~Application() @@ -68,21 +49,18 @@ namespace kiwano Destroy(); } - void Application::Run(const Config& config) + void Application::Run(bool debug) { - Window::instance().Init(config.window); - Renderer::instance().Init(config.render); - // Setup all components for (auto c : comps_) { c->SetupComponent(); } - if (config.debug) + if (debug) { - Director::instance().ShowDebugInfo(true); - Renderer::instance().SetCollectingStatus(true); + Director::Instance().ShowDebugInfo(true); + Renderer::Instance().SetCollectingStatus(true); } // Everything is ready @@ -90,7 +68,7 @@ namespace kiwano last_update_time_ = Time::Now(); - Window& window = Window::instance(); + Window& window = Window::Instance(); while (!window.ShouldClose()) { while (EventPtr evt = window.PollEvent()) @@ -105,20 +83,23 @@ namespace kiwano void Application::Quit() { - Window::instance().Destroy(); + Window::Instance().Destroy(); } void Application::Destroy() { // Clear all resources - Director::instance().ClearStages(); - ResourceCache::instance().Clear(); - TextureCache::instance().Clear(); + Director::Instance().ClearStages(); + ResourceCache::Instance().Clear(); + TextureCache::Instance().Clear(); for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter) { (*iter)->DestroyComponent(); } + render_comps_.clear(); + update_comps_.clear(); + event_comps_.clear(); comps_.clear(); } @@ -209,7 +190,7 @@ namespace kiwano } // Rendering - Renderer& renderer = Renderer::instance(); + Renderer& renderer = Renderer::Instance(); for (auto c : render_comps_) { c->OnRender(renderer); diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 065c3fbd..8f2151d5 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -31,43 +31,6 @@ namespace kiwano { - /** - * \~chinese - * @brief 应用程序配置 - * @details 启动 Kiwano 应用程序前的初始化选项 - */ - struct Config - { - WindowConfig window; ///< 窗口配置 - RenderConfig render; ///< 渲染配置 - bool debug; ///< 启用调试模式 - - /** - * \~chinese - * @param title 窗口标题 - * @param width 窗口宽度 - * @param height 窗口高度 - * @param icon 窗口图标的资源ID - */ - Config( - String const& title = L"Kiwano Game", - uint32_t width = 640, - uint32_t height = 480, - uint32_t icon = 0 - ); - - /** - * \~chinese - * @param wnd_config 窗口配置 - * @param render_config 渲染配置 - */ - Config( - WindowConfig const& wnd_config, - RenderConfig const& render_config = RenderConfig() - ); - }; - - /** * \~chinese * @brief 应用程序,控制游戏的整个生命周期,包括初始化、启动、结束以及事件分发等 @@ -85,23 +48,23 @@ namespace kiwano * @brief 初始化完成处理 * @details 重载该函数以在应用程序初始化完成后自动执行 */ - virtual void OnReady() {} + virtual void OnReady(); /** * \~chinese * @brief 应用程序销毁处理 * @details 重载该函数以处理应用程序销毁时的行为,如完成资源回收等 */ - virtual void OnDestroy() {} + virtual void OnDestroy(); /** * \~chinese * @brief 启动应用程序 * @details 初始化所有功能组件后执行 OnReady 函数 - * @param config 初始化配置 + * @param debug 是否启用调试模式 * @note 该函数是阻塞的,应用程序结束时函数返回 */ - void Run(Config const& config = Config()); + void Run(bool debug = false); /** * \~chinese @@ -148,10 +111,18 @@ namespace kiwano static void PreformInMainThread(Function func); private: - void Render(); - + /** + * \~chinese + * @brief 更新所有组件 + */ void Update(); + /** + * \~chinese + * @brief 渲染所有组件 + */ + void Render(); + private: float time_scale_; Time last_update_time_; @@ -160,4 +131,12 @@ namespace kiwano Vector update_comps_; Vector event_comps_; }; + + inline void Application::OnReady() + { + } + + inline void Application::OnDestroy() + { + } } diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index a5271f99..2386a43c 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -19,32 +19,9 @@ // THE SOFTWARE. #include -#include -#include -#include -#include -#include - -#include // ImmAssociateContext -#pragma comment(lib, "imm32.lib") - -#define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX -#define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX -#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP -#define KGE_WND_CLASS_NAME L"KiwanoAppWnd" namespace kiwano { - namespace - { - MONITORINFOEX GetMoniterInfoEx(HWND hwnd); - - void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height); - - void ChangeFullScreenResolution(int width, int height, WCHAR* device_name); - - void RestoreResolution(WCHAR* device_name); - } WindowConfig::WindowConfig(String const& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen) : title(title) @@ -57,13 +34,9 @@ namespace kiwano } Window::Window() - : handle_(nullptr) + : should_close_(false) , width_(0) , height_(0) - , device_name_(nullptr) - , is_fullscreen_(false) - , resizable_(false) - , mouse_cursor_(CursorType::Arrow) { } @@ -71,125 +44,9 @@ namespace kiwano { } - void Window::Init(WindowConfig const& config) - { - HINSTANCE hinst = GetModuleHandleW(nullptr); - WNDCLASSEX wcex = { 0 }; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpszClassName = KGE_WND_CLASS_NAME; - wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */; - wcex.lpfnWndProc = Window::WndProc; - wcex.hIcon = nullptr; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = sizeof(LONG_PTR); - wcex.hInstance = hinst; - wcex.hbrBackground = (HBRUSH)(::GetStockObject(BLACK_BRUSH)); - wcex.lpszMenuName = nullptr; - wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW); - - if (config.icon) - { - wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0, - LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); - } - - ::RegisterClassExW(&wcex); - - // Get the nearest monitor to this window - HMONITOR monitor = ::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - - // Get the target monitor info - MONITORINFOEX monitor_info_ex; - memset(&monitor_info_ex, 0, sizeof(MONITORINFOEX)); - monitor_info_ex.cbSize = sizeof(MONITORINFOEX); - ::GetMonitorInfoW(monitor, &monitor_info_ex); - - // Save the device name - int len = lstrlenW(monitor_info_ex.szDevice); - device_name_ = new wchar_t[len + 1]; - lstrcpyW(device_name_, monitor_info_ex.szDevice); - - uint32_t width = config.width; - uint32_t height = config.height; - int left = -1; - int top = -1; - - resizable_ = config.resizable; - is_fullscreen_ = config.fullscreen; - - if (is_fullscreen_) - { - top = monitor_info_ex.rcMonitor.top; - left = monitor_info_ex.rcMonitor.left; - - if (width > static_cast(monitor_info_ex.rcWork.right - left)) - width = static_cast(monitor_info_ex.rcWork.right - left); - - if (height > static_cast(monitor_info_ex.rcWork.bottom - top)) - height = static_cast(monitor_info_ex.rcWork.bottom - top); - } - else - { - uint32_t screenw = monitor_info_ex.rcWork.right - monitor_info_ex.rcWork.left; - uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top; - - uint32_t win_width, win_height; - AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height); - - left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2; - top = monitor_info_ex.rcWork.top + (screenh - win_height) / 2; - width = win_width; - height = win_height; - } - - handle_ = ::CreateWindowExW( - is_fullscreen_ ? WS_EX_TOPMOST : 0, - KGE_WND_CLASS_NAME, - config.title.c_str(), - GetWindowStyle(), - left, - top, - width, - height, - nullptr, - nullptr, - hinst, - nullptr - ); - - if (handle_ == nullptr) - { - ::UnregisterClass(KGE_WND_CLASS_NAME, hinst); - win32::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); - return; - } - - width_ = width; - height_ = height; - - // disable imm - ::ImmAssociateContext(handle_, nullptr); - - // use Application instance in message loop - ::SetWindowLongPtr(handle_, GWLP_USERDATA, LONG_PTR(this)); - - ::ShowWindow(handle_, SW_SHOWNORMAL); - ::UpdateWindow(handle_); - - if (is_fullscreen_) - { - ChangeFullScreenResolution(width_, height_, device_name_); - } - } - EventPtr Window::PollEvent() { - MSG msg; - while (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) - { - ::TranslateMessage(&msg); - ::DispatchMessageW(&msg); - } + PumpEvents(); EventPtr evt; if (!event_queue_.empty()) @@ -202,135 +59,27 @@ namespace kiwano String Window::GetTitle() const { - if (handle_) - { - wchar_t title[256]; - ::GetWindowTextW(handle_, title, 256); - return title; - } - return String(); - } - - void Window::SetTitle(String const& title) - { - if (handle_) - ::SetWindowTextW(handle_, title.c_str()); + return title_; } Size Window::GetSize() const { - return Size{ - static_cast(width_), - static_cast(height_) - }; + return Size(float(width_), float(height_)); } - float Window::GetWidth() const + uint32_t Window::GetWidth() const { - return static_cast(width_); + return width_; } - float Window::GetHeight() const + uint32_t Window::GetHeight() const { - return static_cast(height_); - } - - void Window::SetIcon(uint32_t icon_resource) - { - if (handle_) - { - HINSTANCE hinstance = GetModuleHandle(nullptr); - HICON icon = (HICON)::LoadImageW( - hinstance, - MAKEINTRESOURCE(icon_resource), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE - ); - - ::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)icon); - ::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)icon); - } - } - - void Window::Resize(int width, int height) - { - if (handle_ && !is_fullscreen_) - { - RECT rc = { 0, 0, int(width), int(height) }; - ::AdjustWindowRect(&rc, GetWindowStyle(), false); - - width = rc.right - rc.left; - height = rc.bottom - rc.top; - ::SetWindowPos(handle_, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - } - } - - void Window::SetFullscreen(bool fullscreen, int width, int height) - { - if (is_fullscreen_ != fullscreen || width != width_ || height != height_) - { - is_fullscreen_ = fullscreen; - - if (is_fullscreen_) - { - // move window to (0, 0) before display switch - ::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, width_, height_, SWP_NOACTIVATE); - - ChangeFullScreenResolution(width, height, device_name_); - - MONITORINFOEX info = GetMoniterInfoEx(handle_); - - ::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle()); - ::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height, SWP_NOACTIVATE); - - width_ = width; - height_ = height; - } - else - { - RestoreResolution(device_name_); - - MONITORINFOEX info = GetMoniterInfoEx(handle_); - - uint32_t screenw = info.rcWork.right - info.rcWork.left; - uint32_t screenh = info.rcWork.bottom - info.rcWork.top; - - uint32_t win_width, win_height; - AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height); - - int left = screenw > win_width ? ((screenw - win_width) / 2) : 0; - int top = screenh > win_height ? ((screenh - win_height) / 2) : 0; - - ::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle()); - ::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, win_width, win_height, SWP_DRAWFRAME | SWP_FRAMECHANGED); - - // Update window rect - RECT rc; - ::GetClientRect(handle_, &rc); - - width_ = static_cast(rc.right - rc.left); - height_ = static_cast(rc.bottom - rc.top); - } - - ::ShowWindow(handle_, SW_SHOWNORMAL); - } - } - - void Window::SetCursor(CursorType cursor) - { - mouse_cursor_ = cursor; - } - - WindowHandle Window::GetHandle() const - { - return handle_; + return height_; } bool Window::ShouldClose() { - return handle_ == nullptr; + return should_close_; } void Window::PushEvent(EventPtr evt) @@ -340,306 +89,12 @@ namespace kiwano void Window::Destroy() { - if (is_fullscreen_) - RestoreResolution(device_name_); - - if (device_name_) + while (!event_queue_.empty()) { - delete[] device_name_; - device_name_ = nullptr; + event_queue_.pop(); } - if (handle_) - { - ::DestroyWindow(handle_); - handle_ = nullptr; - } + should_close_ = true; } -#if defined(KGE_WIN32) - - DWORD Window::GetWindowStyle() const - { - return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); - } - - void Window::UpdateCursor() - { - LPTSTR win32_cursor = IDC_ARROW; - switch (mouse_cursor_) - { - case CursorType::Arrow: win32_cursor = IDC_ARROW; break; - case CursorType::TextInput: win32_cursor = IDC_IBEAM; break; - case CursorType::SizeAll: win32_cursor = IDC_SIZEALL; break; - case CursorType::SizeWE: win32_cursor = IDC_SIZEWE; break; - case CursorType::SizeNS: win32_cursor = IDC_SIZENS; break; - case CursorType::SizeNESW: win32_cursor = IDC_SIZENESW; break; - case CursorType::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; - case CursorType::Hand: win32_cursor = IDC_HAND; break; - } - ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); - } - - void Window::SetActive(bool actived) - { - if (!handle_) - return; - - if (is_fullscreen_) - { - if (actived) - { - ChangeFullScreenResolution(width_, height_, device_name_); - - MONITORINFOEX info = GetMoniterInfoEx(handle_); - ::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width_, height_, SWP_NOACTIVATE); - } - else - { - RestoreResolution(device_name_); - - ::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - ::ShowWindow(handle_, SW_MINIMIZE); - } - } - } - - LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) - { - Window* 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: - { - KeyDownEventPtr evt = new KeyDownEvent; - evt->code = static_cast(wparam); - window->PushEvent(evt); - } - break; - - case WM_KEYUP: - case WM_SYSKEYUP: - { - KeyUpEventPtr evt = new KeyUpEvent; - evt->code = static_cast(wparam); - window->PushEvent(evt); - } - break; - - case WM_CHAR: - { - KeyCharEventPtr evt = new KeyCharEvent; - evt->value = static_cast(wparam); - window->PushEvent(evt); - } - break; - - case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: - case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: - case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: - { - MouseDownEventPtr evt = new MouseDownEvent; - evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); - - if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { evt->button = MouseButton::Left; } - else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { evt->button = MouseButton::Right; } - else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { evt->button = MouseButton::Middle; } - - window->PushEvent(evt); - } - break; - - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - { - MouseUpEventPtr evt = new MouseUpEvent; - evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); - - if (msg == WM_LBUTTONUP) { evt->button = MouseButton::Left; } - else if (msg == WM_RBUTTONUP) { evt->button = MouseButton::Right; } - else if (msg == WM_MBUTTONUP) { evt->button = MouseButton::Middle; } - - window->PushEvent(evt); - } - break; - - case WM_MOUSEMOVE: - { - MouseMoveEventPtr evt = new MouseMoveEvent; - evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); - window->PushEvent(evt); - } - break; - - case WM_MOUSEWHEEL: - { - MouseWheelEventPtr evt = new MouseWheelEvent; - evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); - evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA; - window->PushEvent(evt); - } - break; - - case WM_SIZE: - { - if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) - { - KGE_SYS_LOG(L"Window minimized"); - } - else - { - // KGE_SYS_LOG(L"Window resized"); - - window->width_ = ((uint32_t)(short)LOWORD(lparam)); - window->height_ = ((uint32_t)(short)HIWORD(lparam)); - - WindowResizedEventPtr evt = new WindowResizedEvent; - evt->width = window->width_; - evt->height = window->height_; - window->PushEvent(evt); - } - } - break; - - case WM_MOVE: - { - int x = ((int)(short)LOWORD(lparam)); - int y = ((int)(short)HIWORD(lparam)); - - WindowMovedEventPtr evt = new WindowMovedEvent; - evt->x = x; - evt->y = y; - window->PushEvent(evt); - } - break; - - case WM_ACTIVATE: - { - bool active = (LOWORD(wparam) != WA_INACTIVE); - - window->SetActive(active); - - WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent; - evt->focus = active; - window->PushEvent(evt); - } - break; - - case WM_SETTEXT: - { - KGE_SYS_LOG(L"Window title changed"); - - WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent; - evt->title.assign(reinterpret_cast(lparam)); - window->PushEvent(evt); - } - break; - - case WM_SETICON: - { - KGE_SYS_LOG(L"Window icon changed"); - } - break; - - case WM_DISPLAYCHANGE: - { - KGE_SYS_LOG(L"The display resolution has changed"); - - ::InvalidateRect(hwnd, nullptr, FALSE); - } - break; - - case WM_SETCURSOR: - { - window->UpdateCursor(); - } - break; - - case WM_CLOSE: - { - KGE_SYS_LOG(L"Window is closing"); - - WindowClosedEventPtr evt = new WindowClosedEvent; - window->PushEvent(evt); - window->Destroy(); - } - break; - - case WM_DESTROY: - { - KGE_SYS_LOG(L"Window was destroyed"); - - ::PostQuitMessage(0); - return 0; - } - break; - } - - return ::DefWindowProcW(hwnd, msg, wparam, lparam); - } - - namespace - { - MONITORINFOEX GetMoniterInfoEx(HWND hwnd) - { - HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - MONITORINFOEX monitor_info; - - memset(&monitor_info, 0, sizeof(MONITORINFOEX)); - monitor_info.cbSize = sizeof(MONITORINFOEX); - ::GetMonitorInfoW(monitor, &monitor_info); - - return monitor_info; - } - - void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height) - { - RECT rc; - ::SetRect(&rc, 0, 0, (int)width, (int)height); - ::AdjustWindowRect(&rc, style, false); - - *win_width = rc.right - rc.left; - *win_height = rc.bottom - rc.top; - - MONITORINFOEX info = GetMoniterInfoEx(NULL); - - uint32_t screenw = info.rcWork.right - info.rcWork.left; - uint32_t screenh = info.rcWork.bottom - info.rcWork.top; - - if (*win_width > screenw) - *win_width = screenw; - if (*win_height > screenh) - *win_height = screenh; - } - - void ChangeFullScreenResolution(int width, int height, WCHAR* device_name) - { - DEVMODE mode; - - memset(&mode, 0, sizeof(mode)); - mode.dmSize = sizeof(DEVMODE); - mode.dmBitsPerPel = ::GetDeviceCaps(::GetDC(0), BITSPIXEL);; - mode.dmPelsWidth = width; - mode.dmPelsHeight = height; - mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - - if (::ChangeDisplaySettingsExW(device_name, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) - KGE_ERROR(L"ChangeDisplaySettings failed"); - } - - void RestoreResolution(WCHAR* device_name) - { - ::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); - } - } - -#endif - } diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index 020054b6..c9f3c53e 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -79,23 +79,26 @@ namespace kiwano typedef HWND WindowHandle; #endif - /** * \~chinese * @brief 窗口类,控制窗口标题、大小、图标等 */ class KGE_API Window - : public Singleton + : protected Noncopyable { - friend Singleton; - public: + /** + * \~chinese + * @brief 获取窗口实例 + */ + static Window& Instance(); + /** * \~chinese * @brief 初始化窗口 * @param config 窗口设置 */ - void Init(WindowConfig const& config); + virtual bool Create(WindowConfig const& config) = 0; /** * \~chinese @@ -116,28 +119,34 @@ namespace kiwano * @brief 获取窗口宽度 * @return 窗口宽度 */ - float GetWidth() const; + uint32_t GetWidth() const; /** * \~chinese * @brief 获取窗口高度 * @return 窗口高度 */ - float GetHeight() const; + uint32_t GetHeight() const; + + /** + * \~chinese + * @brief 获取窗口句柄 + */ + virtual WindowHandle GetHandle() const = 0; /** * \~chinese * @brief 设置标题 * @param title 标题 */ - void SetTitle(String const& title); + virtual void SetTitle(String const& title) = 0; /** * \~chinese * @brief 设置窗口图标 * @param icon_resource 图标资源ID */ - void SetIcon(uint32_t icon_resource); + virtual void SetIcon(uint32_t icon_resource) = 0; /** * \~chinese @@ -145,7 +154,7 @@ namespace kiwano * @param width 窗口宽度 * @param height 窗口高度 */ - void Resize(int width, int height); + virtual void Resize(uint32_t width, uint32_t height) = 0; /** * \~chinese @@ -154,14 +163,14 @@ namespace kiwano * @param width 窗口宽度 * @param height 窗口高度 */ - void SetFullscreen(bool fullscreen, int width, int height); + virtual void SetFullscreen(bool fullscreen) = 0; /** * \~chinese * @brief 设置鼠标指针类型 * @param cursor 鼠标指针类型 */ - void SetCursor(CursorType cursor); + virtual void SetCursor(CursorType cursor) = 0; /** * \~chinese @@ -170,49 +179,48 @@ namespace kiwano */ EventPtr PollEvent(); - /** - * \~chinese - * @brief 获取窗口句柄 - */ - WindowHandle GetHandle() const; - /** * \~chinese * @brief 是否需要关闭 */ - bool ShouldClose(); + virtual bool ShouldClose() = 0; /** * \~chinese * @brief 销毁窗口 */ - void Destroy(); + virtual void Destroy(); - private: + protected: Window(); ~Window(); void PushEvent(EventPtr evt); -#if defined(KGE_WIN32) - DWORD GetWindowStyle() const; + void SetInternalSize(uint32_t width, uint32_t height); - void UpdateCursor(); + void SetInternalTitle(String const& title); - void SetActive(bool actived); - - static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM); -#endif + virtual void PumpEvents() = 0; private: - bool resizable_; - bool is_fullscreen_; - WindowHandle handle_; + bool should_close_; uint32_t width_; uint32_t height_; - wchar_t* device_name_; - CursorType mouse_cursor_; + String title_; std::queue event_queue_; }; + + inline void Window::SetInternalSize(uint32_t width, uint32_t height) + { + width_ = width; + height_ = height; + } + + inline void Window::SetInternalTitle(String const& title) + { + title_ = title; + } + } diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp new file mode 100644 index 00000000..7614a0f2 --- /dev/null +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -0,0 +1,632 @@ +// Copyright (c) 2016-2020 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 + +#if defined(KGE_WIN32) + +#include +#include +#include +#include +#include + +#include // ImmAssociateContext +#pragma comment(lib, "imm32.lib") + +#define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX +#define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX +#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP +#define KGE_WND_CLASS_NAME L"KiwanoAppWnd" + +namespace kiwano +{ + namespace win32 + { + namespace + { + MONITORINFOEX GetMoniterInfoEx(HWND hwnd) + { + HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + MONITORINFOEX monitor_info; + + memset(&monitor_info, 0, sizeof(MONITORINFOEX)); + monitor_info.cbSize = sizeof(MONITORINFOEX); + ::GetMonitorInfoW(monitor, &monitor_info); + + return monitor_info; + } + + void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height) + { + RECT rc; + ::SetRect(&rc, 0, 0, (int)width, (int)height); + ::AdjustWindowRect(&rc, style, false); + + *win_width = rc.right - rc.left; + *win_height = rc.bottom - rc.top; + + MONITORINFOEX info = GetMoniterInfoEx(NULL); + + uint32_t screenw = info.rcWork.right - info.rcWork.left; + uint32_t screenh = info.rcWork.bottom - info.rcWork.top; + + if (*win_width > screenw) + *win_width = screenw; + if (*win_height > screenh) + *win_height = screenh; + } + + void ChangeFullScreenResolution(uint32_t width, uint32_t height, WCHAR* device_name) + { + DEVMODE mode; + + memset(&mode, 0, sizeof(mode)); + mode.dmSize = sizeof(DEVMODE); + mode.dmBitsPerPel = ::GetDeviceCaps(::GetDC(0), BITSPIXEL);; + mode.dmPelsWidth = width; + mode.dmPelsHeight = height; + mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + + if (::ChangeDisplaySettingsExW(device_name, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) + KGE_ERROR(L"ChangeDisplaySettings failed"); + } + + void RestoreResolution(WCHAR* device_name) + { + ::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL); + } + } + + class KGE_API WindowImpl + : public kiwano::Window + { + public: + WindowImpl(); + + ~WindowImpl(); + + bool Create(WindowConfig const& config) override; + + WindowHandle GetHandle() const override; + + void SetTitle(String const& title) override; + + void SetIcon(uint32_t icon_resource) override; + + void Resize(uint32_t width, uint32_t height) override; + + void SetFullscreen(bool fullscreen) override; + + void SetCursor(CursorType cursor) override; + + bool ShouldClose() override; + + void Destroy() override; + + private: + void PumpEvents() override; + + DWORD GetWindowStyle() const; + + void UpdateCursor(); + + void SetActive(bool actived); + + static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM); + + private: + bool resizable_; + bool is_fullscreen_; + wchar_t* device_name_; + WindowHandle handle_; + CursorType mouse_cursor_; + }; + + WindowImpl::WindowImpl() + : handle_(nullptr) + , device_name_(nullptr) + , is_fullscreen_(false) + , resizable_(false) + , mouse_cursor_(CursorType::Arrow) + { + } + + WindowImpl::~WindowImpl() + { + } + + bool WindowImpl::Create(WindowConfig const& config) + { + HINSTANCE hinst = GetModuleHandleW(nullptr); + WNDCLASSEX wcex = { 0 }; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpszClassName = KGE_WND_CLASS_NAME; + wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */; + wcex.lpfnWndProc = WindowImpl::WndProc; + wcex.hIcon = nullptr; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = sizeof(LONG_PTR); + wcex.hInstance = hinst; + wcex.hbrBackground = (HBRUSH)(::GetStockObject(BLACK_BRUSH)); + wcex.lpszMenuName = nullptr; + wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW); + + if (config.icon) + { + wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0, + LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + } + + ::RegisterClassExW(&wcex); + + // Get the nearest monitor to this window + HMONITOR monitor = ::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + + // Get the target monitor info + MONITORINFOEX monitor_info_ex; + memset(&monitor_info_ex, 0, sizeof(MONITORINFOEX)); + monitor_info_ex.cbSize = sizeof(MONITORINFOEX); + ::GetMonitorInfoW(monitor, &monitor_info_ex); + + // Save the device name + int len = lstrlenW(monitor_info_ex.szDevice); + device_name_ = new wchar_t[len + 1]; + lstrcpyW(device_name_, monitor_info_ex.szDevice); + + uint32_t width = config.width; + uint32_t height = config.height; + int left = -1; + int top = -1; + + resizable_ = config.resizable; + is_fullscreen_ = config.fullscreen; + + if (is_fullscreen_) + { + top = monitor_info_ex.rcMonitor.top; + left = monitor_info_ex.rcMonitor.left; + + if (width > static_cast(monitor_info_ex.rcWork.right - left)) + width = static_cast(monitor_info_ex.rcWork.right - left); + + if (height > static_cast(monitor_info_ex.rcWork.bottom - top)) + height = static_cast(monitor_info_ex.rcWork.bottom - top); + } + else + { + uint32_t screenw = monitor_info_ex.rcWork.right - monitor_info_ex.rcWork.left; + uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top; + + uint32_t win_width, win_height; + AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height); + + left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2; + top = monitor_info_ex.rcWork.top + (screenh - win_height) / 2; + width = win_width; + height = win_height; + } + + handle_ = ::CreateWindowExW( + is_fullscreen_ ? WS_EX_TOPMOST : 0, + KGE_WND_CLASS_NAME, + config.title.c_str(), + GetWindowStyle(), + left, + top, + width, + height, + nullptr, + nullptr, + hinst, + nullptr + ); + + if (handle_ == nullptr) + { + ::UnregisterClass(KGE_WND_CLASS_NAME, hinst); + KGE_ERROR(L"Failed with HRESULT of %08X", HRESULT_FROM_WIN32(GetLastError())); + return false; + } + + SetInternalSize(width, height); + + // disable imm + ::ImmAssociateContext(handle_, nullptr); + + // use Application instance in message loop + ::SetWindowLongPtr(handle_, GWLP_USERDATA, LONG_PTR(this)); + + ::ShowWindow(handle_, SW_SHOWNORMAL); + ::UpdateWindow(handle_); + + if (is_fullscreen_) + { + ChangeFullScreenResolution(width, height, device_name_); + } + return true; + } + + WindowHandle WindowImpl::GetHandle() const + { + return handle_; + } + + void WindowImpl::PumpEvents() + { + MSG msg; + while (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) + { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + } + + void WindowImpl::SetTitle(String const& title) + { + if (handle_) + ::SetWindowTextW(handle_, title.c_str()); + } + + void WindowImpl::SetIcon(uint32_t icon_resource) + { + if (handle_) + { + HINSTANCE hinstance = GetModuleHandle(nullptr); + HICON icon = (HICON)::LoadImageW( + hinstance, + MAKEINTRESOURCE(icon_resource), + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE + ); + + ::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)icon); + ::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)icon); + } + } + + void WindowImpl::Resize(uint32_t width, uint32_t height) + { + if (handle_ && !is_fullscreen_) + { + RECT rc = { 0, 0, LONG(width), LONG(height) }; + ::AdjustWindowRect(&rc, GetWindowStyle(), false); + + width = rc.right - rc.left; + height = rc.bottom - rc.top; + ::SetWindowPos(handle_, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + void WindowImpl::SetFullscreen(bool fullscreen) + { + if (is_fullscreen_ != fullscreen) + { + is_fullscreen_ = fullscreen; + + uint32_t width = GetWidth(); + uint32_t height = GetHeight(); + + if (is_fullscreen_) + { + // move window to (0, 0) before display switch + ::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, width, height, SWP_NOACTIVATE); + + ChangeFullScreenResolution(width, height, device_name_); + + MONITORINFOEX info = GetMoniterInfoEx(handle_); + + ::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle()); + ::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height, SWP_NOACTIVATE); + } + else + { + RestoreResolution(device_name_); + + MONITORINFOEX 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; + + ::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle()); + ::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, width, height, SWP_DRAWFRAME | SWP_FRAMECHANGED); + } + + ::ShowWindow(handle_, SW_SHOWNORMAL); + } + } + + void WindowImpl::SetCursor(CursorType cursor) + { + mouse_cursor_ = cursor; + } + + bool WindowImpl::ShouldClose() + { + return handle_ == nullptr; + } + + void WindowImpl::Destroy() + { + if (is_fullscreen_) + RestoreResolution(device_name_); + + if (device_name_) + { + delete[] device_name_; + device_name_ = nullptr; + } + + if (handle_) + { + ::DestroyWindow(handle_); + handle_ = nullptr; + } + + Window::Destroy(); + } + + DWORD WindowImpl::GetWindowStyle() const + { + return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); + } + + void WindowImpl::UpdateCursor() + { + LPTSTR win32_cursor = IDC_ARROW; + switch (mouse_cursor_) + { + case CursorType::Arrow: win32_cursor = IDC_ARROW; break; + case CursorType::TextInput: win32_cursor = IDC_IBEAM; break; + case CursorType::SizeAll: win32_cursor = IDC_SIZEALL; break; + case CursorType::SizeWE: win32_cursor = IDC_SIZEWE; break; + case CursorType::SizeNS: win32_cursor = IDC_SIZENS; break; + case CursorType::SizeNESW: win32_cursor = IDC_SIZENESW; break; + case CursorType::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case CursorType::Hand: win32_cursor = IDC_HAND; break; + } + ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); + } + + void WindowImpl::SetActive(bool actived) + { + if (!handle_) + return; + + if (is_fullscreen_) + { + if (actived) + { + ChangeFullScreenResolution(GetWidth(), GetHeight(), device_name_); + + MONITORINFOEX info = GetMoniterInfoEx(handle_); + ::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, GetWidth(), GetHeight(), SWP_NOACTIVATE); + } + else + { + RestoreResolution(device_name_); + + ::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + ::ShowWindow(handle_, SW_MINIMIZE); + } + } + } + + LRESULT CALLBACK WindowImpl::WndProc(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: + { + KeyDownEventPtr evt = new KeyDownEvent; + evt->code = static_cast(wparam); + window->PushEvent(evt); + } + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + { + KeyUpEventPtr evt = new KeyUpEvent; + evt->code = static_cast(wparam); + window->PushEvent(evt); + } + break; + + case WM_CHAR: + { + KeyCharEventPtr evt = new KeyCharEvent; + evt->value = static_cast(wparam); + window->PushEvent(evt); + } + break; + + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + { + MouseDownEventPtr evt = new MouseDownEvent; + evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); + + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { evt->button = MouseButton::Left; } + else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { evt->button = MouseButton::Right; } + else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { evt->button = MouseButton::Middle; } + + window->PushEvent(evt); + } + break; + + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + MouseUpEventPtr evt = new MouseUpEvent; + evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); + + if (msg == WM_LBUTTONUP) { evt->button = MouseButton::Left; } + else if (msg == WM_RBUTTONUP) { evt->button = MouseButton::Right; } + else if (msg == WM_MBUTTONUP) { evt->button = MouseButton::Middle; } + + window->PushEvent(evt); + } + break; + + case WM_MOUSEMOVE: + { + MouseMoveEventPtr evt = new MouseMoveEvent; + evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); + window->PushEvent(evt); + } + break; + + case WM_MOUSEWHEEL: + { + MouseWheelEventPtr evt = new MouseWheelEvent; + evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam))); + evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA; + window->PushEvent(evt); + } + break; + + case WM_SIZE: + { + if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) + { + KGE_SYS_LOG(L"Window minimized"); + } + else + { + // KGE_SYS_LOG(L"WindowImpl resized"); + + window->SetInternalSize(((uint32_t)(short)LOWORD(lparam)), ((uint32_t)(short)HIWORD(lparam))); + + WindowResizedEventPtr evt = new WindowResizedEvent; + evt->width = window->GetWidth(); + evt->height = window->GetHeight(); + window->PushEvent(evt); + } + } + break; + + case WM_MOVE: + { + int x = ((int)(short)LOWORD(lparam)); + int y = ((int)(short)HIWORD(lparam)); + + WindowMovedEventPtr evt = new WindowMovedEvent; + evt->x = x; + evt->y = y; + window->PushEvent(evt); + } + break; + + case WM_ACTIVATE: + { + bool active = (LOWORD(wparam) != WA_INACTIVE); + + window->SetActive(active); + + WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent; + evt->focus = active; + window->PushEvent(evt); + } + break; + + case WM_SETTEXT: + { + KGE_SYS_LOG(L"Window title changed"); + + String title = String::cstr(reinterpret_cast(lparam)); + window->SetInternalTitle(title); + + WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent; + evt->title = title; + window->PushEvent(evt); + } + break; + + case WM_SETICON: + { + KGE_SYS_LOG(L"Window icon changed"); + } + break; + + case WM_DISPLAYCHANGE: + { + KGE_SYS_LOG(L"The display resolution has changed"); + + ::InvalidateRect(hwnd, nullptr, FALSE); + } + break; + + case WM_SETCURSOR: + { + window->UpdateCursor(); + } + break; + + case WM_CLOSE: + { + KGE_SYS_LOG(L"Window is closing"); + + WindowClosedEventPtr evt = new WindowClosedEvent; + window->PushEvent(evt); + window->Destroy(); + } + break; + + case WM_DESTROY: + { + KGE_SYS_LOG(L"Window was destroyed"); + + ::PostQuitMessage(0); + return 0; + } + break; + } + + return ::DefWindowProcW(hwnd, msg, wparam, lparam); + } + + } // namespace win32 +} // namespace kiwano + +namespace kiwano +{ + Window& Window::Instance() + { + static win32::WindowImpl instance; + return instance; + } +} + +#endif diff --git a/src/kiwano/renderer/Brush.cpp b/src/kiwano/renderer/Brush.cpp index 2ed2f65e..718685e7 100644 --- a/src/kiwano/renderer/Brush.cpp +++ b/src/kiwano/renderer/Brush.cpp @@ -90,17 +90,17 @@ namespace kiwano return; } } - Renderer::instance().CreateSolidBrush(*this, color); + Renderer::Instance().CreateSolidBrush(*this, color); } void Brush::SetStyle(LinearGradientStyle const& style) { - Renderer::instance().CreateLinearGradientBrush(*this, style); + Renderer::Instance().CreateLinearGradientBrush(*this, style); } void Brush::SetStyle(RadialGradientStyle const& style) { - Renderer::instance().CreateRadialGradientBrush(*this, style); + Renderer::Instance().CreateRadialGradientBrush(*this, style); } void Brush::SetBrush(ComPtr brush, Type type) diff --git a/src/kiwano/renderer/Font.cpp b/src/kiwano/renderer/Font.cpp index fb7f8117..fca9256b 100644 --- a/src/kiwano/renderer/Font.cpp +++ b/src/kiwano/renderer/Font.cpp @@ -41,7 +41,7 @@ namespace kiwano { try { - Renderer::instance().CreateFontCollection(*this, files); + Renderer::Instance().CreateFontCollection(*this, files); } catch (std::runtime_error&) { @@ -54,7 +54,7 @@ namespace kiwano { try { - Renderer::instance().CreateFontCollection(*this, resources); + Renderer::Instance().CreateFontCollection(*this, resources); } catch (std::runtime_error&) { diff --git a/src/kiwano/renderer/Geometry.cpp b/src/kiwano/renderer/Geometry.cpp index d9f9acb5..87c50bcf 100644 --- a/src/kiwano/renderer/Geometry.cpp +++ b/src/kiwano/renderer/Geometry.cpp @@ -118,35 +118,35 @@ namespace kiwano Geometry Geometry::CreateLine(Point const& begin, Point const& end) { Geometry output; - Renderer::instance().CreateLineGeometry(output, begin, end); + Renderer::Instance().CreateLineGeometry(output, begin, end); return output; } Geometry Geometry::CreateRect(Rect const& rect) { Geometry output; - Renderer::instance().CreateRectGeometry(output, rect); + Renderer::Instance().CreateRectGeometry(output, rect); return output; } Geometry Geometry::CreateRoundedRect(Rect const& rect, Vec2 const& radius) { Geometry output; - Renderer::instance().CreateRoundedRectGeometry(output, rect, radius); + Renderer::Instance().CreateRoundedRectGeometry(output, rect, radius); return output; } Geometry Geometry::CreateCircle(Point const& center, float radius) { Geometry output; - Renderer::instance().CreateEllipseGeometry(output, center, Vec2{ radius, radius }); + Renderer::Instance().CreateEllipseGeometry(output, center, Vec2{ radius, radius }); return output; } Geometry Geometry::CreateEllipse(Point const& center, Vec2 const& radius) { Geometry output; - Renderer::instance().CreateEllipseGeometry(output, center, radius); + Renderer::Instance().CreateEllipseGeometry(output, center, radius); return output; } diff --git a/src/kiwano/renderer/GeometrySink.cpp b/src/kiwano/renderer/GeometrySink.cpp index 9c9cd431..236eb730 100644 --- a/src/kiwano/renderer/GeometrySink.cpp +++ b/src/kiwano/renderer/GeometrySink.cpp @@ -38,7 +38,7 @@ namespace kiwano if (!IsOpened()) { path_geo_.reset(); - Renderer::instance().CreateGeometrySink(*this); + Renderer::Instance().CreateGeometrySink(*this); win32::ThrowIfFailed(path_geo_->Open(&sink_)); } diff --git a/src/kiwano/renderer/GifImage.cpp b/src/kiwano/renderer/GifImage.cpp index 2d8a6298..365b2d4b 100644 --- a/src/kiwano/renderer/GifImage.cpp +++ b/src/kiwano/renderer/GifImage.cpp @@ -33,7 +33,7 @@ namespace kiwano bool GifImage::Load(String const& file_path) { - Renderer::instance().CreateGifImage(*this, file_path); + Renderer::Instance().CreateGifImage(*this, file_path); if (IsValid()) { @@ -49,7 +49,7 @@ namespace kiwano bool GifImage::Load(Resource const& res) { - Renderer::instance().CreateGifImage(*this, res); + Renderer::Instance().CreateGifImage(*this, res); if (IsValid()) { @@ -71,7 +71,7 @@ namespace kiwano GifImage::Frame GifImage::GetFrame(uint32_t index) { Frame frame; - Renderer::instance().CreateGifImageFrame(frame, *this, index); + Renderer::Instance().CreateGifImageFrame(frame, *this, index); return frame; } diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index ab11ddfb..5caac97e 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -26,11 +26,6 @@ namespace kiwano { - RenderConfig::RenderConfig(Color clear_color, bool vsync) - : clear_color(clear_color) - , vsync(vsync) - { - } Renderer::Renderer() : target_window_(nullptr) @@ -43,20 +38,14 @@ namespace kiwano { } - void Renderer::Init(RenderConfig const& config) - { - SetClearColor(config.clear_color); - SetVSyncEnabled(config.vsync); - } - void Renderer::SetupComponent() { KGE_SYS_LOG(L"Creating device resources"); win32::ThrowIfFailed(::CoInitialize(nullptr)); - target_window_ = Window::instance().GetHandle(); - output_size_ = Window::instance().GetSize(); + target_window_ = Window::Instance().GetHandle(); + output_size_ = Window::Instance().GetSize(); d2d_res_ = nullptr; d3d_res_ = nullptr; @@ -210,7 +199,7 @@ namespace kiwano hr = E_UNEXPECTED; } - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_WARN(L"Texture file '%s' not found!", file_path.c_str()); hr = E_FAIL; @@ -218,7 +207,7 @@ namespace kiwano if (SUCCEEDED(hr)) { - String full_path = FileSystem::instance().GetFullPathForFile(file_path); + String full_path = FileSystem::Instance().GetFullPathForFile(file_path); ComPtr decoder; hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); @@ -328,7 +317,7 @@ namespace kiwano hr = E_UNEXPECTED; } - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str()); hr = E_FAIL; @@ -336,7 +325,7 @@ namespace kiwano if (SUCCEEDED(hr)) { - String full_path = FileSystem::instance().GetFullPathForFile(file_path); + String full_path = FileSystem::Instance().GetFullPathForFile(file_path); ComPtr decoder; hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); @@ -560,13 +549,13 @@ namespace kiwano { for (auto& file_path : full_paths) { - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_WARN(L"Font file '%s' not found!", file_path.c_str()); hr = E_FAIL; } - file_path = FileSystem::instance().GetFullPathForFile(file_path); + file_path = FileSystem::Instance().GetFullPathForFile(file_path); } } diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index 00343d8e..42c920b2 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -52,21 +52,6 @@ namespace kiwano * @{ */ - /** - * \~chinese - * @brief 渲染设置 - */ - struct RenderConfig - { - Color clear_color; ///< 清屏颜色 - bool vsync; ///< 垂直同步 - - RenderConfig( - Color clear_color = Color::Black, - bool vsync = true - ); - }; - /** * \~chinese @@ -294,8 +279,6 @@ namespace kiwano ID3DDeviceResources* GetD3DDeviceResources(); public: - void Init(RenderConfig const& config); - void SetupComponent() override; void DestroyComponent() override; diff --git a/src/kiwano/renderer/StrokeStyle.cpp b/src/kiwano/renderer/StrokeStyle.cpp index afffd048..282e9f55 100644 --- a/src/kiwano/renderer/StrokeStyle.cpp +++ b/src/kiwano/renderer/StrokeStyle.cpp @@ -70,7 +70,7 @@ namespace kiwano StrokeStyle StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size, float dash_offset) { StrokeStyle stroke_style; - Renderer::instance().CreateStrokeStyle(stroke_style, cap, line_join, dash_array, dash_size, dash_offset); + Renderer::Instance().CreateStrokeStyle(stroke_style, cap, line_join, dash_array, dash_size, dash_offset); return stroke_style; } diff --git a/src/kiwano/renderer/TextLayout.cpp b/src/kiwano/renderer/TextLayout.cpp index 125cabad..fb143381 100644 --- a/src/kiwano/renderer/TextLayout.cpp +++ b/src/kiwano/renderer/TextLayout.cpp @@ -42,12 +42,12 @@ namespace kiwano if (!text_format_ || (dirty_flag_ & DirtyFlag::DirtyFormat)) { - Renderer::instance().CreateTextFormat(*this); + Renderer::Instance().CreateTextFormat(*this); } if (dirty_flag_ & DirtyFlag::DirtyLayout) { - Renderer::instance().CreateTextLayout(*this); + Renderer::Instance().CreateTextLayout(*this); if (text_layout_) { diff --git a/src/kiwano/renderer/Texture.cpp b/src/kiwano/renderer/Texture.cpp index 50115768..e36bf405 100644 --- a/src/kiwano/renderer/Texture.cpp +++ b/src/kiwano/renderer/Texture.cpp @@ -36,13 +36,13 @@ namespace kiwano bool Texture::Load(String const& file_path) { - Renderer::instance().CreateTexture(*this, file_path); + Renderer::Instance().CreateTexture(*this, file_path); return IsValid(); } bool Texture::Load(Resource const& res) { - Renderer::instance().CreateTexture(*this, res); + Renderer::Instance().CreateTexture(*this, res); return IsValid(); } diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index c9a40018..e976cf8d 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -55,7 +55,7 @@ namespace kiwano bool ResourceCache::LoadFromJsonFile(String const& file_path) { - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: File not found."); return false; @@ -67,7 +67,7 @@ namespace kiwano try { - String full_path = FileSystem::instance().GetFullPathForFile(file_path); + String full_path = FileSystem::Instance().GetFullPathForFile(file_path); ifs.open(full_path.c_str()); ifs >> json_data; ifs.close(); @@ -115,13 +115,13 @@ namespace kiwano bool ResourceCache::LoadFromXmlFile(String const& file_path) { - if (!FileSystem::instance().IsFileExists(file_path)) + if (!FileSystem::Instance().IsFileExists(file_path)) { KGE_ERROR(L"ResourceCache::LoadFromXmlFile failed: File not found."); return false; } - String full_path = FileSystem::instance().GetFullPathForFile(file_path); + String full_path = FileSystem::Instance().GetFullPathForFile(file_path); pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(full_path.c_str(), pugi::parse_default, pugi::encoding_auto);