#include "Actions/ActionRouting.h" #include "Core/IEditorContext.h" #include "Core/ISceneManager.h" #include "Core/ISelectionManager.h" #include "SceneViewPanel.h" #include "Viewport/SceneViewportOverlayRenderer.h" #include "ViewportPanelContent.h" #include "UI/UI.h" #include namespace XCEngine { namespace Editor { namespace { SceneViewportMoveGizmoContext BuildMoveGizmoContext( IEditorContext& context, const SceneViewportOverlayData& overlay, const ViewportPanelContentResult& content, const ImVec2& mousePosition) { SceneViewportMoveGizmoContext gizmoContext = {}; gizmoContext.overlay = overlay; gizmoContext.viewportSize = Math::Vector2(content.availableSize.x, content.availableSize.y); gizmoContext.mousePosition = Math::Vector2( mousePosition.x - content.itemMin.x, mousePosition.y - content.itemMin.y); if (context.GetSelectionManager().GetSelectionCount() == 1) { const uint64_t selectedEntity = context.GetSelectionManager().GetSelectedEntity(); if (selectedEntity != 0) { gizmoContext.selectedObject = context.GetSceneManager().GetEntity(selectedEntity); } } return gizmoContext; } } // namespace SceneViewPanel::SceneViewPanel() : Panel("Scene") {} void SceneViewPanel::Render() { ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); UI::PanelWindowScope panel(m_name.c_str()); ImGui::PopStyleVar(); if (!panel.IsOpen()) { return; } const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene); if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) { const ImGuiIO& io = ImGui::GetIO(); const bool hasInteractiveViewport = content.hasViewportArea && content.frame.hasTexture; SceneViewportOverlayData overlay = {}; SceneViewportMoveGizmoContext moveGizmoContext = {}; if (hasInteractiveViewport) { overlay = viewportHostService->GetSceneViewOverlayData(); moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos); if (m_moveGizmo.IsActive() && (moveGizmoContext.selectedObject == nullptr || m_context->GetSelectionManager().GetSelectedEntity() != m_moveGizmo.GetActiveEntityId())) { m_moveGizmo.CancelDrag(&m_context->GetUndoManager()); } m_moveGizmo.Update(moveGizmoContext); } else if (m_moveGizmo.IsActive()) { m_moveGizmo.CancelDrag(&m_context->GetUndoManager()); } const bool beginMoveGizmo = hasInteractiveViewport && content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !m_lookDragging && !m_panDragging && m_moveGizmo.IsHoveringHandle(); const bool selectClick = hasInteractiveViewport && content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !m_lookDragging && !m_panDragging && !m_moveGizmo.IsHoveringHandle() && !m_moveGizmo.IsActive(); const bool beginLookDrag = content.hovered && !m_moveGizmo.IsActive() && ImGui::IsMouseClicked(ImGuiMouseButton_Right); const bool beginPanDrag = content.hovered && !m_moveGizmo.IsActive() && ImGui::IsMouseClicked(ImGuiMouseButton_Middle); if (beginMoveGizmo || selectClick || beginLookDrag || beginPanDrag) { ImGui::SetWindowFocus(); } if (beginMoveGizmo) { m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager()); } if (selectClick) { const ImVec2 localMousePosition( io.MousePos.x - content.itemMin.x, io.MousePos.y - content.itemMin.y); const uint64_t selectedEntity = viewportHostService->PickSceneViewEntity( *m_context, content.availableSize, localMousePosition); if (selectedEntity != 0) { m_context->GetSelectionManager().SetSelectedEntity(selectedEntity); } else { m_context->GetSelectionManager().ClearSelection(); } } if (m_moveGizmo.IsActive()) { if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) { m_moveGizmo.UpdateDrag(moveGizmoContext); } else { m_moveGizmo.EndDrag(m_context->GetUndoManager()); } } if (beginLookDrag) { m_lookDragging = true; m_lastLookDragDelta = ImVec2(0.0f, 0.0f); } if (beginPanDrag) { m_panDragging = true; m_lastPanDragDelta = ImVec2(0.0f, 0.0f); } if (m_lookDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) { m_lookDragging = false; m_lastLookDragDelta = ImVec2(0.0f, 0.0f); } if (m_panDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Middle)) { m_panDragging = false; m_lastPanDragDelta = ImVec2(0.0f, 0.0f); } if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive()) { ImGui::SetNextFrameWantCaptureMouse(true); } if (m_lookDragging) { ImGui::SetNextFrameWantCaptureKeyboard(true); } SceneViewportInput input = {}; input.viewportSize = content.availableSize; input.deltaTime = io.DeltaTime; input.hovered = content.hovered; input.focused = content.focused || m_lookDragging || m_panDragging; input.mouseWheel = (content.hovered && !m_lookDragging) ? io.MouseWheel : 0.0f; input.flySpeedDelta = (content.hovered && m_lookDragging) ? io.MouseWheel : 0.0f; input.looking = m_lookDragging; input.orbiting = false; input.panning = m_panDragging; input.fastMove = io.KeyShift; input.focusSelectionRequested = input.focused && !io.WantTextInput && ImGui::IsKeyPressed(ImGuiKey_F, false); if (m_lookDragging && !io.WantTextInput) { input.moveForward = (ImGui::IsKeyDown(ImGuiKey_W) ? 1.0f : 0.0f) - (ImGui::IsKeyDown(ImGuiKey_S) ? 1.0f : 0.0f); input.moveRight = (ImGui::IsKeyDown(ImGuiKey_D) ? 1.0f : 0.0f) - (ImGui::IsKeyDown(ImGuiKey_A) ? 1.0f : 0.0f); input.moveUp = (ImGui::IsKeyDown(ImGuiKey_E) ? 1.0f : 0.0f) - (ImGui::IsKeyDown(ImGuiKey_Q) ? 1.0f : 0.0f); } if (m_lookDragging || m_panDragging) { if (m_lookDragging) { const ImVec2 lookDragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right, 0.0f); input.mouseDelta.x += lookDragDelta.x - m_lastLookDragDelta.x; input.mouseDelta.y += lookDragDelta.y - m_lastLookDragDelta.y; m_lastLookDragDelta = lookDragDelta; } else { m_lastLookDragDelta = ImVec2(0.0f, 0.0f); } if (m_panDragging) { const ImVec2 panDragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle, 0.0f); input.mouseDelta.x += panDragDelta.x - m_lastPanDragDelta.x; input.mouseDelta.y += panDragDelta.y - m_lastPanDragDelta.y; m_lastPanDragDelta = panDragDelta; } else { m_lastPanDragDelta = ImVec2(0.0f, 0.0f); } } viewportHostService->UpdateSceneViewInput(*m_context, input); if (content.hasViewportArea && content.frame.hasTexture) { overlay = viewportHostService->GetSceneViewOverlayData(); moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos); m_moveGizmo.Update(moveGizmoContext); DrawSceneViewportOverlay( ImGui::GetWindowDrawList(), overlay, content.itemMin, content.itemMax, content.availableSize, &m_moveGizmo.GetDrawData()); } } Actions::ObserveInactiveActionRoute(*m_context); } } }