Window fullscreen mode supported
This commit is contained in:
parent
4946246f0f
commit
ff0234559b
|
|
@ -82,8 +82,8 @@ void Runner::InitSettings()
|
|||
}
|
||||
|
||||
// Create game window
|
||||
WindowPtr window =
|
||||
Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable);
|
||||
WindowPtr window = Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon,
|
||||
settings_.resizable, settings_.fullscreen);
|
||||
SetWindow(window);
|
||||
|
||||
// Update renderer settings
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ struct Settings
|
|||
String title; ///< 窗口标题
|
||||
uint32_t icon; ///< 窗口图标
|
||||
bool resizable; ///< 窗口大小可调整
|
||||
bool fullscreen; ///< 窗口全屏
|
||||
Color bg_color; ///< 窗口背景色
|
||||
Duration frame_interval; ///< 帧间隔
|
||||
bool vsync_enabled; ///< 垂直同步
|
||||
|
|
@ -56,6 +57,7 @@ struct Settings
|
|||
, title("Kiwano")
|
||||
, icon()
|
||||
, resizable(false)
|
||||
, fullscreen(false)
|
||||
, bg_color(Color::Black)
|
||||
, frame_interval(16)
|
||||
, vsync_enabled(false)
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ uint32_t Window::GetHeight() const
|
|||
return height_;
|
||||
}
|
||||
|
||||
Resolution Window::GetCurrentResolution() const
|
||||
{
|
||||
return resolution_;
|
||||
}
|
||||
|
||||
WindowHandle Window::GetHandle() const
|
||||
{
|
||||
return handle_;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public:
|
|||
* @throw kiwano::SystemError 窗口创建失败时抛出
|
||||
*/
|
||||
static WindowPtr Create(const String& title, uint32_t width, uint32_t height, uint32_t icon = 0,
|
||||
bool resizable = false);
|
||||
bool resizable = false, bool fullscreen = false);
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
|
|
@ -110,6 +110,12 @@ public:
|
|||
*/
|
||||
uint32_t GetHeight() const;
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 获取当前分辨率
|
||||
*/
|
||||
Resolution GetCurrentResolution() const;
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 获取窗口句柄
|
||||
|
|
@ -214,6 +220,7 @@ protected:
|
|||
uint32_t min_height_;
|
||||
uint32_t max_width_;
|
||||
uint32_t max_height_;
|
||||
Resolution resolution_;
|
||||
WindowHandle handle_;
|
||||
String title_;
|
||||
std::queue<EventPtr> event_queue_;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include <kiwano/event/Events.h>
|
||||
#include <kiwano/platform/Application.h>
|
||||
#include <kiwano/render/Renderer.h>
|
||||
#include <kiwano/render/DirectX/D3DDeviceResources.h>
|
||||
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
|
||||
#include <imm.h> // ImmAssociateContext
|
||||
#pragma comment(lib, "imm32.lib")
|
||||
|
|
@ -49,7 +48,7 @@ public:
|
|||
|
||||
virtual ~WindowWin32Impl();
|
||||
|
||||
void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable);
|
||||
void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen);
|
||||
|
||||
void SetTitle(const String& title) override;
|
||||
|
||||
|
|
@ -69,6 +68,8 @@ public:
|
|||
|
||||
DWORD GetStyle() const;
|
||||
|
||||
void SetActive(bool active);
|
||||
|
||||
void UpdateCursor();
|
||||
|
||||
LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM);
|
||||
|
|
@ -86,12 +87,13 @@ private:
|
|||
std::array<KeyCode, 256> key_map_;
|
||||
};
|
||||
|
||||
WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable)
|
||||
WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable,
|
||||
bool fullscreen)
|
||||
{
|
||||
WindowWin32ImplPtr ptr = memory::New<WindowWin32Impl>();
|
||||
if (ptr)
|
||||
{
|
||||
ptr->Init(title, width, height, icon, resizable);
|
||||
ptr->Init(title, width, height, icon, resizable, fullscreen);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
|
@ -103,6 +105,7 @@ namespace kiwano
|
|||
|
||||
#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
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -202,7 +205,8 @@ WindowWin32Impl::~WindowWin32Impl()
|
|||
::timeEndPeriod(0);
|
||||
}
|
||||
|
||||
void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable)
|
||||
void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable,
|
||||
bool fullscreen)
|
||||
{
|
||||
HINSTANCE hinst = GetModuleHandle(nullptr);
|
||||
WNDCLASSEXA wcex = { 0 };
|
||||
|
|
@ -249,10 +253,13 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
|
|||
width = win_width;
|
||||
height = win_height;
|
||||
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
resizable_ = resizable;
|
||||
handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr,
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
resizable_ = resizable;
|
||||
is_fullscreen_ = fullscreen;
|
||||
resolution_ = Resolution{ width_, height_, 0 };
|
||||
|
||||
handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr,
|
||||
nullptr, hinst, nullptr);
|
||||
|
||||
if (handle_ == nullptr)
|
||||
|
|
@ -269,6 +276,19 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
|
|||
|
||||
::ShowWindow(handle_, SW_SHOWNORMAL);
|
||||
::UpdateWindow(handle_);
|
||||
|
||||
if (is_fullscreen_)
|
||||
{
|
||||
MONITORINFOEXA info = GetMoniterInfoEx(handle_);
|
||||
int x = (int)info.rcMonitor.left;
|
||||
int y = (int)info.rcMonitor.top;
|
||||
int cx = (int)(info.rcMonitor.right - info.rcMonitor.left);
|
||||
int cy = (int)(info.rcMonitor.bottom - info.rcMonitor.top);
|
||||
|
||||
// Top the window
|
||||
::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE);
|
||||
::ShowWindow(handle_, SW_SHOWNORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowWin32Impl::PumpEvents()
|
||||
|
|
@ -318,71 +338,78 @@ void WindowWin32Impl::SetCursor(CursorType cursor)
|
|||
|
||||
void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen)
|
||||
{
|
||||
auto d3d = kiwano::graphics::directx::GetD3DDeviceResources();
|
||||
|
||||
if (fullscreen)
|
||||
if (is_fullscreen_ != fullscreen)
|
||||
{
|
||||
HRESULT hr = d3d->ResizeTarget(width, height);
|
||||
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
|
||||
is_fullscreen_ = fullscreen;
|
||||
|
||||
hr = d3d->SetFullscreenState(fullscreen);
|
||||
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
|
||||
// Reset window style
|
||||
::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle());
|
||||
}
|
||||
|
||||
if (is_fullscreen_)
|
||||
{
|
||||
MONITORINFOEXA info = GetMoniterInfoEx(handle_);
|
||||
int x = (int)info.rcMonitor.left;
|
||||
int y = (int)info.rcMonitor.top;
|
||||
int cx = (int)(info.rcMonitor.right - info.rcMonitor.left);
|
||||
int cy = (int)(info.rcMonitor.bottom - info.rcMonitor.top);
|
||||
|
||||
// Top the window
|
||||
::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE);
|
||||
::ShowWindow(handle_, SW_SHOWNORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = d3d->SetFullscreenState(fullscreen);
|
||||
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
|
||||
// Adjust the rect of client area
|
||||
RECT rc = { 0, 0, LONG(width), LONG(height) };
|
||||
::AdjustWindowRect(&rc, GetStyle(), false);
|
||||
|
||||
hr = d3d->ResizeTarget(width, height);
|
||||
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
|
||||
width = uint32_t(rc.right - rc.left);
|
||||
height = uint32_t(rc.bottom - rc.top);
|
||||
|
||||
MONITORINFOEXA 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;
|
||||
|
||||
// Reset window style
|
||||
::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle());
|
||||
|
||||
// Unpin the window
|
||||
::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, width, height, SWP_DRAWFRAME | SWP_FRAMECHANGED);
|
||||
::ShowWindow(handle_, SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
is_fullscreen_ = fullscreen;
|
||||
resolution_ = Resolution{ width, height, 0 };
|
||||
|
||||
// Resize render target
|
||||
Renderer::GetInstance().Resize(width, height);
|
||||
}
|
||||
|
||||
Vector<Resolution> WindowWin32Impl::GetResolutions()
|
||||
{
|
||||
if (resolutions_.empty())
|
||||
{
|
||||
auto d3d = kiwano::graphics::directx::GetD3DDeviceResources();
|
||||
Set<String> resolution_list;
|
||||
|
||||
DXGI_MODE_DESC* mode_descs = nullptr;
|
||||
int mode_num = 0;
|
||||
DEVMODEA dmi;
|
||||
ZeroMemory(&dmi, sizeof(dmi));
|
||||
dmi.dmSize = sizeof(dmi);
|
||||
|
||||
HRESULT hr = d3d->GetDisplaySettings(&mode_descs, &mode_num);
|
||||
if (SUCCEEDED(hr))
|
||||
DWORD mode_count = 0;
|
||||
while (EnumDisplaySettingsA(device_name_.c_str(), mode_count++, &dmi) != 0)
|
||||
{
|
||||
std::unique_ptr<DXGI_MODE_DESC[]> mode_list(mode_descs);
|
||||
StringStream ss;
|
||||
ss << dmi.dmPelsWidth << 'x' << dmi.dmPelsHeight << ':' << dmi.dmDisplayFrequency;
|
||||
|
||||
if (mode_list)
|
||||
if (resolution_list.find(ss.str()) == resolution_list.end())
|
||||
{
|
||||
for (int i = 0; i < mode_num; i++)
|
||||
{
|
||||
Resolution res;
|
||||
res.width = mode_descs[i].Width;
|
||||
res.height = mode_descs[i].Height;
|
||||
res.refresh_rate = 0;
|
||||
|
||||
if (mode_descs[i].RefreshRate.Denominator > 0)
|
||||
{
|
||||
res.refresh_rate = mode_descs[i].RefreshRate.Numerator / mode_descs[i].RefreshRate.Denominator;
|
||||
}
|
||||
|
||||
if (!resolutions_.empty())
|
||||
{
|
||||
auto& back = resolutions_.back();
|
||||
if (back.width == res.width && back.height == res.height
|
||||
&& back.refresh_rate == res.refresh_rate)
|
||||
continue;
|
||||
}
|
||||
|
||||
resolutions_.push_back(res);
|
||||
}
|
||||
resolution_list.insert(ss.str());
|
||||
resolutions_.push_back(Resolution{ uint32_t(dmi.dmPelsWidth), uint32_t(dmi.dmPelsHeight),
|
||||
uint32_t(dmi.dmDisplayFrequency) });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!");
|
||||
ZeroMemory(&dmi, sizeof(dmi));
|
||||
}
|
||||
}
|
||||
return resolutions_;
|
||||
|
|
@ -390,7 +417,30 @@ Vector<Resolution> WindowWin32Impl::GetResolutions()
|
|||
|
||||
DWORD WindowWin32Impl::GetStyle() const
|
||||
{
|
||||
return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE));
|
||||
if (is_fullscreen_)
|
||||
return WINDOW_FULLSCREEN_STYLE;
|
||||
if (resizable_)
|
||||
return WINDOW_RESIZABLE_STYLE;
|
||||
return WINDOW_FIXED_STYLE;
|
||||
}
|
||||
|
||||
void WindowWin32Impl::SetActive(bool active)
|
||||
{
|
||||
if (!handle_)
|
||||
return;
|
||||
|
||||
if (is_fullscreen_)
|
||||
{
|
||||
// Hide window when it is not active
|
||||
if (active)
|
||||
{
|
||||
::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowWin32Impl::UpdateCursor()
|
||||
|
|
@ -658,8 +708,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
|
|||
{
|
||||
if (is_fullscreen_)
|
||||
{
|
||||
// TODO restore to fullscreen mode
|
||||
// SetResolution();
|
||||
SetActive(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -668,8 +717,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
|
|||
{
|
||||
if (is_fullscreen_)
|
||||
{
|
||||
// TODO exit fullscreen mode
|
||||
// ::ShowWindow(handle_, SW_MINIMIZE);
|
||||
SetActive(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -695,18 +743,6 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
|
|||
case WM_DISPLAYCHANGE:
|
||||
{
|
||||
KGE_SYS_LOG("The display resolution has changed");
|
||||
|
||||
// Check fullscreen state
|
||||
auto d3d_res = graphics::directx::GetD3DDeviceResources();
|
||||
auto swap_chain = d3d_res->GetDXGISwapChain();
|
||||
if (swap_chain)
|
||||
{
|
||||
BOOL is_fullscreen = FALSE;
|
||||
if (SUCCEEDED(swap_chain->GetFullscreenState(&is_fullscreen, nullptr)))
|
||||
{
|
||||
is_fullscreen_ = !!is_fullscreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ inline bool SdkLayersAvailable()
|
|||
struct D3D10DeviceResources : public ID3D10DeviceResources
|
||||
{
|
||||
public:
|
||||
HRESULT Initialize(HWND hwnd) override;
|
||||
HRESULT Initialize(HWND hwnd, Size logical_size) override;
|
||||
|
||||
HRESULT Present(bool vsync) override;
|
||||
|
||||
|
|
@ -138,14 +138,10 @@ D3D10DeviceResources::~D3D10DeviceResources()
|
|||
DiscardResources();
|
||||
}
|
||||
|
||||
HRESULT D3D10DeviceResources::Initialize(HWND hwnd)
|
||||
HRESULT D3D10DeviceResources::Initialize(HWND hwnd, Size logical_size)
|
||||
{
|
||||
RECT rc;
|
||||
::GetClientRect(hwnd, &rc);
|
||||
|
||||
this->hwnd_ = hwnd;
|
||||
this->logical_size_.x = float(rc.right - rc.left);
|
||||
this->logical_size_.y = float(rc.bottom - rc.top);
|
||||
this->logical_size_ = logical_size;
|
||||
|
||||
HRESULT hr = this->CreateDeviceResources();
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ inline bool SdkLayersAvailable()
|
|||
struct D3D11DeviceResources : public ID3D11DeviceResources
|
||||
{
|
||||
public:
|
||||
HRESULT Initialize(HWND hwnd) override;
|
||||
HRESULT Initialize(HWND hwnd, Size logical_size) override;
|
||||
|
||||
HRESULT Present(bool vsync) override;
|
||||
|
||||
|
|
@ -133,14 +133,10 @@ D3D11DeviceResources::~D3D11DeviceResources()
|
|||
DiscardResources();
|
||||
}
|
||||
|
||||
HRESULT D3D11DeviceResources::Initialize(HWND hwnd)
|
||||
HRESULT D3D11DeviceResources::Initialize(HWND hwnd, Size logical_size)
|
||||
{
|
||||
RECT rc;
|
||||
::GetClientRect(hwnd, &rc);
|
||||
|
||||
this->hwnd_ = hwnd;
|
||||
this->logical_size_.x = float(rc.right - rc.left);
|
||||
this->logical_size_.y = float(rc.bottom - rc.top);
|
||||
this->logical_size_ = logical_size;
|
||||
|
||||
HRESULT hr = this->CreateDeviceResources();
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ MIDL_INTERFACE("fb99fa64-d9cf-4e0e-9c75-90514797b01d")
|
|||
ID3DDeviceResourcesBase : public IUnknown
|
||||
{
|
||||
public:
|
||||
virtual HRESULT Initialize(HWND hwnd) = 0;
|
||||
virtual HRESULT Initialize(HWND hwnd, Size logical_size) = 0;
|
||||
|
||||
virtual HRESULT Present(bool vsync) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,17 +55,18 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
|
|||
|
||||
KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed");
|
||||
|
||||
HWND target_window = window->GetHandle();
|
||||
output_size_ = window->GetSize();
|
||||
HWND target_window = window->GetHandle();
|
||||
Resolution resolution = window->GetCurrentResolution();
|
||||
HRESULT hr = target_window ? S_OK : E_FAIL;
|
||||
|
||||
HRESULT hr = target_window ? S_OK : E_FAIL;
|
||||
output_size_ = Size{ float(resolution.width), float(resolution.height) };
|
||||
|
||||
// Initialize Direct3D resources
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto d3d_res = graphics::directx::GetD3DDeviceResources();
|
||||
|
||||
hr = d3d_res->Initialize(target_window);
|
||||
hr = d3d_res->Initialize(target_window, output_size_);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
d3d_res->DiscardResources();
|
||||
|
|
|
|||
Loading…
Reference in New Issue