diff --git a/Engine/Source/Runtime/Display/CameraController.cpp b/Engine/Source/Editor/Camera/EditorCameraController.cpp similarity index 78% rename from Engine/Source/Runtime/Display/CameraController.cpp rename to Engine/Source/Editor/Camera/EditorCameraController.cpp index 10bf3b51..7c1651c5 100644 --- a/Engine/Source/Runtime/Display/CameraController.cpp +++ b/Engine/Source/Editor/Camera/EditorCameraController.cpp @@ -1,4 +1,4 @@ -#include "CameraController.h" +#include "EditorCameraController.h" #include "ECWorld/CameraComponent.h" #include "ECWorld/SceneWorld.h" @@ -13,15 +13,15 @@ namespace engine { -CameraController::CameraController( +EditorCameraController::EditorCameraController( const SceneWorld* pSceneWorld, float sensitivity, float movement_speed) - : CameraController(pSceneWorld, sensitivity, sensitivity, movement_speed) + : EditorCameraController(pSceneWorld, sensitivity, sensitivity, movement_speed) { } -CameraController::CameraController( +EditorCameraController::EditorCameraController( const SceneWorld* pSceneWorld, float horizontal_sensitivity, float vertical_sensitivity, @@ -35,14 +35,14 @@ CameraController::CameraController( assert(pSceneWorld); } -void CameraController::CameraToController() +void EditorCameraController::CameraToController() { m_eye = GetMainCameraTransform().GetTranslation(); m_lookAt = CameraComponent::GetLookAt(GetMainCameraTransform()); m_up = CameraComponent::GetUp(GetMainCameraTransform()); } -void CameraController::ControllerToCamera() +void EditorCameraController::ControllerToCamera() { cd::Vec3f eye = m_eye; cd::Vec3f lookAt = m_lookAt; @@ -86,12 +86,9 @@ void CameraController::ControllerToCamera() pTransformComponent->Build(); } -void CameraController::Update(float deltaTime) +void EditorCameraController::Update(float deltaTime) { Moving(); - bool isAnyMouseButtonPressed = engine::Input::Get().IsMouseLBPressed() || engine::Input::Get().IsMouseMBPressed() || engine::Input::Get().IsMouseRBPressed(); - bool isAnyDirectionMouseMoved = 0 != engine::Input::Get().GetMousePositionOffsetX() || 0 != engine::Input::Get().GetMousePositionOffsetY(); - m_isMouseMovedInView = isAnyMouseButtonPressed && isAnyDirectionMouseMoved; if (Input::Get().IsKeyPressed(KeyCode::z)) { @@ -183,7 +180,7 @@ void CameraController::Update(float deltaTime) Yaw(m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); } - if (Input::Get().IsMouseLBPressed() && m_isInViewScene && !ImGuizmo::IsUsing()) + if (Input::Get().IsMouseLBPressed() && !ImGuizmo::IsUsing()) { m_isTracking = false; PitchLocal(m_verticalSensitivity * Input::Get().GetMousePositionOffsetY() * deltaTime); @@ -192,76 +189,76 @@ void CameraController::Update(float deltaTime) } } -void CameraController::SetMovementSpeed(float speed) +void EditorCameraController::SetMovementSpeed(float speed) { m_movementSpeed = speed; } -void CameraController::SetSensitivity(float horizontal, float verticle) +void EditorCameraController::SetSensitivity(float horizontal, float verticle) { m_horizontalSensitivity = horizontal; m_verticalSensitivity = verticle; } -void CameraController::SetHorizontalSensitivity(float sensitivity) +void EditorCameraController::SetHorizontalSensitivity(float sensitivity) { m_horizontalSensitivity = sensitivity; } -void CameraController::SetVerticalSensitivity(float sensitivity) +void EditorCameraController::SetVerticalSensitivity(float sensitivity) { m_verticalSensitivity = sensitivity; } -engine::CameraComponent* CameraController::GetMainCameraComponent() const +engine::CameraComponent* EditorCameraController::GetMainCameraComponent() const { return m_pSceneWorld->GetCameraComponent(m_pSceneWorld->GetMainCameraEntity()); } -engine::TransformComponent* CameraController::GetMainCameraTransformComponent() const +engine::TransformComponent* EditorCameraController::GetMainCameraTransformComponent() const { return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity()); } -const cd::Transform& CameraController::GetMainCameraTransform() +const cd::Transform& EditorCameraController::GetMainCameraTransform() { return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity())->GetTransform(); } -void CameraController::MoveForward(float amount) +void EditorCameraController::MoveForward(float amount) { m_eye = m_eye + m_lookAt * amount; ControllerToCamera(); } -void CameraController::MoveBackward(float amount) +void EditorCameraController::MoveBackward(float amount) { MoveForward(-amount); } -void CameraController::MoveLeft(float amount) +void EditorCameraController::MoveLeft(float amount) { m_eye = m_eye + m_lookAt.Cross(m_up) * amount; ControllerToCamera(); } -void CameraController::MoveRight(float amount) +void EditorCameraController::MoveRight(float amount) { MoveLeft(-amount); } -void CameraController::MoveUp(float amount) +void EditorCameraController::MoveUp(float amount) { m_eye = m_eye + cd::Vec3f(0.0f, 1.0f, 0.0f) * amount; ControllerToCamera(); } -void CameraController::MoveDown(float amount) +void EditorCameraController::MoveDown(float amount) { MoveUp(-amount); } -void CameraController::Rotate(const cd::Vec3f& axis, float angleDegrees) +void EditorCameraController::Rotate(const cd::Vec3f& axis, float angleDegrees) { cd::Quaternion rotation = cd::Quaternion::FromAxisAngle(axis, cd::Math::DegreeToRadian(angleDegrees)); m_lookAt = rotation * m_lookAt; @@ -269,43 +266,43 @@ void CameraController::Rotate(const cd::Vec3f& axis, float angleDegrees) ControllerToCamera(); } -void CameraController::Rotate(float x, float y, float z, float angleDegrees) +void EditorCameraController::Rotate(float x, float y, float z, float angleDegrees) { Rotate(cd::Vec3f(x, y, z), angleDegrees); } -void CameraController::Yaw(float angleDegrees) +void EditorCameraController::Yaw(float angleDegrees) { Rotate(0.0f, 1.0f, 0.0f, angleDegrees); } -void CameraController::Pitch(float angleDegrees) +void EditorCameraController::Pitch(float angleDegrees) { Rotate(1.0f, 0.0f, 0.0f, angleDegrees); } -void CameraController::Roll(float angleDegrees) +void EditorCameraController::Roll(float angleDegrees) { Rotate(0.0f, 0.0f, 1.0f, angleDegrees); } -void CameraController::YawLocal(float angleDegrees) +void EditorCameraController::YawLocal(float angleDegrees) { Rotate(m_up, angleDegrees); } -void CameraController::PitchLocal(float angleDegrees) +void EditorCameraController::PitchLocal(float angleDegrees) { Rotate(m_up.Cross(m_lookAt), angleDegrees); } -void CameraController::RollLocal(float angleDegrees) +void EditorCameraController::RollLocal(float angleDegrees) { Rotate(m_lookAt, angleDegrees); } -void CameraController::ElevationChanging(float angleDegrees) +void EditorCameraController::ElevationChanging(float angleDegrees) { m_elevation += angleDegrees / 360.0f * cd::Math::PI; if (m_elevation > cd::Math::PI) @@ -319,7 +316,7 @@ void CameraController::ElevationChanging(float angleDegrees) ControllerToCamera(); } -void CameraController::AzimuthChanging(float angleDegrees) +void EditorCameraController::AzimuthChanging(float angleDegrees) { m_azimuth -= angleDegrees / 360.0f * cd::Math::PI; if (m_azimuth > cd::Math::PI) @@ -333,7 +330,7 @@ void CameraController::AzimuthChanging(float angleDegrees) ControllerToCamera(); } -void CameraController::SynchronizeTrackingCamera() +void EditorCameraController::SynchronizeTrackingCamera() { m_lookAtPoint = m_lookAt * m_distanceFromLookAt + m_eye; m_elevation = std::asin(-m_lookAt.y()); @@ -356,13 +353,14 @@ void CameraController::SynchronizeTrackingCamera() } } -void CameraController::CameraFocus() +void EditorCameraController::CameraFocus() { Entity selectedEntity = m_pSceneWorld->GetSelectedEntity(); if (selectedEntity == INVALID_ENTITY) { return; } + if (TransformComponent* pTransform = m_pSceneWorld->GetTransformComponent(selectedEntity)) { m_isMoving = true; @@ -381,7 +379,7 @@ void CameraController::CameraFocus() } } -void CameraController::Moving() +void EditorCameraController::Moving() { if (m_isMoving) { @@ -399,13 +397,13 @@ void CameraController::Moving() } } -void CameraController::Panning(float x, float y) +void EditorCameraController::Panning(float x, float y) { MoveLeft(x); m_eye = m_eye + m_up * y; } -void CameraController::MoveToPosition(cd::Point position, cd::Vec3f rotation) +void EditorCameraController::MoveToPosition(cd::Point position, cd::Vec3f rotation) { m_isMoving = true; m_eyeDestination = position; diff --git a/Engine/Source/Runtime/Display/CameraController.h b/Engine/Source/Editor/Camera/EditorCameraController.h similarity index 77% rename from Engine/Source/Runtime/Display/CameraController.h rename to Engine/Source/Editor/Camera/EditorCameraController.h index b95c49bd..017ca928 100644 --- a/Engine/Source/Runtime/Display/CameraController.h +++ b/Engine/Source/Editor/Camera/EditorCameraController.h @@ -10,18 +10,18 @@ namespace engine class CameraComponent; class SceneWorld; -class CameraController final +class EditorCameraController final { public: - CameraController() = delete; - explicit CameraController(const SceneWorld* pSceneWorld, float sensitivity, float movement_speed); - explicit CameraController(const SceneWorld* pSceneWorld, float horizontal_sensitivity, float vertical_sensitivity, float movement_speed); - ~CameraController() = default; + EditorCameraController() = delete; + explicit EditorCameraController(const SceneWorld* pSceneWorld, float sensitivity, float movement_speed); + explicit EditorCameraController(const SceneWorld* pSceneWorld, float horizontal_sensitivity, float vertical_sensitivity, float movement_speed); + ~EditorCameraController() = default; - CameraController(const CameraController&) = delete; - CameraController(CameraController&&) = delete; - CameraController& operator=(const CameraController&) = delete; - CameraController& operator=(CameraController&&) = delete; + EditorCameraController(const EditorCameraController&) = delete; + EditorCameraController(EditorCameraController&&) = delete; + EditorCameraController& operator=(const EditorCameraController&) = delete; + EditorCameraController& operator=(EditorCameraController&&) = delete; void Update(float deltaTime); @@ -69,11 +69,6 @@ class CameraController final void MoveToPosition(cd::Point position, cd::Vec3f lookAt); - // TODO : generic solution to process mouse / key input events for UI panels in different areas. - void SetIsInViewScene(bool isIn) { m_isInViewScene = isIn; } - - bool GetViewIsMoved() { return m_isMouseMovedInView; } - private: engine::CameraComponent* GetMainCameraComponent() const; engine::TransformComponent* GetMainCameraTransformComponent() const; @@ -103,7 +98,6 @@ class CameraController final bool m_isTracking = false; bool m_isMoving = false; - bool m_isInViewScene = false; bool m_isMouseMovedInView = false; }; diff --git a/Engine/Source/Editor/EditorApp.cpp b/Engine/Source/Editor/EditorApp.cpp index 50c08048..82093927 100644 --- a/Engine/Source/Editor/EditorApp.cpp +++ b/Engine/Source/Editor/EditorApp.cpp @@ -1,9 +1,10 @@ #include "EditorApp.h" #include "Application/Engine.h" -#include "Display/CameraController.h" +#include "Camera/EditorCameraController.h" #include "ECWorld/SceneWorld.h" #include "ImGui/ImGuiContextInstance.h" +#include "ImGui/ImGuiContextManager.h" #include "ImGui/Localization.h" #include "ImGui/UILayers/DebugPanel.h" #include "ImGui/UILayers/Profiler.h" @@ -80,7 +81,9 @@ void EditorApp::Init(engine::EngineInitArgs initArgs) CD_ERROR("Failed to open CSV file"); } - m_pWindowManager = std::make_unique(); + // Init Systems + InitWindowManager(); + m_pImGuiContextManager = std::make_unique(); // Phase 1 - Splash // * Compile uber shader permutations automatically when initialization or detect changes @@ -160,23 +163,16 @@ void EditorApp::InitEditorImGuiContext(engine::Language language) { assert(GetMainWindow() && "Init window before imgui context"); - const bool enableDock = true; - const bool enableViewport = true; - m_pEditorImGuiContext = std::make_unique(GetMainWindow()->GetWidth(), GetMainWindow()->GetHeight(), enableDock, enableViewport); - RegisterImGuiUserData(m_pEditorImGuiContext.get()); - - // TODO : more font files to load and switch dynamically. - std::vector ttfFileNames = { "FanWunMing-SB.ttf" }; - m_pEditorImGuiContext->LoadFontFiles(ttfFileNames, language); - - // Bind event callbacks from current available input devices. - GetMainWindow()->OnResize.Bind(m_pEditorImGuiContext.get()); - - // Set style settings. + m_pEditorImGuiContext = m_pImGuiContextManager->AddImGuiContext(engine::StringCrc("Editor")); + m_pEditorImGuiContext->InitBackendUserData(GetMainWindow(), m_pRenderContext.get()); + m_pEditorImGuiContext->SetDisplaySize(GetMainWindow()->GetWidth(), GetMainWindow()->GetHeight()); + m_pEditorImGuiContext->LoadFontFiles({ "FanWunMing-SB.ttf" }, language); m_pEditorImGuiContext->SetImGuiThemeColor(engine::ThemeColor::Dark); + m_pEditorImGuiContext->EnableDock(); + m_pEditorImGuiContext->EnableViewport(); // Init viewport settings. - if (enableViewport) + if (m_pEditorImGuiContext->IsViewportEnable()) { m_pEditorImGuiContext->InitViewport(m_pWindowManager.get(), m_pRenderContext.get()); ImGuiViewport* pMainViewport = ImGui::GetMainViewport(); @@ -185,6 +181,8 @@ void EditorApp::InitEditorImGuiContext(engine::Language language) pMainViewport->PlatformHandleRaw = GetMainWindow()->GetHandle(); m_pEditorImGuiContext->UpdateViewport(); } + + GetMainWindow()->OnResize.Bind(m_pEditorImGuiContext); } void EditorApp::InitEditorUILayers() @@ -228,38 +226,22 @@ void EditorApp::InitEngineImGuiContext(engine::Language language) constexpr engine::StringCrc sceneRenderTarget("SceneRenderTarget"); engine::RenderTarget* pSceneRenderTarget = m_pRenderContext->GetRenderTarget(sceneRenderTarget); - m_pEngineImGuiContext = std::make_unique(pSceneRenderTarget->GetWidth(), pSceneRenderTarget->GetHeight()); - RegisterImGuiUserData(m_pEngineImGuiContext.get()); - - std::vector ttfFileNames = { "FanWunMing-SB.ttf" }; - m_pEngineImGuiContext->LoadFontFiles(ttfFileNames, language); - + m_pEngineImGuiContext = m_pImGuiContextManager->AddImGuiContext(engine::StringCrc("Engine")); + m_pEngineImGuiContext->InitBackendUserData(GetMainWindow(), m_pRenderContext.get()); + m_pEngineImGuiContext->SetDisplaySize(pSceneRenderTarget->GetWidth(), pSceneRenderTarget->GetHeight()); + m_pEngineImGuiContext->LoadFontFiles({ "FanWunMing-SB.ttf" }, language); m_pEngineImGuiContext->SetImGuiThemeColor(engine::ThemeColor::Light); - - pSceneRenderTarget->OnResize.Bind(m_pEngineImGuiContext.get()); + + pSceneRenderTarget->OnResize.Bind(m_pEngineImGuiContext); } void EditorApp::InitEngineUILayers() { //m_pEngineImGuiContext->AddDynamicLayer(std::make_unique("DebugPanel")); - - auto pImGuizmoView = std::make_unique("ImGuizmoView"); - pImGuizmoView->SetSceneView(m_pSceneView); - m_pEngineImGuiContext->AddDynamicLayer(cd::MoveTemp(pImGuizmoView)); + m_pEngineImGuiContext->AddDynamicLayer(std::make_unique("ImGuizmoView")); //m_pEngineImGuiContext->AddDynamicLayer(std::make_unique("TestNodeEditor")); } -void EditorApp::RegisterImGuiUserData(engine::ImGuiContextInstance* pImGuiContext) -{ - assert(GetMainWindow() && m_pRenderContext); - - ImGuiIO& io = ImGui::GetIO(); - assert(io.UserData == pImGuiContext); - - io.BackendPlatformUserData = GetMainWindow(); - io.BackendRendererUserData = m_pRenderContext.get(); -} - void EditorApp::InitECWorld() { m_pSceneWorld = std::make_unique(); @@ -561,7 +543,7 @@ void EditorApp::InitShaderPrograms(bool compileAllShaders) const void EditorApp::InitEditorController() { // Controller for Input events. - m_pViewportCameraController = std::make_unique( + m_pViewportCameraController = std::make_unique( m_pSceneWorld.get(), 12.0f /* horizontal sensitivity */, 12.0f /* vertical sensitivity */); @@ -617,6 +599,7 @@ bool EditorApp::Update(float deltaTime) } engine::Input::Get().Update(); + m_pEditorImGuiContext->BeginFrame(); m_pEditorImGuiContext->Update(deltaTime); m_pWindowManager->Update(); m_pSceneWorld->Update(); @@ -638,35 +621,40 @@ bool EditorApp::Update(float deltaTime) } } - if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - } + auto [sceneRectX, sceneRectY] = m_pSceneView->GetRectPosition(); + m_pEditorImGuiContext->EndFrame(); if (m_pEngineImGuiContext) { - //GetMainWindow()->SetMouseVisible(m_pSceneView->IsShowMouse(), m_pSceneView->GetMouseFixedPositionX(), m_pSceneView->GetMouseFixedPositionY()); if (m_pViewportCameraController) { m_pViewportCameraController->Update(deltaTime); } + // Do Screen Space Smoothing - if (pTerrainComponent && m_pSceneView->IsTerrainEditMode() && engine::Input::Get().IsMouseLBPressed()) + //if (pTerrainComponent && m_pSceneView->IsTerrainEditMode() && engine::Input::Get().IsMouseLBPressed()) + //{ + // float screenSpaceX = 2.0f * static_cast(engine::Input::Get().GetMousePositionX() - m_pSceneView->GetWindowPosX()) / + // m_pSceneView->GetRenderTarget()->GetWidth() - 1.0f; + // float screenSpaceY = 1.0f - 2.0f * static_cast(engine::Input::Get().GetMousePositionY() - m_pSceneView->GetWindowPosY()) / + // m_pSceneView->GetRenderTarget()->GetHeight(); + // + // engine::TransformComponent* pCameraTransformComponent = m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity()); + // cd::Vec3f camPos = pCameraTransformComponent->GetTransform().GetTranslation(); + // + // pTerrainComponent->ScreenSpaceSmooth(screenSpaceX, screenSpaceY, pMainCameraComponent->GetProjectionMatrix().Inverse(), + // pMainCameraComponent->GetViewMatrix().Inverse(), camPos); + //} + + m_pEngineImGuiContext->BeginFrame(); + if (!m_pEngineImGuiContext->IsViewportEnable()) { - float screenSpaceX = 2.0f * static_cast(engine::Input::Get().GetMousePositionX() - m_pSceneView->GetWindowPosX()) / - m_pSceneView->GetRenderTarget()->GetWidth() - 1.0f; - float screenSpaceY = 1.0f - 2.0f * static_cast(engine::Input::Get().GetMousePositionY() - m_pSceneView->GetWindowPosY()) / - m_pSceneView->GetRenderTarget()->GetHeight(); - - engine::TransformComponent* pCameraTransformComponent = m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity()); - cd::Vec3f camPos = pCameraTransformComponent->GetTransform().GetTranslation(); - - pTerrainComponent->ScreenSpaceSmooth(screenSpaceX, screenSpaceY, pMainCameraComponent->GetProjectionMatrix().Inverse(), - pMainCameraComponent->GetViewMatrix().Inverse(), camPos); + auto [windowX, windowY] = m_pMainWindow->GetPosition(); + sceneRectX -= windowX; + sceneRectY -= windowY; } - m_pEngineImGuiContext->SetWindowPosOffset(m_pSceneView->GetWindowPosX(), m_pSceneView->GetWindowPosY()); + m_pEngineImGuiContext->SetRectPosition(sceneRectX, sceneRectY); m_pEngineImGuiContext->Update(deltaTime); UpdateMaterials(); @@ -682,8 +670,9 @@ bool EditorApp::Update(float deltaTime) pRenderer->Render(deltaTime); } } - } + m_pEngineImGuiContext->EndFrame(); + } m_pRenderContext->EndFrame(); engine::Input::Get().FlushInputs(); @@ -691,4 +680,36 @@ bool EditorApp::Update(float deltaTime) return !GetMainWindow()->ShouldClose(); } +void EditorApp::InitWindowManager() +{ + m_pWindowManager = std::make_unique(); + m_pWindowManager->OnMouseMove.Bind(this); +} + +void EditorApp::HandleMouseMotionEvent(uint32_t windowID, int x, int y) +{ + engine::Input::Get().SetMousePositionX(x); + engine::Input::Get().SetMousePositionY(y); + + //auto [screenX, screenY] = engine::Input::GetGloalMousePosition(); + ////auto* pWindow = m_pWindowManager->GetWindow(windowID); + //for (auto& [_, pImGuiContext] : m_pImGuiContextManager->GetAllImGuiContexts()) + //{ + // if (pImGuiContext->IsViewportEnable()) + // { + // // In multiple viewport mode, it always use global screen space coordinates. + // engine::Input::Get().SetMousePositionX(screenX); + // engine::Input::Get().SetMousePositionY(screenY); + // } + // else + // { + // if (pImGuiContext->IsInsideDisplayRect()) + // { + // engine::Input::Get().SetMousePositionX(x); + // engine::Input::Get().SetMousePositionY(y); + // } + // } + //} +} + } diff --git a/Engine/Source/Editor/EditorApp.h b/Engine/Source/Editor/EditorApp.h index 0fb73e87..dd6bfedc 100644 --- a/Engine/Source/Editor/EditorApp.h +++ b/Engine/Source/Editor/EditorApp.h @@ -10,10 +10,11 @@ namespace engine { class AABBRenderer; -class CameraController; +class EditorCameraController; class FlybyCamera; class ImGuiBaseLayer; class ImGuiContextInstance; +class ImGuiContextManager; class Window; class WindowManager; class RenderContext; @@ -46,30 +47,35 @@ class EditorApp final : public engine::IApplication virtual bool Update(float deltaTime) override; virtual void Shutdown() override; + // Window Management + void InitWindowManager(); engine::Window* GetMainWindow() const { return m_pMainWindow; } engine::WindowManager* GetWindowManager() const { return m_pWindowManager.get(); } + void HandleMouseMotionEvent(uint32_t windowID, int x, int y); + // Rendering Management void InitRenderContext(engine::GraphicsBackend backend, void* hwnd = nullptr); + void InitShaderPrograms(bool compileAllShaders = false) const; void InitEditorRenderers(); - void InitEngineRenderers(); - + void AddEditorRenderer(std::unique_ptr pRenderer); void EditorRenderersWarmup(); - void EngineRenderersWarmup(); - void InitShaderPrograms(bool compileAllShaders = false) const; - void AddEditorRenderer(std::unique_ptr pRenderer); + void InitEngineRenderers(); void AddEngineRenderer(std::unique_ptr pRenderer); + void EngineRenderersWarmup(); + // ImGui Management void InitEditorImGuiContext(engine::Language language); void InitEditorUILayers(); void InitEngineImGuiContext(engine::Language language); void InitEngineUILayers(); - void RegisterImGuiUserData(engine::ImGuiContextInstance* pImGuiContext); + // Scene World void InitECWorld(); + + // Misc void InitEditorController(); - bool IsAtmosphericScatteringEnable() const; private: @@ -91,8 +97,9 @@ class EditorApp final : public engine::IApplication std::unique_ptr m_pWindowManager; // ImGui - std::unique_ptr m_pEditorImGuiContext; - std::unique_ptr m_pEngineImGuiContext; + engine::ImGuiContextInstance* m_pEditorImGuiContext = nullptr; + engine::ImGuiContextInstance* m_pEngineImGuiContext = nullptr; + std::unique_ptr m_pImGuiContextManager; // Scene std::unique_ptr m_pSceneWorld; @@ -112,7 +119,7 @@ class EditorApp final : public engine::IApplication engine::Renderer* m_pAABBRenderer = nullptr; // Controllers for processing input events. - std::unique_ptr m_pViewportCameraController; + std::unique_ptr m_pViewportCameraController; std::unique_ptr m_pFileWatcher; }; diff --git a/Engine/Source/Editor/UILayers/EntityList.cpp b/Engine/Source/Editor/UILayers/EntityList.cpp index 8c6151c8..837d5c80 100644 --- a/Engine/Source/Editor/UILayers/EntityList.cpp +++ b/Engine/Source/Editor/UILayers/EntityList.cpp @@ -1,6 +1,6 @@ #include "EntityList.h" -#include "Display/CameraController.h" +#include "Camera/EditorCameraController.h" #include "ECWorld/SceneWorld.h" #include "ECWorld/World.h" #include "ImGui/IconFont/IconsMaterialDesignIcons.h" @@ -333,7 +333,7 @@ void EntityList::DrawEntity(engine::SceneWorld* pSceneWorld, engine::Entity enti if (ImGui::IsItemClicked()) { pSceneWorld->SetSelectedEntity(entity); - if (ImGui::IsMouseDoubleClicked(0)) + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { if (m_pCameraController) { diff --git a/Engine/Source/Editor/UILayers/EntityList.h b/Engine/Source/Editor/UILayers/EntityList.h index 50290b13..b62cda50 100644 --- a/Engine/Source/Editor/UILayers/EntityList.h +++ b/Engine/Source/Editor/UILayers/EntityList.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include "ECWorld/Entity.h" @@ -8,7 +10,7 @@ namespace engine { -class CameraController; +class EditorCameraController; class SceneWorld; } @@ -28,12 +30,11 @@ class EntityList : public engine::ImGuiBaseLayer void AddEntity(engine::SceneWorld* pSceneWorld); void DrawEntity(engine::SceneWorld* pSceneWorld, engine::Entity entity); - void SetCameraController(engine::CameraController* pCameraController) { m_pCameraController = pCameraController; } - + void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } private: ImGuiTextFilter m_entityFilter; - engine::CameraController* m_pCameraController = nullptr; + engine::EditorCameraController* m_pCameraController = nullptr; }; } diff --git a/Engine/Source/Editor/UILayers/GameView.h b/Engine/Source/Editor/UILayers/GameView.h index 3dd9989b..110bfa4b 100644 --- a/Engine/Source/Editor/UILayers/GameView.h +++ b/Engine/Source/Editor/UILayers/GameView.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include diff --git a/Engine/Source/Editor/UILayers/ImGuizmoView.cpp b/Engine/Source/Editor/UILayers/ImGuizmoView.cpp index d34fbef2..24ff7f9c 100644 --- a/Engine/Source/Editor/UILayers/ImGuizmoView.cpp +++ b/Engine/Source/Editor/UILayers/ImGuizmoView.cpp @@ -5,11 +5,10 @@ #include "ECWorld/StaticMeshComponent.h" #include "ECWorld/TransformComponent.h" #include "ImGui/ImGuiContextInstance.h" - -// TODO : can use StringCrc to access other UILayers from ImGuiContextInstance. #include "UILayers/SceneView.h" #include +#include #include namespace editor @@ -21,6 +20,7 @@ ImGuizmoView::~ImGuizmoView() void ImGuizmoView::Init() { + m_sceneViewID = ImHashStr("SceneView"); ImGuizmo::SetGizmoSizeClipSpace(0.25f); } @@ -40,7 +40,9 @@ void ImGuizmoView::Update() return; } - ImGuizmo::OPERATION operation = m_pSceneView->GetImGuizmoOperation(); + constexpr engine::StringCrc sceneViewName("SceneView"); + auto* pSceneView = reinterpret_cast(GetImGuiContextInstance()->GetLayerByName(sceneViewName)); + ImGuizmo::OPERATION operation = pSceneView->GetImGuizmoOperation(); const engine::CameraComponent* pCameraComponent = pSceneWorld->GetCameraComponent(pSceneWorld->GetMainCameraEntity()); ImGuizmo::BeginFrame(); diff --git a/Engine/Source/Editor/UILayers/ImGuizmoView.h b/Engine/Source/Editor/UILayers/ImGuizmoView.h index b84cfe01..44b9ef66 100644 --- a/Engine/Source/Editor/UILayers/ImGuizmoView.h +++ b/Engine/Source/Editor/UILayers/ImGuizmoView.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" namespace editor @@ -14,10 +16,8 @@ class ImGuizmoView : public engine::ImGuiBaseLayer virtual void Init() override; virtual void Update() override; - void SetSceneView(const SceneView* pSceneView) { m_pSceneView = pSceneView; } - private: - const SceneView* m_pSceneView = nullptr; + uint32_t m_sceneViewID; }; } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/Inspector.h b/Engine/Source/Editor/UILayers/Inspector.h index f224dbb0..9813c7c8 100644 --- a/Engine/Source/Editor/UILayers/Inspector.h +++ b/Engine/Source/Editor/UILayers/Inspector.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include "ImGui/ImGuiUtils.hpp" diff --git a/Engine/Source/Editor/UILayers/MainMenu.cpp b/Engine/Source/Editor/UILayers/MainMenu.cpp index f21c2ac2..36313244 100644 --- a/Engine/Source/Editor/UILayers/MainMenu.cpp +++ b/Engine/Source/Editor/UILayers/MainMenu.cpp @@ -1,6 +1,6 @@ #include "MainMenu.h" -#include "Display/CameraController.h" +#include "Camera/EditorCameraController.h" #include "ECWorld/SceneWorld.h" #include "EditorApp.h" #include "ImGui/ImGuiContextInstance.h" @@ -32,8 +32,8 @@ void MainMenu::FileMenu() { if (ImGui::MenuItem(CD_TEXT("TEXT_NEW"), "Ctrl N")) { - m_pCreatProjectDialog->SetTitle("Creat"); - m_pCreatProjectDialog->Open(); + m_pCreateProjectDialog->SetTitle("Creat"); + m_pCreateProjectDialog->Open(); } if (ImGui::MenuItem("Open", "Ctrl O")) { @@ -117,7 +117,7 @@ void MainMenu::EditMenu() void MainMenu::ViewMenu() { - auto FrameEntities = [](engine::SceneWorld* pSceneWorld, const std::vector& entities, engine::CameraController* pCameraController) + auto FrameEntities = [](engine::SceneWorld* pSceneWorld, const std::vector& entities, engine::EditorCameraController* pCameraController) { if (entities.empty()) { @@ -245,7 +245,7 @@ void MainMenu::AboutMenu() void MainMenu::Init() { - m_pCreatProjectDialog = std::make_unique(); + m_pCreateProjectDialog = std::make_unique(); } void MainMenu::Update() @@ -261,10 +261,10 @@ void MainMenu::Update() ImGui::EndMainMenuBar(); } - m_pCreatProjectDialog->Display(); + m_pCreateProjectDialog->Display(); - if (engine::Input::Get().ContainsModifier(engine::KeyMod::KMOD_CTRL) - && engine::Input::Get().IsKeyPressed(engine::KeyCode::q)) + if ((ImGui::IsKeyPressed(ImGuiKey_LeftCtrl) || ImGui::IsKeyPressed(ImGuiKey_RightCtrl)) + && ImGui::IsKeyPressed(ImGuiKey_Q)) { if (auto* pMainWindow = reinterpret_cast(ImGui::GetIO().BackendPlatformUserData)) { diff --git a/Engine/Source/Editor/UILayers/MainMenu.h b/Engine/Source/Editor/UILayers/MainMenu.h index 55437e5f..ca8817f6 100644 --- a/Engine/Source/Editor/UILayers/MainMenu.h +++ b/Engine/Source/Editor/UILayers/MainMenu.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include @@ -12,7 +14,7 @@ class FileBrowser; namespace engine { -class CameraController; +class EditorCameraController; } @@ -35,11 +37,11 @@ class MainMenu : public engine::ImGuiBaseLayer void BuildMenu(); void AboutMenu(); - void SetCameraController(engine::CameraController* pCameraController) { m_pCameraController = pCameraController; } + void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } private: - std::unique_ptr m_pCreatProjectDialog; - engine::CameraController* m_pCameraController = nullptr; + std::unique_ptr m_pCreateProjectDialog; + engine::EditorCameraController* m_pCameraController = nullptr; }; } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/OutputLog.h b/Engine/Source/Editor/UILayers/OutputLog.h index 8b130f2c..8494620c 100644 --- a/Engine/Source/Editor/UILayers/OutputLog.h +++ b/Engine/Source/Editor/UILayers/OutputLog.h @@ -1,6 +1,8 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" -#include "imgui.h" +#include #include diff --git a/Engine/Source/Editor/UILayers/SceneView.cpp b/Engine/Source/Editor/UILayers/SceneView.cpp index 85c4138f..c8a5b96f 100644 --- a/Engine/Source/Editor/UILayers/SceneView.cpp +++ b/Engine/Source/Editor/UILayers/SceneView.cpp @@ -5,8 +5,8 @@ #include "ECWorld/SceneWorld.h" #include "ECWorld/StaticMeshComponent.h" #include "ECWorld/TransformComponent.h" -#include "ImGui/ImGuiContextInstance.h" #include "ImGui/IconFont/IconsMaterialDesignIcons.h" +#include "ImGui/ImGuiContextInstance.h" #include "Log/Log.h" #include "Material/ShaderSchema.h" #include "Math/Ray.hpp" @@ -239,25 +239,12 @@ void SceneView::UpdateToolMenuButtons() void SceneView::PickSceneMesh(float regionWidth, float regionHeight) { - if (m_currentOperation != SelectOperation) - { - return; - } - - float screenX = static_cast(m_mouseFixedPositionX - GetWindowPosX()); - float screenY = static_cast(m_mouseFixedPositionY - GetWindowPosY()); - float screenWidth = static_cast(regionWidth); - float screenHeight = static_cast(regionHeight); - if (screenX < 0.0f || screenX > screenWidth || - screenY < 0.0f || screenY > screenHeight) - { - return; - } - // Loop through scene's all static meshes' AABB to test intersections with Ray. engine::SceneWorld* pSceneWorld = GetSceneWorld(); engine::CameraComponent* pCameraComponent = pSceneWorld->GetCameraComponent(pSceneWorld->GetMainCameraEntity()); - cd::Ray pickRay = pCameraComponent->EmitRay(screenX, screenY, screenWidth, screenHeight); + ImVec2 mousePos = ImGui::GetMousePos(); + auto [scenePosX, scenePosY] = GetRectPosition(); + cd::Ray pickRay = pCameraComponent->EmitRay(mousePos.x - scenePosX, mousePos.y - scenePosY, regionWidth, regionHeight); float minRayTime = FLT_MAX; engine::Entity nearestEntity = engine::INVALID_ENTITY; @@ -328,83 +315,69 @@ void SceneView::Update() } } - ImVec2 windowPos = ImGui::GetWindowPos(); - ImVec2 mousePos = ImGui::GetMousePos(); - bool isMouseInsideSeneView = false; - cd::Vec2f rightDown(windowPos.x + regionSize.x, windowPos.y + regionSize.y); - - // Check if mouse hover on the area of SceneView so it can control. - ImVec2 cursorPosition = ImGui::GetCursorPos(); - ImVec2 sceneViewPosition = ImGui::GetWindowPos() + cursorPosition; - SetWindowPos(sceneViewPosition.x, sceneViewPosition.y); - if (ImGui::IsWindowHovered()) - { - isMouseInsideSeneView = true; - } - else - { - isMouseInsideSeneView = false; - } // Draw scene. ImGui::Image(reinterpret_cast(m_pRenderTarget->GetTextureHandle(0).idx), ImVec2(m_pRenderTarget->GetWidth(), m_pRenderTarget->GetHeight())); - // Check if there is a file to drop in the scene view to import assets automatically. - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* pPayload = ImGui::AcceptDragDropPayload("AssetFile", ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) - { - std::string filePath(static_cast(pPayload->Data)); - } - ImGui::EndDragDropTarget(); - } - ImGui::PopStyleVar(); - ImGui::End(); - bool isAnyMouseButtonPressed = engine::Input::Get().IsMouseLBPressed() || engine::Input::Get().IsMouseMBPressed() || engine::Input::Get().IsMouseRBPressed(); - if (isAnyMouseButtonPressed && !ImGuizmo::IsUsing()) + if (!ImGuizmo::IsUsing()) { - if (!m_isMouseDownFirstTime) - { - if (m_pCameraController->GetViewIsMoved()) - { - m_isUsingCamera = true; - } - if (engine::Input::Get().IsMouseLBPressed()) - { - m_isLeftClick = true; - } - return; - } - - m_isMouseDownFirstTime = false; - if (isMouseInsideSeneView && !m_isTerrainEditMode) - { - m_pCameraController->SetIsInViewScene(true); - m_isMouseShow = false; - } - else + bool isAnyMouseButtonDraging = ImGui::IsMouseDragging(ImGuiMouseButton_Left) || ImGui::IsMouseDragging(ImGuiMouseButton_Middle) || ImGui::IsMouseDragging(ImGuiMouseButton_Right); + if (isAnyMouseButtonDraging) { - m_pCameraController->SetIsInViewScene(false); + m_pCameraController; } } - else + + if (m_currentOperation == SelectOperation && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { - m_mouseFixedPositionX = engine::Input::Get().GetMousePositionX(); - m_mouseFixedPositionY = engine::Input::Get().GetMousePositionY(); - if (!m_isMouseShow && !m_isUsingCamera) - { - PickSceneMesh(regionWidth, regionHeight); - } - m_isMouseDownFirstTime = true; - m_isMouseShow = true; - m_isUsingCamera = false; - m_isLeftClick = false; + PickSceneMesh(regionWidth, regionHeight); } + + //if (isAnyMouseButtonPressed && !ImGuizmo::IsUsing()) + //{ + // if (!m_isMouseDownFirstTime) + // { + // if (m_pCameraController->GetViewIsMoved()) + // { + // m_isUsingCamera = true; + // } + // if (engine::Input::Get().IsMouseLBPressed()) + // { + // m_isLeftClick = true; + // } + // return; + // } + // + // m_isMouseDownFirstTime = false; + // if (isMouseInsideSeneView && !m_isTerrainEditMode) + // { + // m_pCameraController->SetIsInViewScene(true); + // m_isMouseShow = false; + // } + // else + // { + // m_pCameraController->SetIsInViewScene(false); + // } + //} + //else + //{ + // m_mouseFixedPositionX = engine::Input::Get().GetMousePositionX(); + // m_mouseFixedPositionY = engine::Input::Get().GetMousePositionY(); + // if (!m_isMouseShow && !m_isUsingCamera) + // { + // PickSceneMesh(regionWidth, regionHeight); + // } + // m_isMouseDownFirstTime = true; + // m_isMouseShow = true; + // m_isUsingCamera = false; + // m_isLeftClick = false; + //} - if (ImGui::IsMouseDoubleClicked(0) && engine::INVALID_ENTITY != pSceneWorld->GetSelectedEntity()) + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && + engine::INVALID_ENTITY != pSceneWorld->GetSelectedEntity()) { m_pCameraController->CameraFocus(); } diff --git a/Engine/Source/Editor/UILayers/SceneView.h b/Engine/Source/Editor/UILayers/SceneView.h index fbcb9e1f..783f777a 100644 --- a/Engine/Source/Editor/UILayers/SceneView.h +++ b/Engine/Source/Editor/UILayers/SceneView.h @@ -1,5 +1,7 @@ +#pragma once + +#include "Camera/EditorCameraController.h" #include "Core/Delegates/MulticastDelegate.hpp" -#include "Display/CameraController.h" #include "ECWorld/Entity.h" #include "ImGui/ImGuiBaseLayer.h" #include "Rendering/AABBRenderer.h" @@ -64,14 +66,9 @@ class SceneView : public engine::ImGuiBaseLayer bool IsTerrainEditMode() const { return m_isTerrainEditMode; } - bool IsFirstClick() const { return m_isMouseDownFirstTime; } - bool IsShowMouse() { return m_isMouseShow; } - uint32_t GetMouseFixedPositionX() const { return m_mouseFixedPositionX; } - uint32_t GetMouseFixedPositionY() const { return m_mouseFixedPositionY; } - - void SetCameraController(engine::CameraController* pCameraController) { m_pCameraController = pCameraController; } - + void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } const engine::RenderTarget* GetRenderTarget() const { return m_pRenderTarget; } + private: void UpdateToolMenuButtons(); void Update2DAnd3DButtons(); @@ -89,9 +86,6 @@ class SceneView : public engine::ImGuiBaseLayer bool m_is3DMode = true; bool m_isIBLActive = false; bool m_isTerrainEditMode = false; - bool m_isMouseShow = true; - bool m_isUsingCamera = false; - bool m_isLeftClick = false; RenderModeType m_renderMode = RenderModeType::Rendered; engine::Renderer* m_pSceneRenderer = nullptr; @@ -100,12 +94,7 @@ class SceneView : public engine::ImGuiBaseLayer engine::Renderer* m_pAABBRenderer = nullptr; engine::RenderTarget* m_pRenderTarget = nullptr; - bool m_isMouseDownFirstTime = true; - - int32_t m_mouseFixedPositionX = 0; - int32_t m_mouseFixedPositionY = 0; - - engine::CameraController* m_pCameraController = nullptr; + engine::EditorCameraController* m_pCameraController = nullptr; }; } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/SkeletonView.h b/Engine/Source/Editor/UILayers/SkeletonView.h index 21252484..f5a7a4ae 100644 --- a/Engine/Source/Editor/UILayers/SkeletonView.h +++ b/Engine/Source/Editor/UILayers/SkeletonView.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include "Scene/Bone.h" diff --git a/Engine/Source/Editor/UILayers/Splash.h b/Engine/Source/Editor/UILayers/Splash.h index 5843b3a6..0ff34456 100644 --- a/Engine/Source/Editor/UILayers/Splash.h +++ b/Engine/Source/Editor/UILayers/Splash.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" #include diff --git a/Engine/Source/Editor/UILayers/TestNodeEditor.h b/Engine/Source/Editor/UILayers/TestNodeEditor.h index 6630fa15..09ea89f1 100644 --- a/Engine/Source/Editor/UILayers/TestNodeEditor.h +++ b/Engine/Source/Editor/UILayers/TestNodeEditor.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" namespace ax::NodeEditor diff --git a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp index bf3e2545..5da3397e 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp +++ b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp @@ -5,18 +5,42 @@ #include "Rendering/RenderContext.h" #include +#include namespace engine { +ImGuiBaseLayer::ImGuiBaseLayer(const char* pName) + : m_pName(pName) +{ + m_id = ImHashStr(pName); +} + +ImGuiWindow* ImGuiBaseLayer::GetRootWindow() const +{ + return ImGui::FindWindowByID(m_id); +} + +std::pair ImGuiBaseLayer::GetRectPosition() const +{ + auto pos = GetRootWindow()->Pos; + return std::make_pair(pos.x, pos.y); +} + +std::pair ImGuiBaseLayer::GetRectSize() const +{ + auto size = GetRootWindow()->Size; + return std::make_pair(size.x, size.y); +} + ImGuiContextInstance* ImGuiBaseLayer::GetImGuiContextInstance() const { - return reinterpret_cast(ImGui::GetIO().UserData); + return static_cast(ImGui::GetIO().UserData); } RenderContext* ImGuiBaseLayer::GetRenderContext() const { - return reinterpret_cast(ImGui::GetIO().BackendRendererUserData); + return static_cast(ImGui::GetIO().BackendRendererUserData); } SceneWorld* ImGuiBaseLayer::GetSceneWorld() const diff --git a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h index 743d6b89..3e6e1de5 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h +++ b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h @@ -1,5 +1,10 @@ #pragma once +#include +#include + +struct ImGuiWindow; + namespace engine { @@ -10,7 +15,7 @@ class SceneWorld; class ImGuiBaseLayer { public: - ImGuiBaseLayer(const char* pName) : m_pName(pName) { } + ImGuiBaseLayer(const char* pName); ImGuiBaseLayer(const ImGuiBaseLayer&) = delete; ImGuiBaseLayer& operator=(const ImGuiBaseLayer&) = delete; ImGuiBaseLayer(ImGuiBaseLayer&&) = default; @@ -21,21 +26,23 @@ class ImGuiBaseLayer virtual void Update() = 0; const char* GetName() const { return m_pName; } - float GetWindowPosX() const { return m_windowPosX; } - float GetWindowPosY() const { return m_windowPosY; } - void SetWindowPos(float x, float y) { m_windowPosX = x; m_windowPosY = y; } + uint32_t GetID() const { return m_id; } + + ImGuiWindow* GetRootWindow() const; + std::pair GetRectPosition() const; + std::pair GetRectSize() const; void SetEnable(bool enable) { m_isEnable = enable; } bool IsEnable() const { return m_isEnable; } ImGuiContextInstance* GetImGuiContextInstance() const; + RenderContext* GetRenderContext() const; SceneWorld* GetSceneWorld() const; protected: const char* m_pName = nullptr; - float m_windowPosX = 0.0f; - float m_windowPosY = 0.0f; + uint32_t m_id = UINT32_MAX; bool m_isEnable = true; }; diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp index 198c0282..053ede85 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp @@ -28,150 +28,105 @@ namespace std::unordered_map kImguiKeyLookup { {engine::KeyCode::RETURN, ImGuiKey::ImGuiKey_Enter}, - {engine::KeyCode::ESCAPE, ImGuiKey::ImGuiKey_Escape}, - {engine::KeyCode::BACKSPACE, ImGuiKey::ImGuiKey_Backspace}, - {engine::KeyCode::TAB, ImGuiKey::ImGuiKey_Tab}, - {engine::KeyCode::SPACE, ImGuiKey::ImGuiKey_Space}, - // {engine::KeyCode::EXCLAIM, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::QUOTEDBL, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::HASH, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::PERCENT, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::DOLLAR, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::AMPERSAND, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::QUOTE, ImGuiKey::ImGuiKey_Apostrophe}, - // {engine::KeyCode::LEFTPAREN, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::RIGHTPAREN, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::ASTERISK, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::PLUS, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::COMMA, ImGuiKey::ImGuiKey_Comma}, - {engine::KeyCode::MINUS, ImGuiKey::ImGuiKey_Minus}, - {engine::KeyCode::PERIOD, ImGuiKey::ImGuiKey_Period}, - {engine::KeyCode::SLASH, ImGuiKey::ImGuiKey_Slash}, - {engine::KeyCode::NUM_0, ImGuiKey::ImGuiKey_0}, - {engine::KeyCode::NUM_1, ImGuiKey::ImGuiKey_1}, - {engine::KeyCode::NUM_2, ImGuiKey::ImGuiKey_2}, - {engine::KeyCode::NUM_3, ImGuiKey::ImGuiKey_3}, - {engine::KeyCode::NUM_4, ImGuiKey::ImGuiKey_4}, - {engine::KeyCode::NUM_5, ImGuiKey::ImGuiKey_5}, - {engine::KeyCode::NUM_6, ImGuiKey::ImGuiKey_6}, - {engine::KeyCode::NUM_7, ImGuiKey::ImGuiKey_7}, - {engine::KeyCode::NUM_8, ImGuiKey::ImGuiKey_8}, - {engine::KeyCode::NUM_9, ImGuiKey::ImGuiKey_9}, - // {engine::KeyCode::COLON, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::SEMICOLON, ImGuiKey::ImGuiKey_Semicolon}, - // {engine::KeyCode::LESS, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::EQUALS, ImGuiKey::ImGuiKey_Equal}, - // {engine::KeyCode::GREATER, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::QUESTION, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::AT, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::LEFTBRACKET, ImGuiKey::ImGuiKey_LeftBracket}, - {engine::KeyCode::BACKSLASH, ImGuiKey::ImGuiKey_Backslash}, - {engine::KeyCode::RIGHTBRACKET, ImGuiKey::ImGuiKey_RightBracket}, - // {engine::KeyCode::CARET, ImGuiKey::ImGuiKey_}, - // {engine::KeyCode::UNDERSCORE, ImGuiKey::ImGuiKey_}, - {engine::KeyCode::BACKQUOTE, ImGuiKey::ImGuiKey_GraveAccent}, - {engine::KeyCode::a, ImGuiKey::ImGuiKey_A}, - {engine::KeyCode::b, ImGuiKey::ImGuiKey_B}, - {engine::KeyCode::c, ImGuiKey::ImGuiKey_C}, - {engine::KeyCode::d, ImGuiKey::ImGuiKey_D}, - {engine::KeyCode::e, ImGuiKey::ImGuiKey_E}, - {engine::KeyCode::f, ImGuiKey::ImGuiKey_F}, - {engine::KeyCode::g, ImGuiKey::ImGuiKey_G}, - {engine::KeyCode::h, ImGuiKey::ImGuiKey_H}, - {engine::KeyCode::i, ImGuiKey::ImGuiKey_I}, - {engine::KeyCode::j, ImGuiKey::ImGuiKey_J}, - {engine::KeyCode::k, ImGuiKey::ImGuiKey_K}, - {engine::KeyCode::l, ImGuiKey::ImGuiKey_L}, - {engine::KeyCode::m, ImGuiKey::ImGuiKey_M}, - {engine::KeyCode::n, ImGuiKey::ImGuiKey_N}, - {engine::KeyCode::o, ImGuiKey::ImGuiKey_O}, - {engine::KeyCode::p, ImGuiKey::ImGuiKey_P}, - {engine::KeyCode::q, ImGuiKey::ImGuiKey_Q}, - {engine::KeyCode::r, ImGuiKey::ImGuiKey_R}, - {engine::KeyCode::s, ImGuiKey::ImGuiKey_S}, - {engine::KeyCode::t, ImGuiKey::ImGuiKey_T}, - {engine::KeyCode::u, ImGuiKey::ImGuiKey_U}, - {engine::KeyCode::v, ImGuiKey::ImGuiKey_V}, - {engine::KeyCode::w, ImGuiKey::ImGuiKey_W}, - {engine::KeyCode::x, ImGuiKey::ImGuiKey_X}, - {engine::KeyCode::y, ImGuiKey::ImGuiKey_Y}, - {engine::KeyCode::z, ImGuiKey::ImGuiKey_Z}, + { engine::KeyCode::ESCAPE, ImGuiKey::ImGuiKey_Escape }, + { engine::KeyCode::BACKSPACE, ImGuiKey::ImGuiKey_Backspace }, + { engine::KeyCode::TAB, ImGuiKey::ImGuiKey_Tab }, + { engine::KeyCode::SPACE, ImGuiKey::ImGuiKey_Space }, + // {engine::KeyCode::EXCLAIM, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::QUOTEDBL, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::HASH, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::PERCENT, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::DOLLAR, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::AMPERSAND, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::QUOTE, ImGuiKey::ImGuiKey_Apostrophe }, + // {engine::KeyCode::LEFTPAREN, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::RIGHTPAREN, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::ASTERISK, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::PLUS, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::COMMA, ImGuiKey::ImGuiKey_Comma }, + { engine::KeyCode::MINUS, ImGuiKey::ImGuiKey_Minus }, + { engine::KeyCode::PERIOD, ImGuiKey::ImGuiKey_Period }, + { engine::KeyCode::SLASH, ImGuiKey::ImGuiKey_Slash }, + { engine::KeyCode::NUM_0, ImGuiKey::ImGuiKey_0 }, + { engine::KeyCode::NUM_1, ImGuiKey::ImGuiKey_1 }, + { engine::KeyCode::NUM_2, ImGuiKey::ImGuiKey_2 }, + { engine::KeyCode::NUM_3, ImGuiKey::ImGuiKey_3 }, + { engine::KeyCode::NUM_4, ImGuiKey::ImGuiKey_4 }, + { engine::KeyCode::NUM_5, ImGuiKey::ImGuiKey_5 }, + { engine::KeyCode::NUM_6, ImGuiKey::ImGuiKey_6 }, + { engine::KeyCode::NUM_7, ImGuiKey::ImGuiKey_7 }, + { engine::KeyCode::NUM_8, ImGuiKey::ImGuiKey_8 }, + { engine::KeyCode::NUM_9, ImGuiKey::ImGuiKey_9 }, + // {engine::KeyCode::COLON, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::SEMICOLON, ImGuiKey::ImGuiKey_Semicolon }, + // {engine::KeyCode::LESS, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::EQUALS, ImGuiKey::ImGuiKey_Equal }, + // {engine::KeyCode::GREATER, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::QUESTION, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::AT, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::LEFTBRACKET, ImGuiKey::ImGuiKey_LeftBracket }, + { engine::KeyCode::BACKSLASH, ImGuiKey::ImGuiKey_Backslash }, + { engine::KeyCode::RIGHTBRACKET, ImGuiKey::ImGuiKey_RightBracket }, + // {engine::KeyCode::CARET, ImGuiKey::ImGuiKey_}, + // {engine::KeyCode::UNDERSCORE, ImGuiKey::ImGuiKey_}, + { engine::KeyCode::BACKQUOTE, ImGuiKey::ImGuiKey_GraveAccent }, + { engine::KeyCode::a, ImGuiKey::ImGuiKey_A }, + { engine::KeyCode::b, ImGuiKey::ImGuiKey_B }, + { engine::KeyCode::c, ImGuiKey::ImGuiKey_C }, + { engine::KeyCode::d, ImGuiKey::ImGuiKey_D }, + { engine::KeyCode::e, ImGuiKey::ImGuiKey_E }, + { engine::KeyCode::f, ImGuiKey::ImGuiKey_F }, + { engine::KeyCode::g, ImGuiKey::ImGuiKey_G }, + { engine::KeyCode::h, ImGuiKey::ImGuiKey_H }, + { engine::KeyCode::i, ImGuiKey::ImGuiKey_I }, + { engine::KeyCode::j, ImGuiKey::ImGuiKey_J }, + { engine::KeyCode::k, ImGuiKey::ImGuiKey_K }, + { engine::KeyCode::l, ImGuiKey::ImGuiKey_L }, + { engine::KeyCode::m, ImGuiKey::ImGuiKey_M }, + { engine::KeyCode::n, ImGuiKey::ImGuiKey_N }, + { engine::KeyCode::o, ImGuiKey::ImGuiKey_O }, + { engine::KeyCode::p, ImGuiKey::ImGuiKey_P }, + { engine::KeyCode::q, ImGuiKey::ImGuiKey_Q }, + { engine::KeyCode::r, ImGuiKey::ImGuiKey_R }, + { engine::KeyCode::s, ImGuiKey::ImGuiKey_S }, + { engine::KeyCode::t, ImGuiKey::ImGuiKey_T }, + { engine::KeyCode::u, ImGuiKey::ImGuiKey_U }, + { engine::KeyCode::v, ImGuiKey::ImGuiKey_V }, + { engine::KeyCode::w, ImGuiKey::ImGuiKey_W }, + { engine::KeyCode::x, ImGuiKey::ImGuiKey_X }, + { engine::KeyCode::y, ImGuiKey::ImGuiKey_Y }, + { engine::KeyCode::z, ImGuiKey::ImGuiKey_Z }, }; std::unordered_map kImguiKeyModToImGuiKeyLookup{ {engine::KeyMod::KMOD_LSHIFT, ImGuiKey::ImGuiKey_LeftShift}, - {engine::KeyMod::KMOD_RSHIFT, ImGuiKey::ImGuiKey_RightShift}, - {engine::KeyMod::KMOD_LCTRL, ImGuiKey::ImGuiKey_LeftCtrl}, - {engine::KeyMod::KMOD_RCTRL, ImGuiKey::ImGuiKey_RightCtrl}, - {engine::KeyMod::KMOD_LALT, ImGuiKey::ImGuiKey_LeftAlt}, - {engine::KeyMod::KMOD_RALT, ImGuiKey::ImGuiKey_RightAlt}, - {engine::KeyMod::KMOD_LGUI, ImGuiKey::ImGuiKey_LeftSuper}, - {engine::KeyMod::KMOD_RGUI, ImGuiKey::ImGuiKey_RightSuper}, - {engine::KeyMod::KMOD_NUM, ImGuiKey::ImGuiKey_NumLock}, - {engine::KeyMod::KMOD_CAPS, ImGuiKey::ImGuiKey_CapsLock}, - {engine::KeyMod::KMOD_MODE, ImGuiKey::ImGuiKey_ModSuper}, - {engine::KeyMod::KMOD_SCROLL, ImGuiKey::ImGuiKey_ScrollLock}, + { engine::KeyMod::KMOD_RSHIFT, ImGuiKey::ImGuiKey_RightShift }, + { engine::KeyMod::KMOD_LCTRL, ImGuiKey::ImGuiKey_LeftCtrl }, + { engine::KeyMod::KMOD_RCTRL, ImGuiKey::ImGuiKey_RightCtrl }, + { engine::KeyMod::KMOD_LALT, ImGuiKey::ImGuiKey_LeftAlt }, + { engine::KeyMod::KMOD_RALT, ImGuiKey::ImGuiKey_RightAlt }, + { engine::KeyMod::KMOD_LGUI, ImGuiKey::ImGuiKey_LeftSuper }, + { engine::KeyMod::KMOD_RGUI, ImGuiKey::ImGuiKey_RightSuper }, + { engine::KeyMod::KMOD_NUM, ImGuiKey::ImGuiKey_NumLock }, + { engine::KeyMod::KMOD_CAPS, ImGuiKey::ImGuiKey_CapsLock }, + { engine::KeyMod::KMOD_MODE, ImGuiKey::ImGuiKey_ModSuper }, + { engine::KeyMod::KMOD_SCROLL, ImGuiKey::ImGuiKey_ScrollLock }, }; std::unordered_map kImguiKeyModToImGuiModLookup{ {engine::KeyMod::KMOD_NONE, ImGuiKey::ImGuiMod_None}, - {engine::KeyMod::KMOD_LSHIFT, ImGuiKey::ImGuiMod_Shift}, - {engine::KeyMod::KMOD_RSHIFT, ImGuiKey::ImGuiMod_Shift}, - {engine::KeyMod::KMOD_LCTRL, ImGuiKey::ImGuiMod_Ctrl}, - {engine::KeyMod::KMOD_RCTRL, ImGuiKey::ImGuiMod_Ctrl}, - {engine::KeyMod::KMOD_LALT, ImGuiKey::ImGuiMod_Alt}, - {engine::KeyMod::KMOD_RALT, ImGuiKey::ImGuiMod_Alt}, - {engine::KeyMod::KMOD_LGUI, ImGuiKey::ImGuiMod_Super}, - {engine::KeyMod::KMOD_RGUI, ImGuiKey::ImGuiMod_Super}, - {engine::KeyMod::KMOD_CTRL, ImGuiKey::ImGuiMod_Ctrl}, - {engine::KeyMod::KMOD_SHIFT, ImGuiKey::ImGuiMod_Shift}, - {engine::KeyMod::KMOD_ALT, ImGuiKey::ImGuiMod_Alt}, - {engine::KeyMod::KMOD_GUI, ImGuiKey::ImGuiMod_Super}, -}; - -// ImGui has a static global ImGuiContext* which points to current active ImGuiContext. -// And almost all ImGui apis assume that the api call will affect current active ImGuiContext. -// -// As we have multiple ImGuiContext instances so you need to use ImGui correctly by two solutions: -// 1. Create a TempSwitchContextScope variable before calling any ImGui API. It will switch context temporarily for you automatically. -// It is a convenient way to develop features but it will waste a little performance on switching context. -// -// 2. Don't use any ImGui apis to finish your work. Instead, you should use m_pImGuiContext to call API. -// It is an advance way to save performances but you are easy to cause bugs if you forgot to use ImGui api. -// For example, ImGui::GetIO() returns current active context's IO. Instead, you should use m_pImGuiContext->IO. -// -// I recommend that you use TempSwitchContextScope in some functions which doesn't call frequently or the logic is too complex to write many codes. -// -class TempSwitchContextScope -{ -public: - TempSwitchContextScope(engine::ImGuiContextInstance* pThis) - { - ImGuiIO& io = ImGui::GetIO(); - assert(io.UserData != nullptr && "Please set ImGuiContextInstance to io.UserData field."); - if (io.UserData != pThis) - { - pThis->SwitchCurrentContext(); - pBackContext = reinterpret_cast(io.UserData); - } - } - - ~TempSwitchContextScope() - { - if (pBackContext) - { - pBackContext->SwitchCurrentContext(); - } - } - - // Disable Copy/Move as it is just a simple scope object to switch ImGui contexts. - TempSwitchContextScope(const TempSwitchContextScope&) = delete; - TempSwitchContextScope& operator=(const TempSwitchContextScope&) = delete; - TempSwitchContextScope(TempSwitchContextScope&&) = delete; - TempSwitchContextScope& operator=(TempSwitchContextScope&&) = delete; - -private: - engine::ImGuiContextInstance* pBackContext = nullptr; + { engine::KeyMod::KMOD_LSHIFT, ImGuiKey::ImGuiMod_Shift }, + { engine::KeyMod::KMOD_RSHIFT, ImGuiKey::ImGuiMod_Shift }, + { engine::KeyMod::KMOD_LCTRL, ImGuiKey::ImGuiMod_Ctrl }, + { engine::KeyMod::KMOD_RCTRL, ImGuiKey::ImGuiMod_Ctrl }, + { engine::KeyMod::KMOD_LALT, ImGuiKey::ImGuiMod_Alt }, + { engine::KeyMod::KMOD_RALT, ImGuiKey::ImGuiMod_Alt }, + { engine::KeyMod::KMOD_LGUI, ImGuiKey::ImGuiMod_Super }, + { engine::KeyMod::KMOD_RGUI, ImGuiKey::ImGuiMod_Super }, + { engine::KeyMod::KMOD_CTRL, ImGuiKey::ImGuiMod_Ctrl }, + { engine::KeyMod::KMOD_SHIFT, ImGuiKey::ImGuiMod_Shift }, + { engine::KeyMod::KMOD_ALT, ImGuiKey::ImGuiMod_Alt }, + { engine::KeyMod::KMOD_GUI, ImGuiKey::ImGuiMod_Super }, }; } @@ -179,33 +134,17 @@ class TempSwitchContextScope namespace engine { -ImGuiContextInstance::ImGuiContextInstance(uint16_t width, uint16_t height, bool enableDock, bool enableViewport) +ImGuiContextInstance::ImGuiContextInstance() { m_pImGuiContext = ImGui::CreateContext(); - SwitchCurrentContext(); - ImGuiIO& io = ImGui::GetIO(); + // Basic settings which can export as APIs if need. + ImGuiIO& io = GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; - io.ConfigWindowsMoveFromTitleBarOnly = true; - io.UserData = this; - - if (enableDock) - { - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - } - - if (enableViewport) - { - io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_RendererHasViewports; - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; - } - - io.IniFilename = nullptr; - io.LogFilename = nullptr; - - io.DisplaySize = ImVec2(static_cast(width), static_cast(height)); - - SetImGuiStyles(); + io.UserData = this; // Help to find ImGuiContextInstance from ImGuiIO. + io.IniFilename = nullptr; // No cache gui settings. + io.LogFilename = nullptr; // No auto generated log texts. + InitLayoutStyles(); } ImGuiContextInstance::~ImGuiContextInstance() @@ -213,6 +152,9 @@ ImGuiContextInstance::~ImGuiContextInstance() ImGui::DestroyContext(m_pImGuiContext); } +/////////////////////////////////////////////////////////////////////////////////////////// +/// Context +/////////////////////////////////////////////////////////////////////////////////////////// void ImGuiContextInstance::SwitchCurrentContext() const { ImGui::SetCurrentContext(m_pImGuiContext); @@ -223,167 +165,111 @@ bool ImGuiContextInstance::IsActive() const return ImGui::GetCurrentContext() == m_pImGuiContext; } -void ImGuiContextInstance::AddStaticLayer(std::unique_ptr pLayer) +ImGuiIO& ImGuiContextInstance::GetIO() const { - pLayer->Init(); - m_pImGuiStaticLayers.emplace_back(std::move(pLayer)); + return m_pImGuiContext->IO; } -void ImGuiContextInstance::AddDynamicLayer(std::unique_ptr pLayer) +ImGuiPlatformIO& ImGuiContextInstance::GetPlatformIO() const { - pLayer->Init(); - m_pImGuiDockableLayers.emplace_back(std::move(pLayer)); + return m_pImGuiContext->PlatformIO; } -void ImGuiContextInstance::ClearUILayers() +ImGuiStyle& ImGuiContextInstance::GetStyle() const { - m_pImGuiStaticLayers.clear(); - m_pImGuiDockableLayers.clear(); + return m_pImGuiContext->Style; } -void ImGuiContextInstance::InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext) +void ImGuiContextInstance::InitBackendUserData(void* pWindow, void* pRenderContext) { - // Register window interfaces. - static WindowManager* s_pWindowManager = pWindowManager; - ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO(); - platformIO.Platform_CreateWindow = [](ImGuiViewport* pViewport) - { - auto pWindow = std::make_unique("ViewportWindow", static_cast(pViewport->Pos.x), static_cast(pViewport->Pos.y), - static_cast(pViewport->Size.x), static_cast(pViewport->Size.y)); - bool noDecoration = pViewport->Flags & ImGuiViewportFlags_NoDecoration; - pWindow->SetBordedLess(noDecoration); - pWindow->SetResizeable(!noDecoration); - 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; - }; - - 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)); - }; + ImGuiIO& io = GetIO(); + io.BackendPlatformUserData = pWindow; + io.BackendRendererUserData = pRenderContext; +} - 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) }; - }; +/////////////////////////////////////////////////////////////////////////////////////////// +/// Display +/////////////////////////////////////////////////////////////////////////////////////////// +void ImGuiContextInstance::SetDisplaySize(uint16_t width, uint16_t height) +{ + ImGuiIO& io = GetIO(); + io.DisplaySize = ImVec2(static_cast(width), static_cast(height)); +} - platformIO.Platform_SetWindowTitle = [](ImGuiViewport* pViewport, const char* pTitle) - { - engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); - pWindow->SetTitle(pTitle); - }; +void ImGuiContextInstance::OnResize(uint16_t width, uint16_t height) +{ + SetDisplaySize(width, height); +} - platformIO.Platform_GetWindowFocus = [](ImGuiViewport* pViewport) - { - engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); - return pWindow->IsFocused(); - }; - - platformIO.Platform_SetWindowFocus = [](ImGuiViewport* pViewport) +bool ImGuiContextInstance::IsInsideDisplayRect(float x, float y) const +{ + ImGuiIO& io = GetIO(); + if (x < m_rectPosX || + x > m_rectPosX + io.DisplaySize.x || + y < m_rectPosY || + y > m_rectPosY + io.DisplaySize.y) { - engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); - pWindow->SetFocused(); - }; + return false; + } - platformIO.Platform_GetWindowMinimized = [](ImGuiViewport* pViewport) - { - engine::Window* pWindow = s_pWindowManager->GetWindow(pViewport->PlatformHandleRaw); - return pWindow->IsMinimized(); - }; + return true; +} - // Register rendering interfaces. - static RenderContext* s_pRenderContext = pRenderContext; - platformIO.Renderer_CreateWindow = [](ImGuiViewport* pViewport) - { - pViewport->PlatformUserData = reinterpret_cast(s_pRenderContext->CreateView()); - engine::StringCrc newRenderTargetName = s_pRenderContext->GetRenderTargetCrc(pViewport->PlatformUserData); - s_pRenderContext->CreateRenderTarget(newRenderTargetName, 1, 1, pViewport->PlatformHandleRaw); - }; +void ImGuiContextInstance::AddStaticLayer(std::unique_ptr pLayer) +{ + pLayer->Init(); + m_mapNameCrcToLayers[StringCrc(pLayer->GetName())] = pLayer.get(); + m_pImGuiStaticLayers.emplace_back(std::move(pLayer)); +} - platformIO.Renderer_DestroyWindow = [](ImGuiViewport* pViewport) - { - if (pViewport->PlatformUserData) - { - s_pRenderContext->DestoryRenderTarget(s_pRenderContext->GetRenderTargetCrc(pViewport->PlatformUserData)); - pViewport->PlatformUserData = nullptr; - } - }; +void ImGuiContextInstance::AddDynamicLayer(std::unique_ptr pLayer) +{ + pLayer->Init(); + m_mapNameCrcToLayers[StringCrc(pLayer->GetName())] = pLayer.get(); + m_pImGuiDockableLayers.emplace_back(std::move(pLayer)); +} - platformIO.Renderer_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 v) - { - auto* pRenderTarget = s_pRenderContext->GetRenderTarget(pViewport->PlatformUserData); - pRenderTarget->Resize(static_cast(v.x), static_cast(v.y)); - }; +ImGuiBaseLayer* ImGuiContextInstance::GetLayerByName(StringCrc nameCrc) const +{ + auto itLayer = m_mapNameCrcToLayers.find(nameCrc); + return itLayer != m_mapNameCrcToLayers.end() ? itLayer->second : nullptr; } -void ImGuiContextInstance::UpdateViewport() +void ImGuiContextInstance::ClearUILayers() { - 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); + m_pImGuiStaticLayers.clear(); + m_pImGuiDockableLayers.clear(); +} - 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); +/////////////////////////////////////////////////////////////////////////////////////////// +/// Dock +/////////////////////////////////////////////////////////////////////////////////////////// +void ImGuiContextInstance::EnableDock() +{ + ImGuiIO& io = GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; +} - // 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); - } - } +bool ImGuiContextInstance::IsDockEnable() const +{ + return GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable; } void ImGuiContextInstance::BeginDockSpace() { + ImGuiIO& io = GetIO(); + // To create a dock space, we need to create a window to host it at first. constexpr const char* pDockSpaceName = "FullScreenDockSpace"; static bool enableDockSpace = true; constexpr ImGuiWindowFlags dockSpaceWindowFlags = ImGuiWindowFlags_NoDocking | - ImGuiWindowFlags_NoTitleBar | - ImGuiWindowFlags_NoCollapse | - ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoBringToFrontOnFocus | - ImGuiWindowFlags_NoNavFocus | - ImGuiWindowFlags_NoBackground; + ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoCollapse | + ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoNavFocus | + ImGuiWindowFlags_NoBackground; // Place dock space window under static imgui layers. // It is a hack now as only main menu bar is a static layer so we only need to adjust the height. @@ -412,7 +298,7 @@ void ImGuiContextInstance::BeginDockSpace() { ImGui::DockBuilderRemoveNode(dockSpaceWindowID); ImGui::DockBuilderAddNode(dockSpaceWindowID); - ImGui::DockBuilderSetNodeSize(dockSpaceWindowID, ImGui::GetIO().DisplaySize * ImGui::GetIO().DisplayFramebufferScale); + ImGui::DockBuilderSetNodeSize(dockSpaceWindowID, io.DisplaySize * io.DisplayFramebufferScale); ImGuiID dockSpaceMainID = dockSpaceWindowID; @@ -452,135 +338,162 @@ void ImGuiContextInstance::EndDockSpace() ImGui::End(); } -void ImGuiContextInstance::Update(float deltaTime) +/////////////////////////////////////////////////////////////////////////////////////////// +/// Viewport +/////////////////////////////////////////////////////////////////////////////////////////// +void ImGuiContextInstance::EnableViewport() { - SwitchCurrentContext(); - - auto& io = ImGui::GetIO(); + ImGuiIO& io = GetIO(); + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_RendererHasViewports; + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; +} - // 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; +bool ImGuiContextInstance::IsViewportEnable() const +{ + return GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable; +} - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) +void ImGuiContextInstance::InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext) +{ + // Register window interfaces. + static WindowManager* s_pWindowManager = pWindowManager; + ImGuiPlatformIO& platformIO = GetPlatformIO(); + platformIO.Platform_CreateWindow = [](ImGuiViewport* pViewport) { - UpdateViewport(); - } - - AddInputEvent(); + auto pWindow = std::make_unique("ViewportWindow", static_cast(pViewport->Pos.x), static_cast(pViewport->Pos.y), + static_cast(pViewport->Size.x), static_cast(pViewport->Size.y)); + bool noDecoration = pViewport->Flags & ImGuiViewportFlags_NoDecoration; + pWindow->SetBordedLess(noDecoration); + pWindow->SetResizeable(!noDecoration); + pViewport->PlatformHandle = pWindow.get(); + pViewport->PlatformHandleRaw = pWindow->GetHandle(); + s_pWindowManager->AddWindow(cd::MoveTemp(pWindow)); + }; - ImGui::NewFrame(); - - for (const auto& pImGuiLayer : m_pImGuiStaticLayers) + platformIO.Platform_DestroyWindow = [](ImGuiViewport* pViewport) { - pImGuiLayer->Update(); - } + auto* pWindow = static_cast(pViewport->PlatformHandle); + s_pWindowManager->RemoveWindow(pWindow->GetID()); + pViewport->PlatformHandle = nullptr; + pViewport->PlatformHandleRaw = nullptr; + }; - const bool dockingEnabled = io.ConfigFlags & ImGuiConfigFlags_DockingEnable; - if (dockingEnabled) + platformIO.Platform_ShowWindow = [](ImGuiViewport* pViewport) { - BeginDockSpace(); - } + auto* pWindow = static_cast(pViewport->PlatformHandle); + pWindow->Show(); + }; - for (const auto& pImGuiLayer : m_pImGuiDockableLayers) + platformIO.Platform_SetWindowPos = [](ImGuiViewport* pViewport, ImVec2 v) { - if (pImGuiLayer->IsEnable()) - { - pImGuiLayer->Update(); - } - } + auto* pWindow = static_cast(pViewport->PlatformHandle); + pWindow->SetPosition(static_cast(v.x), static_cast(v.y)); + }; - if (dockingEnabled) + platformIO.Platform_GetWindowPos = [](ImGuiViewport* pViewport) -> ImVec2 { - EndDockSpace(); - } -} - -// Don't push unnecessary events to ImGui. Or it will overflow its event queue to cause a time delay UI feedback. -// Why we don't use callback directly from native platform window? Because we have multiple imgui contexts to receive input events. -// And only the active imgui context can receive window messages. It sounds no problem but imgui context can switch during one frame multiple times. -// It is not safe to use event callback. -void ImGuiContextInstance::AddInputEvent() -{ - ImGuiIO& io = ImGui::GetIO(); + const auto* pWindow = static_cast(pViewport->PlatformHandle); + auto [x, y] = pWindow->GetPosition(); + return { static_cast(x), static_cast(y) }; + }; - io.AddFocusEvent(Input::Get().IsFocused()); + platformIO.Platform_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 v) + { + auto* pWindow = static_cast(pViewport->PlatformHandle); + pWindow->SetSize(static_cast(v.x), static_cast(v.y)); + }; - if (bool mouseLBPressed = Input::Get().IsMouseLBPressed(); m_lastMouseLBPressed != mouseLBPressed) + platformIO.Platform_GetWindowSize = [](ImGuiViewport* pViewport) -> ImVec2 { - io.AddMouseButtonEvent(ImGuiMouseButton_Left, mouseLBPressed); - m_lastMouseLBPressed = mouseLBPressed; - } + const auto* pWindow = static_cast(pViewport->PlatformHandle); + auto [w, h] = pWindow->GetSize(); + return { static_cast(w), static_cast(h) }; + }; - if (bool mouseRBPressed = Input::Get().IsMouseRBPressed(); m_lastMouseRBPressed != mouseRBPressed) + platformIO.Platform_SetWindowTitle = [](ImGuiViewport* pViewport, const char* pTitle) { - io.AddMouseButtonEvent(ImGuiMouseButton_Right, mouseRBPressed); - m_lastMouseRBPressed = mouseRBPressed; - } + auto* pWindow = static_cast(pViewport->PlatformHandle); + pWindow->SetTitle(pTitle); + }; - if (bool mouseMBPressed = Input::Get().IsMouseMBPressed(); m_lastMouseMBPressed != mouseMBPressed) + platformIO.Platform_GetWindowFocus = [](ImGuiViewport* pViewport) { - io.AddMouseButtonEvent(ImGuiMouseButton_Middle, mouseMBPressed); - m_lastMouseMBPressed = mouseMBPressed; - } + const auto* pWindow = static_cast(pViewport->PlatformHandle); + return pWindow->IsFocused(); + }; + + platformIO.Platform_SetWindowFocus = [](ImGuiViewport* pViewport) + { + auto* pWindow = static_cast(pViewport->PlatformHandle); + pWindow->SetFocused(); + }; - if (float mouseScrollOffsetY = Input::Get().GetMouseScrollOffsetY(); mouseScrollOffsetY != m_lastMouseScrollOffstY) + platformIO.Platform_GetWindowMinimized = [](ImGuiViewport* pViewport) { - io.AddMouseWheelEvent(0.0f, mouseScrollOffsetY); - m_lastMouseScrollOffstY = mouseScrollOffsetY; - } + const auto* pWindow = static_cast(pViewport->PlatformHandle); + return pWindow->IsMinimized(); + }; - float mousePosX = static_cast(Input::Get().GetMousePositionX()); - float mousePosY = static_cast(Input::Get().GetMousePositionY()); - if (mousePosX != m_lastMousePositionX || mousePosY != m_lastMousePositionY) + // Register rendering interfaces. + static RenderContext* s_pRenderContext = pRenderContext; + platformIO.Renderer_CreateWindow = [](ImGuiViewport* pViewport) { - io.AddMousePosEvent(mousePosX - m_windowPosOffsetX, mousePosY - m_windowPosOffsetY); - m_lastMousePositionX = mousePosX; - m_lastMousePositionY = mousePosY; - } + pViewport->PlatformUserData = reinterpret_cast(s_pRenderContext->CreateView()); + engine::StringCrc newRenderTargetName = s_pRenderContext->GetRenderTargetCrc(pViewport->PlatformUserData); + s_pRenderContext->CreateRenderTarget(newRenderTargetName, 1, 1, pViewport->PlatformHandleRaw); + }; - const std::vector keyEvents = Input::Get().GetKeyEventList(); - for (uint32_t i = 0; i < keyEvents.size(); ++i) + platformIO.Renderer_DestroyWindow = [](ImGuiViewport* pViewport) { - const Input::KeyEvent keyEvent = keyEvents[i]; - if (keyEvent.mod != KeyMod::KMOD_NONE) + if (pViewport->PlatformUserData) { - // Add the modifier key event - if (kImguiKeyModToImGuiModLookup.find(keyEvent.mod) != kImguiKeyModToImGuiModLookup.cend()) - { - io.AddKeyEvent(kImguiKeyModToImGuiModLookup[keyEvent.mod], keyEvent.isPressed); - } - // Also add the key itself as key event - if (kImguiKeyModToImGuiKeyLookup.find(keyEvent.mod) != kImguiKeyModToImGuiKeyLookup.cend()) - { - io.AddKeyEvent(kImguiKeyModToImGuiKeyLookup[keyEvent.mod], keyEvent.isPressed); - } - } - if (kImguiKeyLookup.find(keyEvent.code) != kImguiKeyLookup.cend()) { - io.AddKeyEvent(kImguiKeyLookup[keyEvent.code], keyEvent.isPressed); + s_pRenderContext->DestoryRenderTarget(s_pRenderContext->GetRenderTargetCrc(pViewport->PlatformUserData)); + pViewport->PlatformUserData = nullptr; } - } + }; - const char* inputChars = Input::Get().GetInputCharacters(); - const size_t inputCharSize = strlen(inputChars); - for (size_t i = 0; i < inputCharSize; ++i) + platformIO.Renderer_SetWindowSize = [](ImGuiViewport* pViewport, ImVec2 v) { - io.AddInputCharacter(inputChars[i]); - } + auto* pRenderTarget = s_pRenderContext->GetRenderTarget(pViewport->PlatformUserData); + pRenderTarget->Resize(static_cast(v.x), static_cast(v.y)); + }; } -void ImGuiContextInstance::OnResize(uint16_t width, uint16_t height) +void ImGuiContextInstance::UpdateViewport() { - ImGuiIO& io = m_pImGuiContext->IO; - io.DisplaySize.x = width; - io.DisplaySize.y = height; + ImGuiPlatformIO& platformIO = 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); + } + } } +/////////////////////////////////////////////////////////////////////////////////////////// +/// Styles +/////////////////////////////////////////////////////////////////////////////////////////// void ImGuiContextInstance::LoadFontFiles(const std::vector& ttfFileNames, engine::Language language) { - TempSwitchContextScope tempSwitchScope(this); - - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = GetIO(); io.FontGlobalScale = 1.0f; ImFontConfig config; @@ -659,7 +572,7 @@ void ImGuiContextInstance::LoadFontFiles(const std::vector& ttfFile io.Fonts->ConfigData[fontConfigDataIndex].RasterizerMultiply = 1.0f; } - ImFontAtlas* pFontAtlas = ImGui::GetIO().Fonts; + ImFontAtlas* pFontAtlas = io.Fonts; #ifdef IMGUI_ENABLE_FREETYPE pFontAtlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType(); #endif @@ -667,11 +580,9 @@ void ImGuiContextInstance::LoadFontFiles(const std::vector& ttfFile pFontAtlas->Build(); } -void ImGuiContextInstance::SetImGuiStyles() +void ImGuiContextInstance::InitLayoutStyles() { - TempSwitchContextScope tempSwitchScope(this); - - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle& style = GetStyle(); style.WindowPadding = ImVec2(5, 5); style.FramePadding = ImVec2(4, 4); style.ItemSpacing = ImVec2(6, 2); @@ -698,7 +609,7 @@ void ImGuiContextInstance::SetImGuiStyles() style.TabBorderSize = 1.0f; style.TabRounding = roundingAmount; - if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + if (IsViewportEnable()) { style.WindowRounding = roundingAmount; style.Colors[ImGuiCol_WindowBg].w = 1.0f; @@ -707,14 +618,13 @@ void ImGuiContextInstance::SetImGuiStyles() void ImGuiContextInstance::SetImGuiThemeColor(ThemeColor theme) { - TempSwitchContextScope tempSwitchScope(this); - m_themeColor = theme; - ImVec4* colours = ImGui::GetStyle().Colors; + ImGuiStyle& style = GetStyle(); + ImVec4* colours = style.Colors; if (ThemeColor::Black == theme) { - ImGui::StyleColorsDark(); + ImGui::StyleColorsDark(&style); colours[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colours[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); colours[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f); @@ -773,11 +683,11 @@ void ImGuiContextInstance::SetImGuiThemeColor(ThemeColor theme) } else if (ThemeColor::Classic == theme) { - ImGui::StyleColorsClassic(); + ImGui::StyleColorsClassic(&style); } else if (ThemeColor::Dark == theme) { - ImGui::StyleColorsDark(); + ImGui::StyleColorsDark(&style); constexpr float max = 255.0f; ImVec4 Titlebar = ImVec4(40.0f / max, 42.0f / max, 54.0f / max, 1.0f); ImVec4 TabActive = ImVec4(52.0f / max, 54.0f / max, 64.0f / max, 1.0f); @@ -835,7 +745,7 @@ void ImGuiContextInstance::SetImGuiThemeColor(ThemeColor theme) } else if (ThemeColor::Grey == theme) { - ImGui::StyleColorsDark(); + ImGui::StyleColorsDark(&style); colours[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colours[ImGuiCol_TextDisabled] = ImVec4(0.40f, 0.40f, 0.40f, 1.00f); colours[ImGuiCol_ChildBg] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); @@ -889,7 +799,7 @@ void ImGuiContextInstance::SetImGuiThemeColor(ThemeColor theme) } else if (ThemeColor::Light == theme) { - ImGui::StyleColorsLight(); + ImGui::StyleColorsLight(&style); colours[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colours[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); colours[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 0.94f); @@ -948,4 +858,175 @@ void ImGuiContextInstance::SetImGuiLanguage(Language language) m_language = language; Localization::SetLanguage(language); } + +/////////////////////////////////////////////////////////////////////////////////////////// +/// Input +/////////////////////////////////////////////////////////////////////////////////////////// +void ImGuiContextInstance::AddInputEvent() +{ + // Don't push unnecessary events to ImGui. Or it will overflow its event queue to cause a time delay UI feedback. + // Why we don't use callback directly from native platform window? Because we have multiple imgui contexts to receive input events. + // And only the active imgui context can receive window messages. It sounds no problem but imgui context can switch during one frame multiple times. + // It is not safe to use event callback. + AddMouseInputEvent(); + AddKeyboardInputEvent(); +} + +void ImGuiContextInstance::AddMouseInputEvent() +{ + ImGuiIO& io = GetIO(); + + float mousePosX; + float mousePosY; + if (IsViewportEnable()) + { + // Multiple Viewports require screen space mouse coordinates. + auto [screenX, screenY] = engine::Input::GetGloalMousePosition(); + mousePosX = static_cast(screenX); + mousePosY = static_cast(screenY); + } + else + { + mousePosX = static_cast(Input::Get().GetMousePositionX()); + mousePosY = static_cast(Input::Get().GetMousePositionY()); + } + + // Filter mouse events outside of rect. + if (!IsInsideDisplayRect(mousePosX, mousePosY)) + { + return; + } + + // TODO : is this focus event for this context? + io.AddFocusEvent(Input::Get().IsFocused()); + + if (mousePosX != m_lastMousePositionX || mousePosY != m_lastMousePositionY) + { + io.AddMousePosEvent(mousePosX, mousePosY); + m_lastMousePositionX = mousePosX; + m_lastMousePositionY = mousePosY; + } + + if (bool mouseLBPressed = Input::Get().IsMouseLBPressed(); m_lastMouseLBPressed != mouseLBPressed) + { + io.AddMouseButtonEvent(ImGuiMouseButton_Left, mouseLBPressed); + m_lastMouseLBPressed = mouseLBPressed; + } + + if (bool mouseRBPressed = Input::Get().IsMouseRBPressed(); m_lastMouseRBPressed != mouseRBPressed) + { + io.AddMouseButtonEvent(ImGuiMouseButton_Right, mouseRBPressed); + m_lastMouseRBPressed = mouseRBPressed; + } + + if (bool mouseMBPressed = Input::Get().IsMouseMBPressed(); m_lastMouseMBPressed != mouseMBPressed) + { + io.AddMouseButtonEvent(ImGuiMouseButton_Middle, mouseMBPressed); + m_lastMouseMBPressed = mouseMBPressed; + } + + if (float mouseScrollOffsetY = Input::Get().GetMouseScrollOffsetY(); mouseScrollOffsetY != m_lastMouseScrollOffstY) + { + io.AddMouseWheelEvent(0.0f, mouseScrollOffsetY); + m_lastMouseScrollOffstY = mouseScrollOffsetY; + } +} + +void ImGuiContextInstance::AddKeyboardInputEvent() +{ + ImGuiIO& io = GetIO(); + + const std::vector keyEvents = Input::Get().GetKeyEventList(); + for (uint32_t i = 0; i < keyEvents.size(); ++i) + { + const Input::KeyEvent keyEvent = keyEvents[i]; + if (keyEvent.mod != KeyMod::KMOD_NONE) + { + // Add the modifier key event + if (kImguiKeyModToImGuiModLookup.find(keyEvent.mod) != kImguiKeyModToImGuiModLookup.cend()) + { + io.AddKeyEvent(kImguiKeyModToImGuiModLookup[keyEvent.mod], keyEvent.isPressed); + } + // Also add the key itself as key event + if (kImguiKeyModToImGuiKeyLookup.find(keyEvent.mod) != kImguiKeyModToImGuiKeyLookup.cend()) + { + io.AddKeyEvent(kImguiKeyModToImGuiKeyLookup[keyEvent.mod], keyEvent.isPressed); + } + } + if (kImguiKeyLookup.find(keyEvent.code) != kImguiKeyLookup.cend()) { + io.AddKeyEvent(kImguiKeyLookup[keyEvent.code], keyEvent.isPressed); + } + } + + const char* inputChars = Input::Get().GetInputCharacters(); + const size_t inputCharSize = strlen(inputChars); + for (size_t i = 0; i < inputCharSize; ++i) + { + io.AddInputCharacter(inputChars[i]); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/// Loop +/////////////////////////////////////////////////////////////////////////////////////////// +void ImGuiContextInstance::BeginFrame() +{ + SwitchCurrentContext(); +} + +void ImGuiContextInstance::EndFrame() +{ + assert(IsActive()); + + if (IsViewportEnable()) + { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + } +} + +void ImGuiContextInstance::Update(float deltaTime) +{ + assert(IsActive()); + + auto& io = GetIO(); + + // 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; + + if (IsViewportEnable()) + { + UpdateViewport(); + } + + AddInputEvent(); + + ImGui::NewFrame(); + + for (const auto& pImGuiLayer : m_pImGuiStaticLayers) + { + pImGuiLayer->Update(); + } + + const bool dockingEnabled = io.ConfigFlags & ImGuiConfigFlags_DockingEnable; + if (dockingEnabled) + { + BeginDockSpace(); + } + + for (const auto& pImGuiLayer : m_pImGuiDockableLayers) + { + if (pImGuiLayer->IsEnable()) + { + pImGuiLayer->Update(); + } + } + + if (dockingEnabled) + { + EndDockSpace(); + } +} + } \ No newline at end of file diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h index 0f71efa8..72f6e618 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h @@ -1,5 +1,6 @@ #pragma once +#include "Core/StringCrc.h" #include "Localization.h" #include "ThemeColor.h" @@ -9,6 +10,9 @@ #include struct ImGuiContext; +struct ImGuiIO; +struct ImGuiPlatformIO; +struct ImGuiStyle; namespace engine { @@ -21,59 +25,78 @@ class WindowManager; class ImGuiContextInstance { public: - ImGuiContextInstance() = delete; - explicit ImGuiContextInstance(uint16_t width, uint16_t height, bool enableDock = false, bool enableViewport = false); + ImGuiContextInstance(); ImGuiContextInstance(const ImGuiContextInstance&) = delete; ImGuiContextInstance& operator=(const ImGuiContextInstance&) = delete; ImGuiContextInstance(ImGuiContextInstance&&) = default; ImGuiContextInstance& operator=(ImGuiContextInstance&&) = default; virtual ~ImGuiContextInstance(); - void Update(float deltaTime); - - // Context settings. - bool IsActive() const; + // Context void SwitchCurrentContext() const; - - // GUI management. + bool IsActive() const; + ImGuiContext* GetContext() const { return m_pImGuiContext; } + ImGuiIO& GetIO() const; + ImGuiPlatformIO& GetPlatformIO() const; + ImGuiStyle& GetStyle() const; + void InitBackendUserData(void* pWindow, void* pRenderContext); + + // Display + void SetRectPosition(float x, float y) { m_rectPosX = x; m_rectPosY = y; } + void SetDisplaySize(uint16_t width, uint16_t height); void OnResize(uint16_t width, uint16_t height); + bool IsInsideDisplayRect(float x, float y) const; void AddStaticLayer(std::unique_ptr pLayer); std::vector>& GetDockableLayers() { return m_pImGuiDockableLayers; } void AddDynamicLayer(std::unique_ptr pLayer); + ImGuiBaseLayer* GetLayerByName(StringCrc nameCrc) const; void ClearUILayers(); - // GUI styles. + // 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); - // Input management. - void SetWindowPosOffset(float x, float y) { m_windowPosOffsetX = x; m_windowPosOffsetY = y; } + // Docking features. + void EnableDock(); + bool IsDockEnable() const; // Viewport feature. + void EnableViewport(); + bool IsViewportEnable() const; void InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext); void UpdateViewport(); + // Loop. + void BeginFrame(); + void Update(float deltaTime); + void EndFrame(); + // Access to world data. void SetSceneWorld(SceneWorld* pSceneWorld) { m_pSceneWorld = pSceneWorld; } SceneWorld* GetSceneWorld() const { return m_pSceneWorld; } private: - void AddInputEvent(); - void SetImGuiStyles(); + void InitLayoutStyles(); + void BeginDockSpace(); void EndDockSpace(); + // Input + void AddInputEvent(); + void AddMouseInputEvent(); + void AddKeyboardInputEvent(); + private: SceneWorld* m_pSceneWorld = nullptr; ImGuiContext* m_pImGuiContext = nullptr; Language m_language; ThemeColor m_themeColor; - float m_windowPosOffsetX = 0.0f; - float m_windowPosOffsetY = 0.0f; + float m_rectPosX = 0.0f; + float m_rectPosY = 0.0f; bool m_lastMouseLBPressed = false; bool m_lastMouseRBPressed = false; @@ -82,6 +105,7 @@ class ImGuiContextInstance float m_lastMousePositionX = 0.0f; float m_lastMousePositionY = 0.0f; + std::map m_mapNameCrcToLayers; std::vector> m_pImGuiStaticLayers; std::vector> m_pImGuiDockableLayers; }; diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextManager.cpp b/Engine/Source/Runtime/ImGui/ImGuiContextManager.cpp new file mode 100644 index 00000000..0bdb7965 --- /dev/null +++ b/Engine/Source/Runtime/ImGui/ImGuiContextManager.cpp @@ -0,0 +1,44 @@ +#include "ImGuiContextManager.h" + +#include "Base/Template.h" +#include "ImGuiContextInstance.h" + +#include + +namespace engine +{ + +ImGuiContextManager::ImGuiContextManager() +{ +} + +ImGuiContextManager::~ImGuiContextManager() +{ +} + +ImGuiContextInstance* ImGuiContextManager::AddImGuiContext(StringCrc nameCrc) +{ + auto itContext = m_allImGuiContexts.find(nameCrc); + if (itContext != m_allImGuiContexts.end()) + { + return itContext->second.get(); + } + + auto newContext = std::make_unique(); + auto* pNewContext = newContext.get(); + m_allImGuiContexts[nameCrc] = cd::MoveTemp(newContext); + return pNewContext; +} + +ImGuiContextInstance* ImGuiContextManager::GetImGuiContext(StringCrc nameCrc) const +{ + auto itContext = m_allImGuiContexts.find(nameCrc); + return itContext != m_allImGuiContexts.end() ? itContext->second.get() : nullptr; +} + +void ImGuiContextManager::RemoveImGuiContext(StringCrc nameCrc) +{ + m_allImGuiContexts.erase(nameCrc); +} + +} \ No newline at end of file diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextManager.h b/Engine/Source/Runtime/ImGui/ImGuiContextManager.h new file mode 100644 index 00000000..fa5a9cf4 --- /dev/null +++ b/Engine/Source/Runtime/ImGui/ImGuiContextManager.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Core/StringCrc.h" + +#include +#include + +namespace engine +{ + +class ImGuiContextInstance; + +class ImGuiContextManager +{ +public: + using MapNameToImGuiContext = std::map>; + +public: + ImGuiContextManager(); + ImGuiContextManager(const ImGuiContextManager&) = delete; + ImGuiContextManager& operator=(const ImGuiContextManager&) = delete; + ImGuiContextManager(ImGuiContextManager&&) = default; + ImGuiContextManager& operator=(ImGuiContextManager&&) = default; + ~ImGuiContextManager(); + + MapNameToImGuiContext& GetAllImGuiContexts() { return m_allImGuiContexts; } + const MapNameToImGuiContext& GetAllImGuiContexts() const { return m_allImGuiContexts; } + ImGuiContextInstance* AddImGuiContext(StringCrc nameCrc); + ImGuiContextInstance* GetImGuiContext(StringCrc nameCrc) const; + void RemoveImGuiContext(StringCrc nameCrc); + +private: + std::map> m_allImGuiContexts; +}; + +} \ No newline at end of file diff --git a/Engine/Source/Runtime/ImGui/UILayers/DebugPanel.h b/Engine/Source/Runtime/ImGui/UILayers/DebugPanel.h index a7d75f27..5408fdf6 100644 --- a/Engine/Source/Runtime/ImGui/UILayers/DebugPanel.h +++ b/Engine/Source/Runtime/ImGui/UILayers/DebugPanel.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" namespace engine diff --git a/Engine/Source/Runtime/ImGui/UILayers/Profiler.h b/Engine/Source/Runtime/ImGui/UILayers/Profiler.h index e76c713c..fb396790 100644 --- a/Engine/Source/Runtime/ImGui/UILayers/Profiler.h +++ b/Engine/Source/Runtime/ImGui/UILayers/Profiler.h @@ -1,3 +1,5 @@ +#pragma once + #include "ImGui/ImGuiBaseLayer.h" namespace engine diff --git a/Engine/Source/Runtime/Window/Input.cpp b/Engine/Source/Runtime/Window/Input.cpp index 77dd41e0..cacd6347 100644 --- a/Engine/Source/Runtime/Window/Input.cpp +++ b/Engine/Source/Runtime/Window/Input.cpp @@ -10,6 +10,13 @@ namespace engine { +std::pair Input::GetGloalMousePosition() +{ + int x, y; + SDL_GetGlobalMouseState(&x, &y); + return std::make_pair(x, y); +} + Input::Input() { memset(m_keyPressed, static_cast(false), sizeof(bool) * MaxKeyCode); @@ -75,13 +82,6 @@ void Input::FlushInputs() m_inputCharBuffer[0] = '\0'; } -std::pair Input::GetGloalMousePosition() const -{ - int x, y; - SDL_GetGlobalMouseState(&x, &y); - return std::make_pair(x, y); -} - void Input::Update() { Input::Get().Reset(); diff --git a/Engine/Source/Runtime/Window/Input.h b/Engine/Source/Runtime/Window/Input.h index 0b87d5dd..59b6985e 100644 --- a/Engine/Source/Runtime/Window/Input.h +++ b/Engine/Source/Runtime/Window/Input.h @@ -29,6 +29,9 @@ class Input bool isPressed; }; +public: + static std::pair GetGloalMousePosition(); + public: // Input is a singleton class which will be used conveniently to query device status. // Always call SetXXX methods in the main thread as Window::Update occurs there. So don't worry about thread safe. @@ -97,8 +100,6 @@ class Input void FlushInputs(); - std::pair GetGloalMousePosition() const; - void Update(); private: diff --git a/Engine/Source/Runtime/Window/Window.cpp b/Engine/Source/Runtime/Window/Window.cpp index 195d952c..12250c67 100644 --- a/Engine/Source/Runtime/Window/Window.cpp +++ b/Engine/Source/Runtime/Window/Window.cpp @@ -65,6 +65,11 @@ Window::~Window() SDL_DestroyWindow(m_pSDLWindow); } +uint32_t Window::GetID() const +{ + return SDL_GetWindowID(m_pSDLWindow); +} + void* Window::GetHandle() const { SDL_SysWMinfo wmi; diff --git a/Engine/Source/Runtime/Window/Window.h b/Engine/Source/Runtime/Window/Window.h index 62f7dad7..1720cf6f 100644 --- a/Engine/Source/Runtime/Window/Window.h +++ b/Engine/Source/Runtime/Window/Window.h @@ -35,6 +35,7 @@ class Window Window& operator=(Window&&) = delete; ~Window(); + uint32_t GetID() const; void* GetHandle() const; const char* GetTitle() const; diff --git a/Engine/Source/Runtime/Window/WindowManager.cpp b/Engine/Source/Runtime/Window/WindowManager.cpp index 91b83ad0..6e318230 100644 --- a/Engine/Source/Runtime/Window/WindowManager.cpp +++ b/Engine/Source/Runtime/Window/WindowManager.cpp @@ -4,9 +4,6 @@ #include "Input.h" #include "Window.h" -// TODO : remove imgui dependencies. -#include "ImGui/imgui.h" - #include "SDL.h" #include @@ -24,25 +21,25 @@ WindowManager::~WindowManager() Window::Shutdown(); } -Window* WindowManager::GetWindow(void* handle) const +Window* WindowManager::GetWindow(uint32_t id) const { - auto itWindow = m_mapWindows.find(handle); - return itWindow != m_mapWindows.end() ? itWindow->second.get() : nullptr; + auto itWindow = m_allWindows.find(id); + return itWindow != m_allWindows.end() ? itWindow->second.get() : nullptr; } void WindowManager::AddWindow(std::unique_ptr pWindow) { - m_mapWindows[pWindow->GetHandle()] = cd::MoveTemp(pWindow); + m_allWindows[pWindow->GetID()] = cd::MoveTemp(pWindow); } -void WindowManager::RemoveWindow(void* handle) +void WindowManager::RemoveWindow(uint32_t id) { - m_mapWindows.erase(handle); + m_allWindows.erase(id); } engine::Window* WindowManager::GetActiveWindow() const { - for (const auto& [_, pWindow] : m_mapWindows) + for (const auto& [_, pWindow] : m_allWindows) { if (pWindow->IsFocused()) { @@ -62,7 +59,7 @@ void WindowManager::Update() { case SDL_QUIT: { - for (const auto& [_, pWindow] : m_mapWindows) + for (const auto& [_, pWindow] : m_allWindows) { pWindow->Close(false); } @@ -98,12 +95,12 @@ void WindowManager::Update() case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_RESIZED: { - if (ImGuiViewport* pViewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(wev.windowID))) - { - pViewport->PlatformRequestClose = wev.event == SDL_WINDOWEVENT_CLOSE; - pViewport->PlatformRequestMove = wev.event == SDL_WINDOWEVENT_MOVED; - pViewport->PlatformRequestResize = wev.event == SDL_WINDOWEVENT_RESIZED; - } + //if (ImGuiViewport* pViewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(wev.windowID))) + //{ + // pViewport->PlatformRequestClose = wev.event == SDL_WINDOWEVENT_CLOSE; + // pViewport->PlatformRequestMove = wev.event == SDL_WINDOWEVENT_MOVED; + // pViewport->PlatformRequestResize = wev.event == SDL_WINDOWEVENT_RESIZED; + //} } break; } @@ -112,23 +109,8 @@ void WindowManager::Update() case SDL_MOUSEMOTION: { - // Top left is (0,0) for (x, y) - // xrel is positive to the right, negative to the left - // yrel is positive to the bottom, negative to the top const SDL_MouseMotionEvent& mouseMotionEvent = sdlEvent.motion; - int mouseX = mouseMotionEvent.x; - int mouseY = mouseMotionEvent.y; - if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - int windowX, windowY; - SDL_GetWindowPosition(SDL_GetWindowFromID(mouseMotionEvent.windowID), &windowX, &windowY); - mouseX += windowX; - mouseY += windowY; - } - Input::Get().SetMousePositionX(mouseX); - Input::Get().SetMousePositionY(mouseY); - //Input::Get().SetMousePositionOffsetX(mouseMotionEvent.xrel); - //Input::Get().SetMousePositionOffsetY(mouseMotionEvent.yrel); + OnMouseMove.Invoke(mouseMotionEvent.windowID, mouseMotionEvent.x, mouseMotionEvent.y); } break; diff --git a/Engine/Source/Runtime/Window/WindowManager.h b/Engine/Source/Runtime/Window/WindowManager.h index a44b3e38..83d94c9e 100644 --- a/Engine/Source/Runtime/Window/WindowManager.h +++ b/Engine/Source/Runtime/Window/WindowManager.h @@ -2,6 +2,7 @@ #include "Core/Delegates/Delegate.hpp" +#include #include #include @@ -12,6 +13,9 @@ class Window; class WindowManager final { +public: + using MapIDToWindow = std::map>; + public: WindowManager(); WindowManager(const WindowManager&) = delete; @@ -20,20 +24,23 @@ class WindowManager final WindowManager& operator=(WindowManager&&) = default; ~WindowManager(); - engine::Window* GetWindow(void* handle) const; + MapIDToWindow& GetAllWindows() { return m_allWindows; } + const MapIDToWindow& GetAllWindows() const { return m_allWindows; } + engine::Window* GetWindow(uint32_t id) const; void AddWindow(std::unique_ptr pWindow); - void RemoveWindow(void* handle); + void RemoveWindow(uint32_t id); void Update(); // Delegates + Delegate OnMouseMove; Delegate OnDropFile; private: engine::Window* GetActiveWindow() const; private: - std::map> m_mapWindows; + MapIDToWindow m_allWindows; }; } \ No newline at end of file diff --git a/Engine/Source/ThirdParty/AssetPipeline b/Engine/Source/ThirdParty/AssetPipeline index d262a1f0..801cee30 160000 --- a/Engine/Source/ThirdParty/AssetPipeline +++ b/Engine/Source/ThirdParty/AssetPipeline @@ -1 +1 @@ -Subproject commit d262a1f043085aa3e0bd808d0ac9875873304b75 +Subproject commit 801cee309566388ba9f1835daeee8c4c9566fb40