From b2a7d89d6156cd7e9aa5aa29dfc06979ec229224 Mon Sep 17 00:00:00 2001 From: Nomango <569629550@qq.com> Date: Tue, 20 Aug 2019 23:51:12 +0800 Subject: [PATCH] Add ResolutionMode --- src/kiwano/base/Window.cpp | 51 ++++++++-------- src/kiwano/base/Window.h | 6 +- src/kiwano/base/types.h | 9 +++ src/kiwano/platform/Application.cpp | 22 ++++--- src/kiwano/platform/Application.h | 2 + src/kiwano/renderer/RenderTarget.cpp | 15 ++++- src/kiwano/renderer/RenderTarget.h | 7 +++ src/kiwano/renderer/Renderer.cpp | 89 ++++++++++++++++++++++++++-- src/kiwano/renderer/Renderer.h | 27 ++++++--- 9 files changed, 181 insertions(+), 47 deletions(-) diff --git a/src/kiwano/base/Window.cpp b/src/kiwano/base/Window.cpp index 296f4257..e62121bb 100644 --- a/src/kiwano/base/Window.cpp +++ b/src/kiwano/base/Window.cpp @@ -21,7 +21,8 @@ #include "Window.h" #include "Logger.h" -#define WINDOW_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX +#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" @@ -44,7 +45,8 @@ namespace kiwano , height_(0) , device_name_(nullptr) , is_fullscreen_(false) - , mouse_cursor_(MouseCursor(-1)) + , resizable_(false) + , mouse_cursor_(MouseCursor::Arrow) { } @@ -66,7 +68,7 @@ namespace kiwano } } - void Window::Init(String const& title, Int32 width, Int32 height, UInt32 icon, bool fullscreen, WNDPROC proc) + void Window::Init(String const& title, Int32 width, Int32 height, UInt32 icon, bool resizable, bool fullscreen, WNDPROC proc) { HINSTANCE hinst = GetModuleHandleW(nullptr); WNDCLASSEX wcex = { 0 }; @@ -80,7 +82,7 @@ namespace kiwano wcex.hInstance = hinst; wcex.hbrBackground = nullptr; wcex.lpszMenuName = nullptr; - wcex.hCursor = nullptr; + wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW); if (icon) { @@ -106,6 +108,7 @@ namespace kiwano Int32 left = -1; Int32 top = -1; + resizable_ = resizable; is_fullscreen_ = fullscreen; if (is_fullscreen_) @@ -165,8 +168,6 @@ namespace kiwano GetClientRect(handle_, &rc); width_ = rc.right - rc.left; height_ = rc.bottom - rc.top; - - SetMouseCursor(MouseCursor::Arrow); } } @@ -296,24 +297,7 @@ namespace kiwano void Window::SetMouseCursor(MouseCursor cursor) { - if (mouse_cursor_ != cursor) - { - mouse_cursor_ = cursor; - - LPTSTR win32_cursor = IDC_ARROW; - switch (cursor) - { - case MouseCursor::Arrow: win32_cursor = IDC_ARROW; break; - case MouseCursor::TextInput: win32_cursor = IDC_IBEAM; break; - case MouseCursor::SizeAll: win32_cursor = IDC_SIZEALL; break; - case MouseCursor::SizeWE: win32_cursor = IDC_SIZEWE; break; - case MouseCursor::SizeNS: win32_cursor = IDC_SIZENS; break; - case MouseCursor::SizeNESW: win32_cursor = IDC_SIZENESW; break; - case MouseCursor::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; - case MouseCursor::Hand: win32_cursor = IDC_HAND; break; - } - ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); - } + mouse_cursor_ = cursor; } HWND Window::GetHandle() const @@ -323,7 +307,7 @@ namespace kiwano DWORD Window::GetWindowStyle() const { - return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (WINDOW_STYLE); + return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); } void Window::UpdateWindowRect() @@ -338,6 +322,23 @@ namespace kiwano height_ = rc.bottom - rc.top; } + void Window::UpdateCursor() + { + LPTSTR win32_cursor = IDC_ARROW; + switch (mouse_cursor_) + { + case MouseCursor::Arrow: win32_cursor = IDC_ARROW; break; + case MouseCursor::TextInput: win32_cursor = IDC_IBEAM; break; + case MouseCursor::SizeAll: win32_cursor = IDC_SIZEALL; break; + case MouseCursor::SizeWE: win32_cursor = IDC_SIZEWE; break; + case MouseCursor::SizeNS: win32_cursor = IDC_SIZENS; break; + case MouseCursor::SizeNESW: win32_cursor = IDC_SIZENESW; break; + case MouseCursor::SizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case MouseCursor::Hand: win32_cursor = IDC_HAND; break; + } + ::SetCursor(::LoadCursorW(nullptr, win32_cursor)); + } + void Window::SetActive(bool actived) { if (!handle_) diff --git a/src/kiwano/base/Window.h b/src/kiwano/base/Window.h index b0c791e6..b613b941 100644 --- a/src/kiwano/base/Window.h +++ b/src/kiwano/base/Window.h @@ -65,6 +65,7 @@ namespace kiwano Int32 width, Int32 height, UInt32 icon, + bool resizable, bool fullscreen, WNDPROC proc ); @@ -77,6 +78,8 @@ namespace kiwano void UpdateWindowRect(); + void UpdateCursor(); + void SetActive(bool actived); protected: @@ -85,8 +88,9 @@ namespace kiwano ~Window(); private: - HWND handle_; + bool resizable_; bool is_fullscreen_; + HWND handle_; Int32 width_; Int32 height_; WCHAR* device_name_; diff --git a/src/kiwano/base/types.h b/src/kiwano/base/types.h index 0066700c..8bc6aa8b 100644 --- a/src/kiwano/base/types.h +++ b/src/kiwano/base/types.h @@ -51,4 +51,13 @@ namespace kiwano GrayScale, // 灰度抗锯齿 None // 不启用抗锯齿 }; + + // 分辨率模式 + enum class ResolutionMode + { + Fixed, /* 固定 */ + Center, /* 居中 */ + Stretch, /* 拉伸 */ + Adaptive, /* 宽高自适应 */ + }; } diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 8c75ca79..fbb81e70 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -43,13 +43,14 @@ namespace kiwano Queue functions_to_perform_; } - Options::Options(String const& title, Int32 width, Int32 height, UInt32 icon, Color clear_color, bool vsync, bool fullscreen, bool debug) + Options::Options(String const& title, Int32 width, Int32 height, UInt32 icon, Color clear_color, bool vsync, bool resizable, bool fullscreen, bool debug) : title(title) , width(width) , height(height) , icon(icon) , clear_color(clear_color) , vsync(vsync) + , resizable(resizable) , fullscreen(fullscreen) , debug(debug) {} @@ -85,6 +86,7 @@ namespace kiwano options.width, options.height, options.icon, + options.resizable, options.fullscreen, Application::WndProc ); @@ -380,11 +382,11 @@ namespace kiwano { if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam) { - KGE_LOG(L"Window minimized"); + // KGE_LOG(L"Window minimized"); } else { - KGE_LOG(L"Window resized"); + // KGE_LOG(L"Window resized"); Window::GetInstance()->UpdateWindowRect(); @@ -422,7 +424,7 @@ namespace kiwano case WM_SETTEXT: { - KGE_LOG(L"Window title changed"); + // KGE_LOG(L"Window title changed"); Event evt(Event::WindowTitleChanged); evt.win.title = reinterpret_cast(lparam); @@ -432,21 +434,27 @@ namespace kiwano case WM_SETICON: { - KGE_LOG(L"Window icon changed"); + // KGE_LOG(L"Window icon changed"); } break; case WM_DISPLAYCHANGE: { - KGE_LOG(L"The display resolution has changed"); + // KGE_LOG(L"The display resolution has changed"); ::InvalidateRect(hwnd, nullptr, FALSE); } break; + case WM_SETCURSOR: + { + Window::GetInstance()->UpdateCursor(); + } + break; + case WM_CLOSE: { - KGE_LOG(L"Window is closing"); + // KGE_LOG(L"Window is closing"); if (!app->OnClosing()) { diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 613b5658..97de5da3 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -35,6 +35,7 @@ namespace kiwano UInt32 icon; // 图标资源 ID Color clear_color; // 清屏颜色 bool vsync; // 垂直同步 + bool resizable; // 窗口大小可拉伸 bool fullscreen; // 全屏模式 bool debug; // 调试模式 @@ -45,6 +46,7 @@ namespace kiwano UInt32 icon = 0, Color clear_color = Color::Black, bool vsync = true, + bool resizable = false, bool fullscreen = false, bool debug = false ); diff --git a/src/kiwano/renderer/RenderTarget.cpp b/src/kiwano/renderer/RenderTarget.cpp index aa33798e..b516ea77 100644 --- a/src/kiwano/renderer/RenderTarget.cpp +++ b/src/kiwano/renderer/RenderTarget.cpp @@ -535,6 +535,11 @@ namespace kiwano return opacity_; } + Matrix3x2 RenderTarget::GetGlobalTransform() const + { + return global_matrix_; + } + void RenderTarget::SetTransform(const Matrix3x2& matrix) { HRESULT hr = S_OK; @@ -545,12 +550,18 @@ namespace kiwano if (SUCCEEDED(hr)) { - render_target_->SetTransform(DX::ConvertToMatrix3x2F(&matrix)); + Matrix3x2 result = matrix * global_matrix_; + render_target_->SetTransform(DX::ConvertToMatrix3x2F(&result)); } ThrowIfFailed(hr); } + void RenderTarget::SetGlobalTransform(const Matrix3x2& matrix) + { + global_matrix_ = matrix; + } + void RenderTarget::SetOpacity(Float32 opacity) { HRESULT hr = S_OK; @@ -628,7 +639,7 @@ namespace kiwano bool RenderTarget::CheckVisibility(Rect const& bounds, Matrix3x2 const& transform) { return Rect{ Point{}, reinterpret_cast(render_target_->GetSize()) }.Intersects( - transform.Transform(bounds) + Matrix3x2(transform * global_matrix_).Transform(bounds) ); } diff --git a/src/kiwano/renderer/RenderTarget.h b/src/kiwano/renderer/RenderTarget.h index 3783fc12..f8c63c5e 100644 --- a/src/kiwano/renderer/RenderTarget.h +++ b/src/kiwano/renderer/RenderTarget.h @@ -140,6 +140,8 @@ namespace kiwano Float32 GetOpacity() const; + Matrix3x2 GetGlobalTransform() const; + void SetOpacity( Float32 opacity ); @@ -148,6 +150,10 @@ namespace kiwano const Matrix3x2& matrix ); + void SetGlobalTransform( + const Matrix3x2& matrix + ); + // 设置抗锯齿模式 void SetAntialiasMode( bool enabled @@ -202,6 +208,7 @@ namespace kiwano ComPtr default_brush_; ComPtr current_brush_; ComPtr device_resources_; + Matrix3x2 global_matrix_; }; diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index 63094173..ccae9a87 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -29,6 +29,7 @@ namespace kiwano : hwnd_(nullptr) , vsync_(true) , clear_color_(Color::Black) + , resolution_mode_(ResolutionMode::Fixed) { } @@ -41,7 +42,7 @@ namespace kiwano KGE_LOG(L"Creating device resources"); hwnd_ = Window::GetInstance()->GetHandle(); - output_size_ = Window::GetInstance()->GetSize(); + resolution_ = output_size_ = Window::GetInstance()->GetSize(); d2d_res_ = nullptr; d3d_res_ = nullptr; @@ -159,6 +160,12 @@ namespace kiwano hr = d3d_res_->ClearRenderTarget(clear_color_); } + if (SUCCEEDED(hr)) + { + SetTransform(Matrix3x2{}); + PushClipRect(Rect{ Point{}, resolution_ }); + } + ThrowIfFailed(hr); } @@ -171,8 +178,11 @@ namespace kiwano hr = E_UNEXPECTED; } + if (SUCCEEDED(hr)) { + PopClipRect(); + EndDraw(); render_target_->RestoreDrawingState(drawing_state_block_.get()); @@ -201,7 +211,7 @@ namespace kiwano UInt32 width = LOWORD(lparam); UInt32 height = HIWORD(lparam); - Resize(width, height); + ResizeTarget(width, height); break; } } @@ -670,7 +680,30 @@ namespace kiwano vsync_ = enabled; } - void Renderer::Resize(UInt32 width, UInt32 height) + void Renderer::SetResolution(Size const& resolution) + { + if (resolution_ != resolution) + { + resolution_ = resolution; + UpdateResolution(); + } + } + + void Renderer::SetResolutionMode(ResolutionMode mode) + { + if (resolution_mode_ != mode) + { + resolution_mode_ = mode; + UpdateResolution(); + } + } + + void Renderer::SetClearColor(const Color& color) + { + clear_color_ = color; + } + + void Renderer::ResizeTarget(UInt32 width, UInt32 height) { HRESULT hr = S_OK; if (!d3d_res_) @@ -685,12 +718,58 @@ namespace kiwano hr = d3d_res_->SetLogicalSize(output_size_); } + if (SUCCEEDED(hr)) + { + UpdateResolution(); + } + ThrowIfFailed(hr); } - void Renderer::SetClearColor(const Color& color) + void Renderer::UpdateResolution() { - clear_color_ = color; + switch (resolution_mode_) + { + case ResolutionMode::Fixed: + { + SetGlobalTransform(Matrix3x2{}); + break; + } + + case ResolutionMode::Center: + { + Float32 left = math::Ceil((output_size_.x - resolution_.x) / 2); + Float32 top = math::Ceil((output_size_.y - resolution_.y) / 2); + SetGlobalTransform(Matrix3x2::Translation(Vec2{ left, top })); + break; + } + + case ResolutionMode::Stretch: + { + Float32 scalex = Float32(Int32((output_size_.x / resolution_.x) * 100 + 0.5f)) / 100; + Float32 scaley = Float32(Int32((output_size_.y / resolution_.y) * 100 + 0.5f)) / 100; + SetGlobalTransform(Matrix3x2::Scaling(Vec2{ scalex, scaley })); + break; + } + + case ResolutionMode::Adaptive: + { + Float32 scalex = Float32(Int32((output_size_.x / resolution_.x) * 100 + 0.5f)) / 100; + Float32 scaley = Float32(Int32((output_size_.y / resolution_.y) * 100 + 0.5f)) / 100; + if (scalex > scaley) + { + Float32 left = math::Ceil((output_size_.x - resolution_.x * scaley) / 2); + SetGlobalTransform(Matrix3x2::SRT(Vec2{ left, 0 }, Vec2{ scaley, scaley }, 0)); + } + else + { + Float32 top = math::Ceil((output_size_.y - resolution_.y * scalex) / 2); + SetGlobalTransform(Matrix3x2::SRT(Vec2{ 0, top }, Vec2{ scalex, scalex }, 0)); + + } + break; + } + } } } diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index a4318b58..7e59ff9a 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -131,9 +131,12 @@ namespace kiwano ImageRenderTarget& render_target ); - void Resize( - UInt32 width, - UInt32 height + void SetResolution( + Size const& resolution + ); + + void SetResolutionMode( + ResolutionMode mode ); public: @@ -152,6 +155,10 @@ namespace kiwano inline Size const& GetOutputSize() const { return output_size_; } + inline Size const& GetResolution() const { return resolution_; } + + inline Color const& GetClearColor() const { return clear_color_; } + inline ID2DDeviceResources* GetD2DDeviceResources() const { KGE_ASSERT(d2d_res_); return d2d_res_.get(); } inline ID3DDeviceResources* GetD3DDeviceResources() const { KGE_ASSERT(d3d_res_); return d3d_res_.get(); } @@ -165,11 +172,17 @@ namespace kiwano HRESULT HandleDeviceLost(); + void ResizeTarget(UInt32 width, UInt32 height); + + void UpdateResolution(); + private: - bool vsync_; - HWND hwnd_; - Size output_size_; - Color clear_color_; + bool vsync_; + HWND hwnd_; + Color clear_color_; + Size output_size_; + Size resolution_; + ResolutionMode resolution_mode_; ComPtr d2d_res_; ComPtr d3d_res_;