Add ResolutionMode

This commit is contained in:
Nomango 2019-08-20 23:51:12 +08:00
parent d9e67fd737
commit b2a7d89d61
9 changed files with 181 additions and 47 deletions

View File

@ -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_)

View File

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

View File

@ -51,4 +51,13 @@ namespace kiwano
GrayScale, // 灰度抗锯齿
None // 不启用抗锯齿
};
// 分辨率模式
enum class ResolutionMode
{
Fixed, /* 固定 */
Center, /* 居中 */
Stretch, /* 拉伸 */
Adaptive, /* 宽高自适应 */
};
}

View File

@ -43,13 +43,14 @@ namespace kiwano
Queue<FunctionToPerform> 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<const WChar*>(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())
{

View File

@ -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
);

View File

@ -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<const Size&>(render_target_->GetSize()) }.Intersects(
transform.Transform(bounds)
Matrix3x2(transform * global_matrix_).Transform(bounds)
);
}

View File

@ -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<ID2D1SolidColorBrush> default_brush_;
ComPtr<ID2D1Brush> current_brush_;
ComPtr<ID2DDeviceResources> device_resources_;
Matrix3x2 global_matrix_;
};

View File

@ -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;
}
}
}
}

View File

@ -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<ID2DDeviceResources> d2d_res_;
ComPtr<ID3DDeviceResources> d3d_res_;