diff --git a/Engine/Source/Editor/EditorApp.cpp b/Engine/Source/Editor/EditorApp.cpp index d34497b8..068b9cfc 100644 --- a/Engine/Source/Editor/EditorApp.cpp +++ b/Engine/Source/Editor/EditorApp.cpp @@ -3,7 +3,6 @@ #include "Application/Engine.h" #include "Display/CameraController.h" #include "ECWorld/SceneWorld.h" -#include "ImGui/EditorImGuiViewport.h" #include "ImGui/ImGuiContextInstance.h" #include "ImGui/Localization.h" #include "ImGui/UILayers/DebugPanel.h" @@ -48,6 +47,7 @@ #include "UILayers/TestNodeEditor.h" #include "Window/Input.h" #include "Window/Window.h" +#include "Window/WindowManager.h" #include #define IMGUI_DEFINE_MATH_OPERATORS @@ -80,6 +80,8 @@ void EditorApp::Init(engine::EngineInitArgs initArgs) CD_ERROR("Failed to open CSV file"); } + m_pWindowManager = std::make_unique(); + // Phase 1 - Splash // * Compile uber shader permutations automatically when initialization or detect changes // * Show compile progresses so it still needs to update ui @@ -94,7 +96,7 @@ void EditorApp::Init(engine::EngineInitArgs initArgs) pSplashWindow->OnResize.Bind(m_pRenderContext.get()); m_pMainWindow = pSplashWindow.get(); - AddWindow(cd::MoveTemp(pSplashWindow)); + m_pWindowManager->AddWindow(cd::MoveTemp(pSplashWindow)); InitEditorRenderers(); EditorRenderersWarmup(); @@ -124,29 +126,12 @@ void EditorApp::Shutdown() { } -engine::Window* EditorApp::GetWindow(void* handle) const -{ - auto itWindow = m_mapWindows.find(handle); - return itWindow != m_mapWindows.end() ? itWindow->second.get() : nullptr; -} - -void EditorApp::AddWindow(std::unique_ptr pWindow) -{ - m_mapWindows[pWindow->GetHandle()] = cd::MoveTemp(pWindow); -} - -void EditorApp::RemoveWindow(void* handle) -{ - assert(handle != m_pMainWindow->GetHandle()); - m_mapWindows.erase(handle); -} - void EditorApp::InitEditorImGuiContext(engine::Language language) { assert(GetMainWindow() && "Init window before imgui context"); const bool enableDock = true; - const bool enableViewport = true; + const bool enableViewport = false; m_pEditorImGuiContext = std::make_unique(GetMainWindow()->GetWidth(), GetMainWindow()->GetHeight(), enableDock, enableViewport); RegisterImGuiUserData(m_pEditorImGuiContext.get()); @@ -163,12 +148,12 @@ void EditorApp::InitEditorImGuiContext(engine::Language language) // Init viewport settings. if (enableViewport) { - m_pEditorImGuiViewport = std::make_unique(this, m_pRenderContext.get()); + m_pEditorImGuiContext->InitViewport(m_pWindowManager.get(), m_pRenderContext.get()); ImGuiViewport* pMainViewport = ImGui::GetMainViewport(); assert(pMainViewport); pMainViewport->PlatformHandle = GetMainWindow(); pMainViewport->PlatformHandleRaw = GetMainWindow()->GetHandle(); - m_pEditorImGuiViewport->Update(); + m_pEditorImGuiContext->UpdateViewport(); } } @@ -601,22 +586,7 @@ bool EditorApp::Update(float deltaTime) InitEngineUILayers(); } - for (auto& [_, pWindow] : m_mapWindows) - { - pWindow->Update(); - if (pWindow->IsFocused()) - { - m_pFocusedWindow = pWindow.get(); - } - } - - if (m_pEditorImGuiContext->IsViewportEnable()) - { - m_pEditorImGuiViewport->Update(); - auto position = engine::Input::Get().GetGloalMousePosition(); - engine::Input::Get().SetMousePositionX(position.first); - engine::Input::Get().SetMousePositionY(position.second); - } + m_pWindowManager->Update(); m_pEditorImGuiContext->Update(deltaTime); m_pSceneWorld->Update(); @@ -637,6 +607,12 @@ bool EditorApp::Update(float deltaTime) } } + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + } + if (m_pEngineImGuiContext) { GetMainWindow()->SetMouseVisible(m_pSceneView->IsShowMouse(), m_pSceneView->GetMouseFixedPositionX(), m_pSceneView->GetMouseFixedPositionY()); diff --git a/Engine/Source/Editor/EditorApp.h b/Engine/Source/Editor/EditorApp.h index 73da2374..91c0ebe0 100644 --- a/Engine/Source/Editor/EditorApp.h +++ b/Engine/Source/Editor/EditorApp.h @@ -14,6 +14,7 @@ class FlybyCamera; class ImGuiBaseLayer; class ImGuiContextInstance; class Window; +class WindowManager; class RenderContext; class Renderer; class AABBRenderer; @@ -28,7 +29,6 @@ struct ImGuiContext; namespace editor { -class EditorImGuiViewport; class FileWatcher; class SceneView; @@ -46,10 +46,8 @@ class EditorApp final : public engine::IApplication virtual bool Update(float deltaTime) override; virtual void Shutdown() override; - engine::Window* GetWindow(void* handle) const; engine::Window* GetMainWindow() const { return m_pMainWindow; } - void AddWindow(std::unique_ptr pWindow); - void RemoveWindow(void* handle); + engine::WindowManager* GetWindowManager() const { return m_pWindowManager.get(); } void InitRenderContext(engine::GraphicsBackend backend, void* hwnd = nullptr); @@ -90,16 +88,20 @@ class EditorApp final : public engine::IApplication // Windows engine::Window* m_pMainWindow = nullptr; - engine::Window* m_pFocusedWindow = nullptr; - std::map> m_mapWindows; + std::unique_ptr m_pWindowManager; // ImGui std::unique_ptr m_pEditorImGuiContext; std::unique_ptr m_pEngineImGuiContext; - std::unique_ptr m_pEditorImGuiViewport; // Scene std::unique_ptr m_pSceneWorld; + + // Rendering + std::unique_ptr m_pRenderContext; + std::unique_ptr m_pShaderCollections; + std::vector> m_pEditorRenderers; + std::vector> m_pEngineRenderers; editor::SceneView* m_pSceneView = nullptr; engine::Renderer* m_pSceneRenderer = nullptr; engine::Renderer* m_pWhiteModelRenderer = nullptr; @@ -109,13 +111,6 @@ class EditorApp final : public engine::IApplication engine::Renderer* m_pTerrainRenderer = nullptr; engine::Renderer* m_pAABBRenderer = nullptr; - // Rendering - std::unique_ptr m_pRenderContext; - std::unique_ptr m_pShaderCollections; - - std::vector> m_pEditorRenderers; - std::vector> m_pEngineRenderers; - // Controllers for processing input events. std::unique_ptr m_pViewportCameraController; diff --git a/Engine/Source/Editor/ImGui/EditorImGuiViewport.cpp b/Engine/Source/Editor/ImGui/EditorImGuiViewport.cpp deleted file mode 100644 index 090d337d..00000000 --- a/Engine/Source/Editor/ImGui/EditorImGuiViewport.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "EditorImGuiViewport.h" - -#include "EditorApp.h" -#include "Rendering/RenderContext.h" -#include "Window/Window.h" - -#include - -namespace editor -{ - -EditorImGuiViewport::EditorImGuiViewport(editor::EditorApp* pEditor, engine::RenderContext* pRenderContext) -{ - static editor::EditorApp* pEditorApp = pEditor; - - ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); - platformIO.Platform_CreateWindow = [](ImGuiViewport* pViewport) - { - auto pWindow = std::make_unique("Dockable", 100, 100); - pViewport->PlatformHandle = pWindow.get(); - pViewport->PlatformHandleRaw = pWindow->GetHandle(); - pEditorApp->AddWindow(cd::MoveTemp(pWindow)); - }; - - platformIO.Platform_DestroyWindow = [](ImGuiViewport* pViewport) - { - pEditorApp->RemoveWindow(pViewport->PlatformHandleRaw); - pViewport->PlatformHandle = nullptr; - pViewport->PlatformUserData = nullptr; - }; - - platformIO.Platform_ShowWindow = [](ImGuiViewport* pViewport) - { - pEditorApp->GetWindow(pViewport->PlatformHandleRaw)->Show(); - }; - - platformIO.Platform_SetWindowPos = [](ImGuiViewport* pViewport, ImVec2 v) - { - pEditorApp->GetWindow(pViewport->PlatformHandleRaw)->SetPosition(static_cast(v.x), static_cast(v.y)); - }; - - platformIO.Platform_GetWindowPos = [](ImGuiViewport* pViewport) -> ImVec2 - { - engine::Window* pWindow = pEditorApp->GetWindow(pViewport->PlatformHandleRaw); - auto position = pWindow->GetPosition(); - return { static_cast(position.first), static_cast(position.second) }; - }; - - platformIO.Platform_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 v) - { - pEditorApp->GetWindow(pViewport->PlatformHandleRaw)->SetSize(static_cast(v.x), static_cast(v.y)); - }; - - platformIO.Platform_GetWindowSize = [](ImGuiViewport* pViewport) -> ImVec2 - { - engine::Window* pWindow = pEditorApp->GetWindow(pViewport->PlatformHandleRaw); - auto size = pWindow->GetSize(); - return { static_cast(size.first), static_cast(size.second) }; - }; - - platformIO.Platform_SetWindowTitle = [](ImGuiViewport* pViewport, const char* pTitle) - { - engine::Window* pWindow = pEditorApp->GetWindow(pViewport->PlatformHandleRaw); - pWindow->SetTitle(pTitle); - }; -} - -void EditorImGuiViewport::Update() -{ - ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); - int monitorCount = engine::Window::GetDisplayMonitorCount(); - platformIO.Monitors.resize(0); - for (int monitorIndex = 0; monitorIndex < monitorCount; ++monitorIndex) - { - auto mainRect = engine::Window::GetDisplayMonitorMainRect(monitorIndex); - auto workRect = engine::Window::GetDisplayMonitorWorkRect(monitorIndex); - - ImGuiPlatformMonitor monitor; - monitor.MainPos = ImVec2((float)mainRect.x, (float)mainRect.y); - monitor.MainSize = ImVec2((float)mainRect.w, (float)mainRect.h); - monitor.WorkPos = ImVec2((float)workRect.x, (float)workRect.y); - monitor.WorkSize = ImVec2((float)workRect.w, (float)workRect.h); - - // Check if the display's position is at (0,0), which is typical for the primary display. - bool isPrimaryDisplay = mainRect.x == 0 && mainRect.y == 0; - if (isPrimaryDisplay) - { - platformIO.Monitors.push_front(monitor); - } - else - { - platformIO.Monitors.push_back(monitor); - } - } -} - -} \ No newline at end of file diff --git a/Engine/Source/Editor/ImGui/EditorImGuiViewport.h b/Engine/Source/Editor/ImGui/EditorImGuiViewport.h deleted file mode 100644 index 21c494ed..00000000 --- a/Engine/Source/Editor/ImGui/EditorImGuiViewport.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -namespace engine -{ - -class RenderContext; - -} - -namespace editor -{ - -class EditorApp; - -struct EditorImGuiViewportData -{ - engine::RenderContext* pRenderContext; -}; - -class EditorImGuiViewport -{ -public: - EditorImGuiViewport() = delete; - explicit EditorImGuiViewport(editor::EditorApp* pEditor, engine::RenderContext* pRenderContext); - EditorImGuiViewport(const EditorImGuiViewport&) = delete; - EditorImGuiViewport& operator=(const EditorImGuiViewport&) = delete; - EditorImGuiViewport(EditorImGuiViewport&&) = default; - EditorImGuiViewport& operator=(EditorImGuiViewport&&) = default; - - void Update(); -}; - -} \ No newline at end of file diff --git a/Engine/Source/Runtime/Application/Engine.cpp b/Engine/Source/Runtime/Application/Engine.cpp index cfcdcda9..058c0114 100644 --- a/Engine/Source/Runtime/Application/Engine.cpp +++ b/Engine/Source/Runtime/Application/Engine.cpp @@ -27,7 +27,6 @@ Engine::~Engine() void Engine::Init(EngineInitArgs args) { CD_ENGINE_INFO("Init engine"); - Window::Init(); m_pApplication->Init(args); } @@ -54,7 +53,6 @@ void Engine::Run() void Engine::Shutdown() { - Window::Shutdown(); } // diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp index f49e3dae..de33b7e2 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp @@ -3,8 +3,11 @@ #include "IconFont/IconsMaterialDesignIcons.h" #include "IconFont/MaterialDesign.inl" #include "ImGui/ImGuiBaseLayer.h" +#include "Rendering/RenderContext.h" +#include "Rendering/RenderTarget.h" #include "Window/Input.h" #include "Window/Window.h" +#include "Window/WindowManager.h" #include "Log/Log.h" #include @@ -16,7 +19,7 @@ #include #endif -//#include +#include #include #include @@ -176,8 +179,7 @@ class TempSwitchContextScope namespace engine { -ImGuiContextInstance::ImGuiContextInstance(uint16_t width, uint16_t height, bool enableDock, bool enableViewport) : - m_enableViewport(enableViewport) +ImGuiContextInstance::ImGuiContextInstance(uint16_t width, uint16_t height, bool enableDock, bool enableViewport) { m_pImGuiContext = ImGui::CreateContext(); SwitchCurrentContext(); @@ -239,6 +241,139 @@ void ImGuiContextInstance::ClearUILayers() m_pImGuiDockableLayers.clear(); } +void ImGuiContextInstance::InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext) +{ + // Register window interfaces. + static WindowManager* s_pWindowManager = pWindowManager; + ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); + platformIO.Platform_CreateWindow = [](ImGuiViewport* pViewport) + { + auto pWindow = std::make_unique("ViewportWindow", 1, 1); + pViewport->PlatformHandle = pWindow.get(); + pViewport->PlatformHandleRaw = pWindow->GetHandle(); + s_pWindowManager->AddWindow(cd::MoveTemp(pWindow)); + }; + + platformIO.Platform_DestroyWindow = [](ImGuiViewport* pViewport) + { + s_pWindowManager->RemoveWindow(pViewport->PlatformHandleRaw); + pViewport->PlatformHandle = nullptr; + pViewport->PlatformUserData = nullptr; + }; + + platformIO.Platform_ShowWindow = [](ImGuiViewport* pViewport) + { + s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw)->Show(); + }; + + platformIO.Platform_SetWindowPos = [](ImGuiViewport* pViewport, ImVec2 v) + { + s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw)->SetPosition(static_cast(v.x), static_cast(v.y)); + }; + + platformIO.Platform_GetWindowPos = [](ImGuiViewport* pViewport) -> ImVec2 + { + engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); + auto position = pWindow->GetPosition(); + return { static_cast(position.first), static_cast(position.second) }; + }; + + platformIO.Platform_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 v) + { + s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw)->SetSize(static_cast(v.x), static_cast(v.y)); + }; + + platformIO.Platform_GetWindowSize = [](ImGuiViewport* pViewport) -> ImVec2 + { + engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); + auto size = pWindow->GetSize(); + return { static_cast(size.first), static_cast(size.second) }; + }; + + platformIO.Platform_SetWindowTitle = [](ImGuiViewport* pViewport, const char* pTitle) + { + engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); + pWindow->SetTitle(pTitle); + }; + + platformIO.Platform_GetWindowFocus = [](ImGuiViewport* pViewport) + { + engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); + return pWindow->IsFocused(); + }; + + platformIO.Platform_SetWindowFocus = [](ImGuiViewport* pViewport) + { + engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); + return pWindow->SetFocused(); + }; + + // Register rendering interfaces. + static RenderContext* s_pRenderContext = pRenderContext; + platformIO.Renderer_CreateWindow = [](ImGuiViewport* pViewport) + { + uint16_t newViewID = s_pRenderContext->CreateView(); + engine::StringCrc newRenderTargetName(std::format("ViewportRT_{}", newViewID)); + s_pRenderContext->CreateRenderTarget(newRenderTargetName, 1, 1, pViewport->PlatformHandleRaw); + pViewport->PlatformUserData = reinterpret_cast(newViewID); + }; + + struct CastPtrToViewID + { + union + { + void* pUserData; + uint16_t viewID; + }; + }; + + platformIO.Renderer_DestroyWindow = [](ImGuiViewport* pViewport) + { + CastPtrToViewID cast; + cast.pUserData = pViewport->PlatformUserData; + uint16_t viewID = cast.viewID; + s_pRenderContext->DestoryRenderTarget(StringCrc(std::format("ViewportRT_{}", viewID))); + }; + + platformIO.Renderer_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 size) + { + CastPtrToViewID cast; + cast.pUserData = pViewport->PlatformUserData; + uint16_t viewID = cast.viewID; + auto* pRenderTarget = s_pRenderContext->GetRenderTarget(StringCrc(std::format("ViewportRT_{}", viewID))); + pRenderTarget->Resize(static_cast(size.x), static_cast(size.y)); + }; +} + +void ImGuiContextInstance::UpdateViewport() +{ + ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); + int monitorCount = engine::Window::GetDisplayMonitorCount(); + platformIO.Monitors.resize(0); + for (int monitorIndex = 0; monitorIndex < monitorCount; ++monitorIndex) + { + auto mainRect = engine::Window::GetDisplayMonitorMainRect(monitorIndex); + auto workRect = engine::Window::GetDisplayMonitorWorkRect(monitorIndex); + + ImGuiPlatformMonitor monitor; + monitor.MainPos = ImVec2((float)mainRect.x, (float)mainRect.y); + monitor.MainSize = ImVec2((float)mainRect.w, (float)mainRect.h); + monitor.WorkPos = ImVec2((float)workRect.x, (float)workRect.y); + monitor.WorkSize = ImVec2((float)workRect.w, (float)workRect.h); + + // Check if the display's position is at (0,0), which is typical for the primary display. + bool isPrimaryDisplay = mainRect.x == 0 && mainRect.y == 0; + if (isPrimaryDisplay) + { + platformIO.Monitors.push_front(monitor); + } + else + { + platformIO.Monitors.push_back(monitor); + } + } +} + void ImGuiContextInstance::BeginDockSpace() { // To create a dock space, we need to create a window to host it at first. @@ -325,7 +460,16 @@ void ImGuiContextInstance::Update(float deltaTime) SwitchCurrentContext(); auto& io = ImGui::GetIO(); - + + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + UpdateViewport(); + + auto position = engine::Input::Get().GetGloalMousePosition(); + engine::Input::Get().SetMousePositionX(position.first); + engine::Input::Get().SetMousePositionY(position.second); + } + // It is necessary to pass correct deltaTime to ImGui underlaying framework because it will use the value to check // something such as if mouse button double click happens(Two click event happens in one frame, < deltaTime). io.DeltaTime = deltaTime; diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h index e041be43..20af585e 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h @@ -14,6 +14,8 @@ namespace engine { class ImGuiBaseLayer; +class WindowManager; +class RenderContext; class SceneWorld; class ImGuiContextInstance @@ -27,43 +29,37 @@ class ImGuiContextInstance ImGuiContextInstance& operator=(ImGuiContextInstance&&) = default; virtual ~ImGuiContextInstance(); - // ImGui can have multiple ImGuiContexts. For example, you want to render ImGui both in engine and editor. - // This method helps to switch ImGui's current context pointer to this ImGuiContextInstance. - // Note that if a method needs to call ImGui api, please call this method in the first line - // unless you really know what you are doing. - // Update multiple ImGuiContext in different threads is not safe. So please update them both in main thread by correct order. - void SwitchCurrentContext() const; + void Update(float deltaTime); - // Query if m_pImGuiContext is current active context. + // Context settings. bool IsActive() const; + void SwitchCurrentContext() const; - // Static layer means non-movable, non-dockable. + // GUI management. + void OnResize(uint16_t width, uint16_t height); void AddStaticLayer(std::unique_ptr pLayer); - - // Dockable layer means movable, dockable. std::vector>& GetDockableLayers() { return m_pImGuiDockableLayers; } void AddDynamicLayer(std::unique_ptr pLayer); - void ClearUILayers(); - void Update(float deltaTime); - - void OnResize(uint16_t width, uint16_t height); - + // GUI styles. void LoadFontFiles(const std::vector& ttfFileNames, engine::Language language); ThemeColor GetImGuiThemeColor() const { return m_themeColor; } + void SetImGuiThemeColor(ThemeColor theme); Language GetImGuiLanguage() const { return m_language; } void SetImGuiLanguage(Language language); - void SetImGuiThemeColor(ThemeColor theme); - + // Input management. void SetWindowPosOffset(float x, float y) { m_windowPosOffsetX = x; m_windowPosOffsetY = y; } + // Viewport feature. + void InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext); + void UpdateViewport(); + + // Access to world data. void SetSceneWorld(SceneWorld* pSceneWorld) { m_pSceneWorld = pSceneWorld; } SceneWorld* GetSceneWorld() const { return m_pSceneWorld; } - bool IsViewportEnable() const { return m_enableViewport; } - private: void AddInputEvent(); void SetImGuiStyles(); @@ -86,7 +82,6 @@ class ImGuiContextInstance float m_lastMousePositionX = 0.0f; float m_lastMousePositionY = 0.0f; - bool m_enableViewport = false; std::vector> m_pImGuiStaticLayers; std::vector> m_pImGuiDockableLayers; }; diff --git a/Engine/Source/Runtime/Rendering/ImGuiRenderer.cpp b/Engine/Source/Runtime/Rendering/ImGuiRenderer.cpp index a357ed54..096bd742 100644 --- a/Engine/Source/Runtime/Rendering/ImGuiRenderer.cpp +++ b/Engine/Source/Runtime/Rendering/ImGuiRenderer.cpp @@ -5,6 +5,8 @@ #include +#include + namespace engine { @@ -12,8 +14,6 @@ void ImGuiRenderer::Init() { constexpr StringCrc programCrc = StringCrc("ImGuiProgram"); GetRenderContext()->RegisterShaderProgram(programCrc, { "vs_imgui", "fs_imgui" }); - - bgfx::setViewName(GetViewID(), "ImGuiRenderer"); } void ImGuiRenderer::Warmup() @@ -56,31 +56,58 @@ void ImGuiRenderer::UpdateView(const float* pViewMatrix, const float* pProjectio } ImGui::Render(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - bgfx::setViewMode(GetViewID(), bgfx::ViewMode::Sequential); - if (const engine::RenderTarget* pRenderTarget = GetRenderTarget()) + struct CastPtrToViewID { - bgfx::setViewFrameBuffer(GetViewID(), *(pRenderTarget->GetFrameBufferHandle())); - } - - const ImDrawData* pImGuiDrawData = ImGui::GetDrawData(); - float x = pImGuiDrawData->DisplayPos.x; - float y = pImGuiDrawData->DisplayPos.y; - float width = pImGuiDrawData->DisplaySize.x; - float height = pImGuiDrawData->DisplaySize.y; - const bgfx::Caps* pCapabilities = bgfx::getCaps(); + union + { + void* pUserData; + uint16_t viewID; + }; + }; - cd::Matrix4x4 orthoMatrix = cd::Matrix4x4::Orthographic(x, x + width, y, y + height, 0.0f, 1000.0f, 0.0f, pCapabilities->homogeneousDepth); - bgfx::setViewRect(GetViewID(), 0, 0, uint16_t(width), uint16_t(height)); - bgfx::setViewTransform(GetViewID(), nullptr, orthoMatrix.begin()); + ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); + for (const ImGuiViewport* pViewport : platformIO.Viewports) + { + CastPtrToViewID cast; + cast.pUserData = pViewport->PlatformUserData; + uint16_t viewID = cast.viewID; + RenderTarget* pRenderTarget = GetRenderContext()->GetRenderTarget(StringCrc(std::format("ViewportRT_{}", viewID))); + if (!pRenderTarget) + { + viewID = GetViewID(); + } + else + { + bgfx::setViewFrameBuffer(viewID, *pRenderTarget->GetFrameBufferHandle()); + } + + bgfx::setViewName(viewID, "ImGuiRenderer"); + bgfx::setViewMode(viewID, bgfx::ViewMode::Sequential); + + const ImDrawData* pImGuiDrawData = pViewport->DrawData; + float x = pImGuiDrawData->DisplayPos.x; + float y = pImGuiDrawData->DisplayPos.y; + float width = pImGuiDrawData->DisplaySize.x; + float height = pImGuiDrawData->DisplaySize.y; + const bgfx::Caps* pCapabilities = bgfx::getCaps(); + cd::Matrix4x4 orthoMatrix = cd::Matrix4x4::Orthographic(x, x + width, y, y + height, 0.0f, 1000.0f, 0.0f, pCapabilities->homogeneousDepth); + bgfx::setViewRect(viewID, 0, 0, uint16_t(width), uint16_t(height)); + bgfx::setViewTransform(viewID, nullptr, orthoMatrix.begin()); + } } void ImGuiRenderer::Render(float deltaTime) { - ImDrawData* pImGuiDrawData = ImGui::GetDrawData(); + ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); + for (const ImGuiViewport* pViewport : platformIO.Viewports) + { + RenderDrawData(pViewport->DrawData, deltaTime); + } +} +void ImGuiRenderer::RenderDrawData(ImDrawData* pImGuiDrawData, float deltaTime) +{ int frameBufferWidth = static_cast(pImGuiDrawData->DisplaySize.x * pImGuiDrawData->FramebufferScale.x); int frameBufferHeight = static_cast(pImGuiDrawData->DisplaySize.y * pImGuiDrawData->FramebufferScale.y); const ImVec2 clipPos = pImGuiDrawData->DisplayPos; // (0,0) unless using multi-viewports diff --git a/Engine/Source/Runtime/Rendering/ImGuiRenderer.h b/Engine/Source/Runtime/Rendering/ImGuiRenderer.h index 7ade340d..db326532 100644 --- a/Engine/Source/Runtime/Rendering/ImGuiRenderer.h +++ b/Engine/Source/Runtime/Rendering/ImGuiRenderer.h @@ -2,6 +2,8 @@ #include "Rendering/Renderer.h" +struct ImDrawData; + namespace engine { @@ -14,6 +16,9 @@ class ImGuiRenderer final : public engine::Renderer virtual void Warmup() override; virtual void UpdateView(const float* pViewMatrix, const float* pProjectionMatrix) override; virtual void Render(float deltaTime) override; + +private: + void RenderDrawData(ImDrawData* pImGuiDrawData, float deltaTime); }; } \ No newline at end of file diff --git a/Engine/Source/Runtime/Window/Window.cpp b/Engine/Source/Runtime/Window/Window.cpp index 58a08157..481fb09b 100644 --- a/Engine/Source/Runtime/Window/Window.cpp +++ b/Engine/Source/Runtime/Window/Window.cpp @@ -65,17 +65,6 @@ Window::~Window() SDL_DestroyWindow(m_pSDLWindow); } -void Window::Close(bool bPushSdlEvent) -{ - m_isClosed = true; - if (!bPushSdlEvent) { return; } - - SDL_Event sdlEvent; - SDL_QuitEvent& quitEvent = sdlEvent.quit; - quitEvent.type = SDL_QUIT; - SDL_PushEvent(&sdlEvent); -} - void* Window::GetHandle() const { SDL_SysWMinfo wmi; @@ -193,6 +182,27 @@ bool Window::GetMouseFocus() const return SDL_GetWindowFlags(m_pSDLWindow) & SDL_WINDOW_MOUSE_FOCUS; } +bool Window::IsFocused() const +{ + return SDL_GetWindowFlags(m_pSDLWindow) & SDL_WINDOW_INPUT_FOCUS; +} + +void Window::SetFocused() +{ + SDL_RaiseWindow(m_pSDLWindow); +} + +void Window::Close(bool bPushSdlEvent) +{ + m_isClosed = true; + if (!bPushSdlEvent) { return; } + + SDL_Event sdlEvent; + SDL_QuitEvent& quitEvent = sdlEvent.quit; + quitEvent.type = SDL_QUIT; + SDL_PushEvent(&sdlEvent); +} + void Window::SetResizeable(bool on) { SDL_SetWindowResizable(m_pSDLWindow, static_cast(on)); @@ -271,8 +281,6 @@ void Window::Update() { Input::Get().Reset(); - m_isFocused = SDL_GetWindowFlags(m_pSDLWindow) & SDL_WINDOW_INPUT_FOCUS; - SDL_Event sdlEvent; while (SDL_PollEvent(&sdlEvent)) { diff --git a/Engine/Source/Runtime/Window/Window.h b/Engine/Source/Runtime/Window/Window.h index d3fd2b28..7f4961fb 100644 --- a/Engine/Source/Runtime/Window/Window.h +++ b/Engine/Source/Runtime/Window/Window.h @@ -36,7 +36,6 @@ class Window ~Window(); void* GetHandle() const; - //void* GetParentHandle() const; const char* GetTitle() const; void SetTitle(const char* pTitle); @@ -55,8 +54,16 @@ class Window void Hide(); void SetFullScreen(bool on); + // Status + bool IsFocused() const; + void SetFocused(); bool GetInputFocus() const; bool GetMouseFocus() const; + + bool ShouldClose() const { return m_isClosed; } + void Close(bool bPushSdlEvent = true); + + // Styles void SetResizeable(bool on); void SetBordedLess(bool on); void SetWindowIcon(const char* pFilePath) const; @@ -65,19 +72,14 @@ class Window void Update(); - bool IsFocused() const { return m_isFocused; } - - bool ShouldClose() const { return m_isClosed; } - void Close(bool bPushSdlEvent = true); public: - // Window + // Delegates Delegate OnDropFile; MulticastDelegate OnResize; private: SDL_Window* m_pSDLWindow = nullptr; bool m_isClosed = false; - bool m_isFocused = false; }; } \ No newline at end of file diff --git a/Engine/Source/Runtime/Window/WindowManager.cpp b/Engine/Source/Runtime/Window/WindowManager.cpp new file mode 100644 index 00000000..d8a5d1e1 --- /dev/null +++ b/Engine/Source/Runtime/Window/WindowManager.cpp @@ -0,0 +1,45 @@ +#include "WindowManager.h" + +#include "Base/Template.h" +#include "Window.h" + +#include + +namespace engine +{ + +WindowManager::WindowManager() +{ + Window::Init(); +} + +WindowManager::~WindowManager() +{ + Window::Shutdown(); +} + +Window* WindowManager::GetWindow(void* handle) const +{ + auto itWindow = m_mapWindows.find(handle); + return itWindow != m_mapWindows.end() ? itWindow->second.get() : nullptr; +} + +void WindowManager::AddWindow(std::unique_ptr pWindow) +{ + m_mapWindows[pWindow->GetHandle()] = cd::MoveTemp(pWindow); +} + +void WindowManager::RemoveWindow(void* handle) +{ + m_mapWindows.erase(handle); +} + +void WindowManager::Update() +{ + for (auto& [_, pWindow] : m_mapWindows) + { + pWindow->Update(); + } +} + +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Window/WindowManager.h b/Engine/Source/Runtime/Window/WindowManager.h new file mode 100644 index 00000000..258dcf04 --- /dev/null +++ b/Engine/Source/Runtime/Window/WindowManager.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +namespace engine +{ + +class Window; + +class WindowManager final +{ +public: + WindowManager(); + WindowManager(const WindowManager&) = delete; + WindowManager& operator=(const WindowManager&) = delete; + WindowManager(WindowManager&&) = default; + WindowManager& operator=(WindowManager&&) = default; + ~WindowManager(); + + engine::Window* GetWindow(void* handle) const; + void AddWindow(std::unique_ptr pWindow); + void RemoveWindow(void* handle); + + void Update(); + +private: + std::map> m_mapWindows; +}; + +} \ No newline at end of file