Add resolution related functions

This commit is contained in:
Nomango 2020-05-17 21:02:43 +08:00
parent ce5edaa689
commit 2ff0d1ad95
16 changed files with 358 additions and 186 deletions

View File

@ -39,10 +39,4 @@ WindowClosedEvent::WindowClosedEvent()
{ {
} }
WindowFullscreenEvent::WindowFullscreenEvent()
: WindowEvent(KGE_EVENT(WindowFullscreenEvent))
, fullscreen(false)
{
}
} // namespace kiwano } // namespace kiwano

View File

@ -29,7 +29,6 @@ KGE_DECLARE_SMART_PTR(WindowResizedEvent);
KGE_DECLARE_SMART_PTR(WindowFocusChangedEvent); KGE_DECLARE_SMART_PTR(WindowFocusChangedEvent);
KGE_DECLARE_SMART_PTR(WindowTitleChangedEvent); KGE_DECLARE_SMART_PTR(WindowTitleChangedEvent);
KGE_DECLARE_SMART_PTR(WindowClosedEvent); KGE_DECLARE_SMART_PTR(WindowClosedEvent);
KGE_DECLARE_SMART_PTR(WindowFullscreenEvent);
/** /**
* \addtogroup Events * \addtogroup Events
@ -94,16 +93,6 @@ public:
WindowClosedEvent(); WindowClosedEvent();
}; };
/// \~chinese
/// @brief 窗口切换全屏事件
class KGE_API WindowFullscreenEvent : public WindowEvent
{
public:
bool fullscreen;
WindowFullscreenEvent();
};
/** @} */ /** @} */
template <> template <>
@ -113,8 +102,8 @@ struct IsEventType<WindowEvent>
{ {
return evt->GetType() == KGE_EVENT(WindowMovedEvent) || evt->GetType() == KGE_EVENT(WindowResizedEvent) return evt->GetType() == KGE_EVENT(WindowMovedEvent) || evt->GetType() == KGE_EVENT(WindowResizedEvent)
|| evt->GetType() == KGE_EVENT(WindowFocusChangedEvent) || evt->GetType() == KGE_EVENT(WindowFocusChangedEvent)
|| evt->GetType() == KGE_EVENT(WindowTitleChangedEvent) || evt->GetType() == KGE_EVENT(WindowClosedEvent) || evt->GetType() == KGE_EVENT(WindowTitleChangedEvent)
|| evt->GetType() == KGE_EVENT(WindowFullscreenEvent); || evt->GetType() == KGE_EVENT(WindowClosedEvent);
} }
}; };

View File

@ -35,7 +35,7 @@ int GetVersion()
} }
Application::Application() Application::Application()
: quiting_(false) : running_(false)
, time_scale_(1.f) , time_scale_(1.f)
{ {
Use(Renderer::GetInstance()); Use(Renderer::GetInstance());
@ -43,7 +43,10 @@ Application::Application()
Use(Director::GetInstance()); Use(Director::GetInstance());
} }
Application::~Application() {} Application::~Application()
{
this->Destroy();
}
void Application::Run(RunnerPtr runner, bool debug) void Application::Run(RunnerPtr runner, bool debug)
{ {
@ -65,30 +68,34 @@ void Application::Run(RunnerPtr runner, bool debug)
// Everything is ready // Everything is ready
runner->OnReady(); runner->OnReady();
quiting_ = false; running_ = true;
last_update_time_ = Time::Now(); last_update_time_ = Time::Now();
while (!quiting_) while (running_)
{ {
const Time now = Time::Now(); const Time now = Time::Now();
const Duration dt = (now - last_update_time_); const Duration dt = (now - last_update_time_);
last_update_time_ = now; last_update_time_ = now;
if (!runner->MainLoop(dt)) if (!runner->MainLoop(dt))
quiting_ = true; running_ = false;
} }
// Destroy all resources
runner->OnDestroy();
this->Destroy(); this->Destroy();
} }
void Application::Quit() void Application::Quit()
{ {
quiting_ = true; running_ = false;
} }
void Application::Destroy() void Application::Destroy()
{ {
if (runner_)
{
runner_->OnDestroy();
runner_ = nullptr;
}
// Clear all resources // Clear all resources
Director::GetInstance().ClearStages(); Director::GetInstance().ClearStages();
ResourceCache::GetInstance().Clear(); ResourceCache::GetInstance().Clear();
@ -98,6 +105,7 @@ void Application::Destroy()
{ {
(*iter)->DestroyModule(); (*iter)->DestroyModule();
} }
modules_.clear();
} }
void Application::Use(Module& module) void Application::Use(Module& module)
@ -124,6 +132,9 @@ void Application::DispatchEvent(EventPtr evt)
void Application::DispatchEvent(Event* evt) void Application::DispatchEvent(Event* evt)
{ {
if (!running_)
return;
for (auto comp : modules_) for (auto comp : modules_)
{ {
if (auto event_comp = comp->Cast<EventModule>()) if (auto event_comp = comp->Cast<EventModule>())
@ -135,6 +146,9 @@ void Application::DispatchEvent(Event* evt)
void Application::Update(Duration dt) void Application::Update(Duration dt)
{ {
if (!running_)
return;
// Before update // Before update
for (auto comp : modules_) for (auto comp : modules_)
{ {
@ -186,6 +200,9 @@ void Application::Update(Duration dt)
void Application::Render() void Application::Render()
{ {
if (!running_)
return;
Renderer& renderer = Renderer::GetInstance(); Renderer& renderer = Renderer::GetInstance();
renderer.Clear(); renderer.Clear();

View File

@ -77,6 +77,12 @@ public:
*/ */
WindowPtr GetMainWindow() const; WindowPtr GetMainWindow() const;
/**
* \~chinese
* @brief
*/
bool IsRunning() const;
/** /**
* \~chinese * \~chinese
* @brief Ìí¼ÓÄ£¿é * @brief Ìí¼ÓÄ£¿é
@ -143,7 +149,7 @@ public:
Time GetLastUpdateTime() const; Time GetLastUpdateTime() const;
private: private:
bool quiting_; bool running_;
float time_scale_; float time_scale_;
RunnerPtr runner_; RunnerPtr runner_;
Time last_update_time_; Time last_update_time_;
@ -163,6 +169,11 @@ inline WindowPtr Application::GetMainWindow() const
return runner_->GetMainWindow(); return runner_->GetMainWindow();
} }
inline bool Application::IsRunning() const
{
return running_;
}
inline Time Application::GetLastUpdateTime() const inline Time Application::GetLastUpdateTime() const
{ {
return last_update_time_; return last_update_time_;

View File

@ -71,6 +71,9 @@ Runner::~Runner() {}
bool Runner::MainLoop(Duration dt) bool Runner::MainLoop(Duration dt)
{ {
if (!main_window_)
return false;
if (main_window_->ShouldClose()) if (main_window_->ShouldClose())
{ {
if (this->OnClosing()) if (this->OnClosing())
@ -81,14 +84,16 @@ bool Runner::MainLoop(Duration dt)
Application& app = Application::GetInstance(); Application& app = Application::GetInstance();
// Update modules before poll events
app.Update(dt);
// Poll events // Poll events
main_window_->PumpEvents();
while (EventPtr evt = main_window_->PollEvent()) while (EventPtr evt = main_window_->PollEvent())
{ {
app.DispatchEvent(evt.Get()); app.DispatchEvent(evt.Get());
} }
// Update & render
app.Update(dt);
app.Render(); app.Render();
return true; return true;
} }

View File

@ -38,8 +38,6 @@ Window::~Window()
EventPtr Window::PollEvent() EventPtr Window::PollEvent()
{ {
PumpEvents();
EventPtr evt; EventPtr evt;
if (!event_queue_.empty()) if (!event_queue_.empty())
{ {
@ -84,6 +82,11 @@ void Window::SetShouldClose(bool should)
should_close_ = should; should_close_ = should;
} }
void Window::SetFullscreenState(bool is_fullscreen)
{
is_fullscreen_ = is_fullscreen;
}
void Window::PushEvent(EventPtr evt) void Window::PushEvent(EventPtr evt)
{ {
event_queue_.push(evt); event_queue_.push(evt);

View File

@ -128,13 +128,6 @@ public:
*/ */
virtual void Resize(uint32_t width, uint32_t height) = 0; virtual void Resize(uint32_t width, uint32_t height) = 0;
/**
* \~chinese
* @brief
* @param fullscreen
*/
virtual void SetFullscreenState(bool fullscreen) = 0;
/** /**
* \~chinese * \~chinese
* @brief * @brief
@ -174,6 +167,12 @@ public:
*/ */
void SetShouldClose(bool should); void SetShouldClose(bool should);
/**
* \~chinese
* @brief
*/
void SetFullscreenState(bool is_fullscreen);
protected: protected:
Window(); Window();

View File

@ -31,6 +31,7 @@
#include <kiwano/core/event/MouseEvent.h> #include <kiwano/core/event/MouseEvent.h>
#include <kiwano/core/event/WindowEvent.h> #include <kiwano/core/event/WindowEvent.h>
#include <kiwano/platform/Application.h> #include <kiwano/platform/Application.h>
#include <kiwano/render/Renderer.h>
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM #include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <imm.h> // ImmAssociateContext #include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib") #pragma comment(lib, "imm32.lib")
@ -55,8 +56,6 @@ public:
void Resize(uint32_t width, uint32_t height) override; void Resize(uint32_t width, uint32_t height) override;
void SetFullscreenState(bool fullscreen) override;
void SetCursor(CursorType cursor) override; void SetCursor(CursorType cursor) override;
void PumpEvents() override; void PumpEvents() override;
@ -65,8 +64,6 @@ public:
void UpdateCursor(); void UpdateCursor();
void SetActive(bool actived);
LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM); LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM);
static LRESULT CALLBACK StaticWndProc(HWND, UINT32, WPARAM, LPARAM); static LRESULT CALLBACK StaticWndProc(HWND, UINT32, WPARAM, LPARAM);
@ -97,7 +94,6 @@ namespace kiwano
#define WINDOW_FIXED_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_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX
#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP
namespace namespace
{ {
@ -276,11 +272,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
::ShowWindow(handle_, SW_SHOWNORMAL); ::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_); ::UpdateWindow(handle_);
if (is_fullscreen_)
{
SetFullscreenState(true);
}
} }
void WindowWin32Impl::PumpEvents() void WindowWin32Impl::PumpEvents()
@ -314,8 +305,7 @@ void WindowWin32Impl::SetIcon(uint32_t icon_resource)
void WindowWin32Impl::Resize(uint32_t width, uint32_t height) void WindowWin32Impl::Resize(uint32_t width, uint32_t height)
{ {
KGE_ASSERT(handle_); KGE_ASSERT(handle_);
if (!is_fullscreen_)
{
RECT rc = { 0, 0, LONG(width), LONG(height) }; RECT rc = { 0, 0, LONG(width), LONG(height) };
::AdjustWindowRect(&rc, GetStyle(), false); ::AdjustWindowRect(&rc, GetStyle(), false);
@ -330,90 +320,15 @@ void WindowWin32Impl::Resize(uint32_t width, uint32_t height)
::SetWindowPos(handle_, 0, left, top, width, height, SWP_NOZORDER | SWP_NOACTIVATE); ::SetWindowPos(handle_, 0, left, top, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
} }
else
{
MONITORINFOEXA info = GetMoniterInfoEx(handle_);
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height, SWP_NOACTIVATE);
}
}
void WindowWin32Impl::SetFullscreenState(bool fullscreen)
{
if (is_fullscreen_ != fullscreen)
{
is_fullscreen_ = fullscreen;
// Adjust the rect of client area
RECT rc = { 0, 0, LONG(width_), LONG(height_) };
::AdjustWindowRect(&rc, GetStyle(), false);
uint32_t width = uint32_t(rc.right - rc.left);
uint32_t height = uint32_t(rc.bottom - rc.top);
if (is_fullscreen_)
{
// Reset window style
::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle());
// Top the window
MONITORINFOEXA info = GetMoniterInfoEx(handle_);
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height,
SWP_NOACTIVATE);
}
else
{
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);
// Send event
WindowFullscreenEventPtr evt = new WindowFullscreenEvent;
evt->fullscreen = is_fullscreen_;
PushEvent(evt);
}
}
void WindowWin32Impl::SetCursor(CursorType cursor) void WindowWin32Impl::SetCursor(CursorType cursor)
{ {
mouse_cursor_ = cursor; mouse_cursor_ = cursor;
} }
void WindowWin32Impl::SetActive(bool actived)
{
if (!handle_)
return;
if (is_fullscreen_)
{
// Hide window when it is not active
if (actived)
{
MONITORINFOEXA info = GetMoniterInfoEx(handle_);
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width_, height_,
SWP_NOACTIVATE);
}
else
{
::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
::ShowWindow(handle_, SW_MINIMIZE);
}
}
}
DWORD WindowWin32Impl::GetStyle() const DWORD WindowWin32Impl::GetStyle() const
{ {
return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE));
} }
void WindowWin32Impl::UpdateCursor() void WindowWin32Impl::UpdateCursor()
@ -563,7 +478,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
} }
else else
{ {
// KGE_SYS_LOG("Window resized"); KGE_SYS_LOG("Window resized");
this->width_ = ((uint32_t)(short)LOWORD(lparam)); this->width_ = ((uint32_t)(short)LOWORD(lparam));
this->height_ = ((uint32_t)(short)HIWORD(lparam)); this->height_ = ((uint32_t)(short)HIWORD(lparam));
@ -587,16 +502,32 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_ACTIVATE: case WM_ACTIVATE:
{ {
bool active = (LOWORD(wparam) != WA_INACTIVE);
this->SetActive(active);
WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent; WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent;
evt->focus = active; evt->focus = (LOWORD(wparam) != WA_INACTIVE);
this->PushEvent(evt); this->PushEvent(evt);
} }
break; break;
case WM_SETFOCUS:
{
if (is_fullscreen_)
{
// TODO restore to fullscreen mode
// Renderer::GetInstance().SetResolution();
}
}
break;
case WM_KILLFOCUS:
{
if (is_fullscreen_)
{
// TODO exit fullscreen mode
// ::ShowWindow(handle_, SW_MINIMIZE);
}
}
break;
case WM_SETTEXT: case WM_SETTEXT:
{ {
KGE_SYS_LOG("Window title changed"); KGE_SYS_LOG("Window title changed");
@ -619,7 +550,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
{ {
KGE_SYS_LOG("The display resolution has changed"); KGE_SYS_LOG("The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE); ::InvalidateRect(hwnd, NULL, FALSE);
} }
break; break;

View File

@ -77,6 +77,10 @@ public:
HRESULT SetFullscreenState(bool fullscreen) override; HRESULT SetFullscreenState(bool fullscreen) override;
HRESULT ResizeTarget(UINT width, UINT height) override;
HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) override;
void DiscardResources() override; void DiscardResources() override;
public: public:
@ -217,7 +221,12 @@ HRESULT D3D10DeviceResources::CreateDeviceResources()
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
dxgi_device_ = dxgi_device; dxgi_device_ = dxgi_device;
}
}
}
if (SUCCEEDED(hr))
{
ComPtr<IDXGIAdapter> dxgi_adapter; ComPtr<IDXGIAdapter> dxgi_adapter;
hr = dxgi_device_->GetAdapter(&dxgi_adapter); hr = dxgi_device_->GetAdapter(&dxgi_adapter);
@ -231,7 +240,10 @@ HRESULT D3D10DeviceResources::CreateDeviceResources()
dxgi_factory_ = dxgi_factory; dxgi_factory_ = dxgi_factory;
} }
} }
}
if (SUCCEEDED(hr))
{
hr = dxgi_factory_->MakeWindowAssociation(hwnd_, DXGI_MWA_NO_ALT_ENTER);
} }
} }
@ -246,6 +258,7 @@ HRESULT D3D10DeviceResources::CreateDeviceResources()
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60; swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1; swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = hwnd_; swap_chain_desc.OutputWindow = hwnd_;
@ -400,7 +413,61 @@ HRESULT D3D10DeviceResources::SetDpi(float dpi)
HRESULT D3D10DeviceResources::SetFullscreenState(bool fullscreen) HRESULT D3D10DeviceResources::SetFullscreenState(bool fullscreen)
{ {
return dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); HRESULT hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr);
return hr;
}
HRESULT D3D10DeviceResources::ResizeTarget(UINT width, UINT height)
{
DXGI_MODE_DESC desc = { 0 };
desc.Width = width;
desc.Height = height;
desc.Format = DXGI_FORMAT_UNKNOWN;
HRESULT hr = dxgi_swap_chain_->ResizeTarget(&desc);
return hr;
}
HRESULT D3D10DeviceResources::GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num)
{
ComPtr<IDXGIAdapter> dxgi_adapter;
HRESULT hr = dxgi_device_->GetAdapter(&dxgi_adapter);
if (SUCCEEDED(hr))
{
ComPtr<IDXGIOutput> output;
hr = dxgi_adapter->EnumOutputs(0, &output);
if (SUCCEEDED(hr))
{
UINT modes_num = 0;
DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
UINT flags = DXGI_ENUM_MODES_INTERLACED;
output->GetDisplayModeList(format, flags, &modes_num, 0);
if (modes_num > 0)
{
DXGI_MODE_DESC* temp = new DXGI_MODE_DESC[modes_num];
hr = output->GetDisplayModeList(format, flags, &modes_num, temp);
if (SUCCEEDED(hr) && mode_descs && num)
{
(*mode_descs) = temp;
(*num) = (int)modes_num;
}
else
{
delete[] temp;
}
}
else
{
hr = E_FAIL;
}
}
}
return hr;
} }
STDMETHODIMP_(unsigned long) D3D10DeviceResources::AddRef() STDMETHODIMP_(unsigned long) D3D10DeviceResources::AddRef()

View File

@ -66,6 +66,10 @@ public:
HRESULT SetFullscreenState(bool fullscreen) override; HRESULT SetFullscreenState(bool fullscreen) override;
HRESULT ResizeTarget(UINT width, UINT height) override;
HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) override;
void DiscardResources() override; void DiscardResources() override;
public: public:
@ -239,7 +243,11 @@ HRESULT D3D11DeviceResources::CreateDeviceResources()
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
dxgi_device_ = dxgi_device; dxgi_device_ = dxgi_device;
}
}
if (SUCCEEDED(hr))
{
ComPtr<IDXGIAdapter> dxgi_adapter; ComPtr<IDXGIAdapter> dxgi_adapter;
hr = dxgi_device_->GetAdapter(&dxgi_adapter); hr = dxgi_device_->GetAdapter(&dxgi_adapter);
@ -253,6 +261,10 @@ HRESULT D3D11DeviceResources::CreateDeviceResources()
dxgi_factory_ = dxgi_factory; dxgi_factory_ = dxgi_factory;
} }
} }
if (SUCCEEDED(hr))
{
hr = dxgi_factory_->MakeWindowAssociation(hwnd_, DXGI_MWA_NO_ALT_ENTER);
} }
} }
} }
@ -268,6 +280,7 @@ HRESULT D3D11DeviceResources::CreateDeviceResources()
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60; swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1; swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
swap_chain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = hwnd_; swap_chain_desc.OutputWindow = hwnd_;
@ -322,8 +335,9 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources()
output_size_.x = std::max(output_size_.x, 1.f); output_size_.x = std::max(output_size_.x, 1.f);
output_size_.y = std::max(output_size_.y, 1.f); output_size_.y = std::max(output_size_.y, 1.f);
hr = dxgi_swap_chain_->ResizeBuffers(2, // Double-buffered swap chain. hr = dxgi_swap_chain_->ResizeBuffers(2, /* Double-buffered swap chain */
::lround(output_size_.x), ::lround(output_size_.y), DXGI_FORMAT_UNKNOWN, 0); ::lround(output_size_.x), ::lround(output_size_.y), DXGI_FORMAT_UNKNOWN,
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -373,7 +387,6 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources()
device_context_->RSSetViewports(1, &screen_viewport); device_context_->RSSetViewports(1, &screen_viewport);
} }
return hr; return hr;
} }
@ -420,7 +433,61 @@ HRESULT D3D11DeviceResources::SetDpi(float dpi)
HRESULT D3D11DeviceResources::SetFullscreenState(bool fullscreen) HRESULT D3D11DeviceResources::SetFullscreenState(bool fullscreen)
{ {
return dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); HRESULT hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr);
return hr;
}
HRESULT D3D11DeviceResources::ResizeTarget(UINT width, UINT height)
{
DXGI_MODE_DESC desc = { 0 };
desc.Width = width;
desc.Height = height;
desc.Format = DXGI_FORMAT_UNKNOWN;
HRESULT hr = dxgi_swap_chain_->ResizeTarget(&desc);
return hr;
}
HRESULT D3D11DeviceResources::GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num)
{
ComPtr<IDXGIAdapter> dxgi_adapter;
HRESULT hr = dxgi_device_->GetAdapter(&dxgi_adapter);
if (SUCCEEDED(hr))
{
ComPtr<IDXGIOutput> output;
hr = dxgi_adapter->EnumOutputs(0, &output);
if (SUCCEEDED(hr))
{
UINT modes_num = 0;
DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
UINT flags = DXGI_ENUM_MODES_INTERLACED;
output->GetDisplayModeList(format, flags, &modes_num, 0);
if (modes_num > 0)
{
DXGI_MODE_DESC* temp = new DXGI_MODE_DESC[modes_num];
hr = output->GetDisplayModeList(format, flags, &modes_num, temp);
if (SUCCEEDED(hr) && mode_descs && num)
{
(*mode_descs) = temp;
(*num) = (int)modes_num;
}
else
{
delete[] temp;
}
}
else
{
hr = E_FAIL;
}
}
}
return hr;
} }
STDMETHODIMP_(unsigned long) D3D11DeviceResources::AddRef() STDMETHODIMP_(unsigned long) D3D11DeviceResources::AddRef()

View File

@ -26,6 +26,7 @@
namespace kiwano namespace kiwano
{ {
MIDL_INTERFACE("3ede2b87-a202-4799-a39b-2308ad34cae8") MIDL_INTERFACE("3ede2b87-a202-4799-a39b-2308ad34cae8")
KGE_API ID3D11DeviceResources : public ID3DDeviceResourcesBase KGE_API ID3D11DeviceResources : public ID3DDeviceResourcesBase
{ {

View File

@ -39,6 +39,10 @@ public:
virtual HRESULT SetFullscreenState(bool fullscreen) = 0; virtual HRESULT SetFullscreenState(bool fullscreen) = 0;
virtual HRESULT ResizeTarget(UINT width, UINT height) = 0;
virtual HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) = 0;
virtual void DiscardResources() = 0; virtual void DiscardResources() = 0;
}; };

View File

@ -27,6 +27,8 @@
#include <kiwano/render/DirectX/RendererImpl.h> #include <kiwano/render/DirectX/RendererImpl.h>
#include <kiwano/render/DirectX/NativePtr.h> #include <kiwano/render/DirectX/NativePtr.h>
#include <memory>
namespace kiwano namespace kiwano
{ {
@ -120,12 +122,6 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
KGE_THROW_IF_FAILED(hr, "Create render resources failed"); KGE_THROW_IF_FAILED(hr, "Create render resources failed");
} }
void RendererImpl::SetFullscreenState(bool fullscreen)
{
KGE_ASSERT(d3d_res_);
d3d_res_->SetFullscreenState(fullscreen);
}
void RendererImpl::Destroy() void RendererImpl::Destroy()
{ {
KGE_SYS_LOG("Destroying device resources"); KGE_SYS_LOG("Destroying device resources");
@ -953,6 +949,77 @@ RenderContextPtr RendererImpl::CreateTextureRenderContext(Texture& texture, cons
return nullptr; return nullptr;
} }
void RendererImpl::SetResolution(uint32_t width, uint32_t height, bool fullscreen)
{
KGE_ASSERT(d3d_res_);
if (fullscreen)
{
HRESULT hr = d3d_res_->ResizeTarget(width, height);
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
hr = d3d_res_->SetFullscreenState(fullscreen);
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
}
else
{
HRESULT hr = d3d_res_->SetFullscreenState(fullscreen);
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
hr = d3d_res_->ResizeTarget(width, height);
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
}
Application::GetInstance().GetMainWindow()->SetFullscreenState(fullscreen);
}
Vector<Resolution> RendererImpl::GetResolutions()
{
if (resolutions_.empty())
{
DXGI_MODE_DESC* mode_descs = nullptr;
int mode_num = 0;
HRESULT hr = d3d_res_->GetDisplaySettings(&mode_descs, &mode_num);
if (SUCCEEDED(hr))
{
std::unique_ptr<DXGI_MODE_DESC[]> mode_list(mode_descs);
if (mode_list)
{
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);
}
}
}
else
{
KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!");
}
}
return resolutions_;
}
void RendererImpl::Resize(uint32_t width, uint32_t height) void RendererImpl::Resize(uint32_t width, uint32_t height)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;

View File

@ -82,6 +82,10 @@ public:
RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) override; RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) override;
void SetResolution(uint32_t width, uint32_t height, bool fullscreen) override;
Vector<Resolution> GetResolutions() override;
public: public:
void Clear() override; void Clear() override;
@ -104,8 +108,6 @@ protected:
void MakeContextForWindow(WindowPtr window) override; void MakeContextForWindow(WindowPtr window) override;
void SetFullscreenState(bool fullscreen) override;
void Destroy() override; void Destroy() override;
private: private:
@ -114,6 +116,8 @@ private:
ComPtr<IFontCollectionLoader> font_collection_loader_; ComPtr<IFontCollectionLoader> font_collection_loader_;
ComPtr<IResourceFontFileLoader> res_font_file_loader_; ComPtr<IResourceFontFileLoader> res_font_file_loader_;
ComPtr<IResourceFontCollectionLoader> res_font_collection_loader_; ComPtr<IResourceFontCollectionLoader> res_font_collection_loader_;
Vector<Resolution> resolutions_;
}; };
/** @} */ /** @} */

View File

@ -49,11 +49,6 @@ void Renderer::HandleEvent(Event* evt)
auto window_evt = dynamic_cast<WindowResizedEvent*>(evt); auto window_evt = dynamic_cast<WindowResizedEvent*>(evt);
Resize(window_evt->width, window_evt->height); Resize(window_evt->width, window_evt->height);
} }
else if (evt->IsType<WindowFullscreenEvent>())
{
auto window_evt = dynamic_cast<WindowFullscreenEvent*>(evt);
SetFullscreenState(window_evt->fullscreen);
}
} }
void Renderer::BeginDraw() void Renderer::BeginDraw()

View File

@ -39,6 +39,18 @@ namespace kiwano
* @{ * @{
*/ */
/**
* \~chinese
* @brief
*/
struct Resolution
{
uint32_t width; ///< 分辨率宽度
uint32_t height; ///< 分辨率高度
uint32_t refresh_rate; ///< 刷新率
};
/** /**
* \~chinese * \~chinese
* @brief * @brief
@ -62,6 +74,14 @@ public:
/// @brief 开启或关闭垂直同步 /// @brief 开启或关闭垂直同步
virtual void SetVSyncEnabled(bool enabled); virtual void SetVSyncEnabled(bool enabled);
/// \~chinese
/// @brief 设置分辨率
virtual void SetResolution(uint32_t width, uint32_t height, bool fullscreen) = 0;
/// \~chinese
/// @brief 获取屏幕分辨率
virtual Vector<Resolution> GetResolutions() = 0;
/// \~chinese /// \~chinese
/// @brief 创建纹理内部资源 /// @brief 创建纹理内部资源
/// @param[out] texture 纹理 /// @param[out] texture 纹理
@ -246,8 +266,6 @@ protected:
virtual void MakeContextForWindow(WindowPtr window) = 0; virtual void MakeContextForWindow(WindowPtr window) = 0;
virtual void SetFullscreenState(bool fullscreen) = 0;
virtual void Destroy() = 0; virtual void Destroy() = 0;
protected: protected: