diff --git a/src/kiwano/core/event/WindowEvent.cpp b/src/kiwano/core/event/WindowEvent.cpp index 2ab6ab75..37cafb2b 100644 --- a/src/kiwano/core/event/WindowEvent.cpp +++ b/src/kiwano/core/event/WindowEvent.cpp @@ -39,10 +39,4 @@ WindowClosedEvent::WindowClosedEvent() { } -WindowFullscreenEvent::WindowFullscreenEvent() - : WindowEvent(KGE_EVENT(WindowFullscreenEvent)) - , fullscreen(false) -{ -} - } // namespace kiwano diff --git a/src/kiwano/core/event/WindowEvent.h b/src/kiwano/core/event/WindowEvent.h index 96e5cfb2..26a28e0d 100644 --- a/src/kiwano/core/event/WindowEvent.h +++ b/src/kiwano/core/event/WindowEvent.h @@ -29,7 +29,6 @@ KGE_DECLARE_SMART_PTR(WindowResizedEvent); KGE_DECLARE_SMART_PTR(WindowFocusChangedEvent); KGE_DECLARE_SMART_PTR(WindowTitleChangedEvent); KGE_DECLARE_SMART_PTR(WindowClosedEvent); -KGE_DECLARE_SMART_PTR(WindowFullscreenEvent); /** * \addtogroup Events @@ -94,16 +93,6 @@ public: WindowClosedEvent(); }; -/// \~chinese -/// @brief 窗口切换全屏事件 -class KGE_API WindowFullscreenEvent : public WindowEvent -{ -public: - bool fullscreen; - - WindowFullscreenEvent(); -}; - /** @} */ template <> @@ -113,8 +102,8 @@ struct IsEventType { return evt->GetType() == KGE_EVENT(WindowMovedEvent) || evt->GetType() == KGE_EVENT(WindowResizedEvent) || evt->GetType() == KGE_EVENT(WindowFocusChangedEvent) - || evt->GetType() == KGE_EVENT(WindowTitleChangedEvent) || evt->GetType() == KGE_EVENT(WindowClosedEvent) - || evt->GetType() == KGE_EVENT(WindowFullscreenEvent); + || evt->GetType() == KGE_EVENT(WindowTitleChangedEvent) + || evt->GetType() == KGE_EVENT(WindowClosedEvent); } }; diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 064f1d94..3c17a16f 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -35,7 +35,7 @@ int GetVersion() } Application::Application() - : quiting_(false) + : running_(false) , time_scale_(1.f) { Use(Renderer::GetInstance()); @@ -43,7 +43,10 @@ Application::Application() Use(Director::GetInstance()); } -Application::~Application() {} +Application::~Application() +{ + this->Destroy(); +} void Application::Run(RunnerPtr runner, bool debug) { @@ -65,30 +68,34 @@ void Application::Run(RunnerPtr runner, bool debug) // Everything is ready runner->OnReady(); - quiting_ = false; + running_ = true; last_update_time_ = Time::Now(); - while (!quiting_) + while (running_) { const Time now = Time::Now(); const Duration dt = (now - last_update_time_); last_update_time_ = now; if (!runner->MainLoop(dt)) - quiting_ = true; + running_ = false; } - // Destroy all resources - runner->OnDestroy(); this->Destroy(); } void Application::Quit() { - quiting_ = true; + running_ = false; } void Application::Destroy() { + if (runner_) + { + runner_->OnDestroy(); + runner_ = nullptr; + } + // Clear all resources Director::GetInstance().ClearStages(); ResourceCache::GetInstance().Clear(); @@ -98,6 +105,7 @@ void Application::Destroy() { (*iter)->DestroyModule(); } + modules_.clear(); } void Application::Use(Module& module) @@ -124,6 +132,9 @@ void Application::DispatchEvent(EventPtr evt) void Application::DispatchEvent(Event* evt) { + if (!running_) + return; + for (auto comp : modules_) { if (auto event_comp = comp->Cast()) @@ -135,6 +146,9 @@ void Application::DispatchEvent(Event* evt) void Application::Update(Duration dt) { + if (!running_) + return; + // Before update for (auto comp : modules_) { @@ -186,6 +200,9 @@ void Application::Update(Duration dt) void Application::Render() { + if (!running_) + return; + Renderer& renderer = Renderer::GetInstance(); renderer.Clear(); diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index 1ca1bce2..e64d3e5a 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -77,6 +77,12 @@ public: */ WindowPtr GetMainWindow() const; + /** + * \~chinese + * @brief 是否正在运行 + */ + bool IsRunning() const; + /** * \~chinese * @brief 添加模块 @@ -143,7 +149,7 @@ public: Time GetLastUpdateTime() const; private: - bool quiting_; + bool running_; float time_scale_; RunnerPtr runner_; Time last_update_time_; @@ -163,6 +169,11 @@ inline WindowPtr Application::GetMainWindow() const return runner_->GetMainWindow(); } +inline bool Application::IsRunning() const +{ + return running_; +} + inline Time Application::GetLastUpdateTime() const { return last_update_time_; diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index 1c261f3e..7417b436 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -71,6 +71,9 @@ Runner::~Runner() {} bool Runner::MainLoop(Duration dt) { + if (!main_window_) + return false; + if (main_window_->ShouldClose()) { if (this->OnClosing()) @@ -81,14 +84,16 @@ bool Runner::MainLoop(Duration dt) Application& app = Application::GetInstance(); + // Update modules before poll events + app.Update(dt); + // Poll events + main_window_->PumpEvents(); while (EventPtr evt = main_window_->PollEvent()) { app.DispatchEvent(evt.Get()); } - // Update & render - app.Update(dt); app.Render(); return true; } diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index be976cb4..e132567a 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -38,8 +38,6 @@ Window::~Window() EventPtr Window::PollEvent() { - PumpEvents(); - EventPtr evt; if (!event_queue_.empty()) { @@ -84,6 +82,11 @@ void Window::SetShouldClose(bool should) should_close_ = should; } +void Window::SetFullscreenState(bool is_fullscreen) +{ + is_fullscreen_ = is_fullscreen; +} + void Window::PushEvent(EventPtr evt) { event_queue_.push(evt); diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index bd8a973f..be450e37 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -128,13 +128,6 @@ public: */ virtual void Resize(uint32_t width, uint32_t height) = 0; - /** - * \~chinese - * @brief 设置全屏模式 - * @param fullscreen 是否全屏 - */ - virtual void SetFullscreenState(bool fullscreen) = 0; - /** * \~chinese * @brief 设置鼠标指针类型 @@ -174,6 +167,12 @@ public: */ void SetShouldClose(bool should); + /** + * \~chinese + * @brief 设置当前是否是全屏状态 + */ + void SetFullscreenState(bool is_fullscreen); + protected: Window(); diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index 818b6698..3c8f5322 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include // GET_X_LPARAM, GET_Y_LPARAM #include // ImmAssociateContext #pragma comment(lib, "imm32.lib") @@ -55,8 +56,6 @@ public: void Resize(uint32_t width, uint32_t height) override; - void SetFullscreenState(bool fullscreen) override; - void SetCursor(CursorType cursor) override; void PumpEvents() override; @@ -65,8 +64,6 @@ public: void UpdateCursor(); - void SetActive(bool actived); - LRESULT MessageProc(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_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX -#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP namespace { @@ -276,11 +272,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, ::ShowWindow(handle_, SW_SHOWNORMAL); ::UpdateWindow(handle_); - - if (is_fullscreen_) - { - SetFullscreenState(true); - } } void WindowWin32Impl::PumpEvents() @@ -314,74 +305,20 @@ void WindowWin32Impl::SetIcon(uint32_t icon_resource) void WindowWin32Impl::Resize(uint32_t width, uint32_t height) { KGE_ASSERT(handle_); - if (!is_fullscreen_) - { - RECT rc = { 0, 0, LONG(width), LONG(height) }; - ::AdjustWindowRect(&rc, GetStyle(), false); - width = rc.right - rc.left; - height = rc.bottom - rc.top; + RECT rc = { 0, 0, LONG(width), LONG(height) }; + ::AdjustWindowRect(&rc, GetStyle(), false); - 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; + width = rc.right - rc.left; + height = rc.bottom - rc.top; - ::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); - } -} + 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; -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); - } + ::SetWindowPos(handle_, 0, left, top, width, height, SWP_NOZORDER | SWP_NOACTIVATE); } void WindowWin32Impl::SetCursor(CursorType cursor) @@ -389,31 +326,9 @@ void WindowWin32Impl::SetCursor(CursorType 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 { - return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); + return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); } void WindowWin32Impl::UpdateCursor() @@ -563,7 +478,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA } else { - // KGE_SYS_LOG("Window resized"); + KGE_SYS_LOG("Window resized"); this->width_ = ((uint32_t)(short)LOWORD(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: { - bool active = (LOWORD(wparam) != WA_INACTIVE); - - this->SetActive(active); - WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent; - evt->focus = active; + evt->focus = (LOWORD(wparam) != WA_INACTIVE); this->PushEvent(evt); } 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: { 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"); - ::InvalidateRect(hwnd, nullptr, FALSE); + ::InvalidateRect(hwnd, NULL, FALSE); } break; diff --git a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp index 662cbb90..e5657f31 100644 --- a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp @@ -77,6 +77,10 @@ public: 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; public: @@ -217,24 +221,32 @@ HRESULT D3D10DeviceResources::CreateDeviceResources() if (SUCCEEDED(hr)) { dxgi_device_ = dxgi_device; - - ComPtr dxgi_adapter; - hr = dxgi_device_->GetAdapter(&dxgi_adapter); - - if (SUCCEEDED(hr)) - { - ComPtr dxgi_factory; - hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); - - if (SUCCEEDED(hr)) - { - dxgi_factory_ = dxgi_factory; - } - } } } } + if (SUCCEEDED(hr)) + { + ComPtr dxgi_adapter; + hr = dxgi_device_->GetAdapter(&dxgi_adapter); + + if (SUCCEEDED(hr)) + { + ComPtr dxgi_factory; + hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); + + if (SUCCEEDED(hr)) + { + dxgi_factory_ = dxgi_factory; + } + } + + if (SUCCEEDED(hr)) + { + hr = dxgi_factory_->MakeWindowAssociation(hwnd_, DXGI_MWA_NO_ALT_ENTER); + } + } + if (SUCCEEDED(hr)) { // Setup swap chain @@ -246,6 +258,7 @@ HRESULT D3D10DeviceResources::CreateDeviceResources() swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60; 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.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.OutputWindow = hwnd_; @@ -400,7 +413,61 @@ HRESULT D3D10DeviceResources::SetDpi(float dpi) 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 dxgi_adapter; + + HRESULT hr = dxgi_device_->GetAdapter(&dxgi_adapter); + if (SUCCEEDED(hr)) + { + ComPtr 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() diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp index fe0b7b12..e07084cd 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp @@ -66,6 +66,10 @@ public: 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; public: @@ -239,21 +243,29 @@ HRESULT D3D11DeviceResources::CreateDeviceResources() if (SUCCEEDED(hr)) { dxgi_device_ = dxgi_device; + } + } - ComPtr dxgi_adapter; - hr = dxgi_device_->GetAdapter(&dxgi_adapter); + if (SUCCEEDED(hr)) + { + ComPtr dxgi_adapter; + hr = dxgi_device_->GetAdapter(&dxgi_adapter); + + if (SUCCEEDED(hr)) + { + ComPtr dxgi_factory; + hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); if (SUCCEEDED(hr)) { - ComPtr dxgi_factory; - hr = dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); - - if (SUCCEEDED(hr)) - { - 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.RefreshRate.Numerator = 60; 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.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.OutputWindow = hwnd_; @@ -322,8 +335,9 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources() output_size_.x = std::max(output_size_.x, 1.f); output_size_.y = std::max(output_size_.y, 1.f); - hr = dxgi_swap_chain_->ResizeBuffers(2, // Double-buffered swap chain. - ::lround(output_size_.x), ::lround(output_size_.y), DXGI_FORMAT_UNKNOWN, 0); + hr = dxgi_swap_chain_->ResizeBuffers(2, /* Double-buffered swap chain */ + ::lround(output_size_.x), ::lround(output_size_.y), DXGI_FORMAT_UNKNOWN, + DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); if (SUCCEEDED(hr)) { @@ -373,7 +387,6 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources() device_context_->RSSetViewports(1, &screen_viewport); } - return hr; } @@ -420,7 +433,61 @@ HRESULT D3D11DeviceResources::SetDpi(float dpi) 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 dxgi_adapter; + + HRESULT hr = dxgi_device_->GetAdapter(&dxgi_adapter); + if (SUCCEEDED(hr)) + { + ComPtr 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() diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.h b/src/kiwano/render/DirectX/D3D11DeviceResources.h index 1cb12daf..8adf06bd 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.h +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.h @@ -26,6 +26,7 @@ namespace kiwano { + MIDL_INTERFACE("3ede2b87-a202-4799-a39b-2308ad34cae8") KGE_API ID3D11DeviceResources : public ID3DDeviceResourcesBase { diff --git a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h index 421376a0..b83e7856 100644 --- a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h +++ b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h @@ -39,6 +39,10 @@ public: 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; }; diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index f0bced1d..2b7adb43 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace kiwano { @@ -120,12 +122,6 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) 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() { KGE_SYS_LOG("Destroying device resources"); @@ -953,6 +949,77 @@ RenderContextPtr RendererImpl::CreateTextureRenderContext(Texture& texture, cons 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 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 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) { HRESULT hr = S_OK; diff --git a/src/kiwano/render/DirectX/RendererImpl.h b/src/kiwano/render/DirectX/RendererImpl.h index e90d35ac..4851229e 100644 --- a/src/kiwano/render/DirectX/RendererImpl.h +++ b/src/kiwano/render/DirectX/RendererImpl.h @@ -82,6 +82,10 @@ public: RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) override; + void SetResolution(uint32_t width, uint32_t height, bool fullscreen) override; + + Vector GetResolutions() override; + public: void Clear() override; @@ -104,8 +108,6 @@ protected: void MakeContextForWindow(WindowPtr window) override; - void SetFullscreenState(bool fullscreen) override; - void Destroy() override; private: @@ -114,6 +116,8 @@ private: ComPtr font_collection_loader_; ComPtr res_font_file_loader_; ComPtr res_font_collection_loader_; + + Vector resolutions_; }; /** @} */ diff --git a/src/kiwano/render/Renderer.cpp b/src/kiwano/render/Renderer.cpp index 4c56e029..f25086ef 100644 --- a/src/kiwano/render/Renderer.cpp +++ b/src/kiwano/render/Renderer.cpp @@ -49,11 +49,6 @@ void Renderer::HandleEvent(Event* evt) auto window_evt = dynamic_cast(evt); Resize(window_evt->width, window_evt->height); } - else if (evt->IsType()) - { - auto window_evt = dynamic_cast(evt); - SetFullscreenState(window_evt->fullscreen); - } } void Renderer::BeginDraw() diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index 07bf9ff1..7b2d60f0 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -39,6 +39,18 @@ namespace kiwano * @{ */ +/** + * \~chinese + * @brief 分辨率 + */ +struct Resolution +{ + uint32_t width; ///< 分辨率宽度 + uint32_t height; ///< 分辨率高度 + uint32_t refresh_rate; ///< 刷新率 +}; + + /** * \~chinese * @brief 渲染器 @@ -62,6 +74,14 @@ public: /// @brief 开启或关闭垂直同步 virtual void SetVSyncEnabled(bool enabled); + /// \~chinese + /// @brief 设置分辨率 + virtual void SetResolution(uint32_t width, uint32_t height, bool fullscreen) = 0; + + /// \~chinese + /// @brief 获取屏幕分辨率 + virtual Vector GetResolutions() = 0; + /// \~chinese /// @brief 创建纹理内部资源 /// @param[out] texture 纹理 @@ -246,8 +266,6 @@ protected: virtual void MakeContextForWindow(WindowPtr window) = 0; - virtual void SetFullscreenState(bool fullscreen) = 0; - virtual void Destroy() = 0; protected: