#pragma once #include "Core/IEditorContext.h" #include "SceneViewportNavigation.h" #include "IViewportHostService.h" #include "SceneViewportEditorModes.h" #include "SceneViewportHudOverlay.h" #include "SceneViewportInteractionActions.h" #include "SceneViewportInteractionResolver.h" #include "SceneViewportTransformGizmoCoordinator.h" namespace XCEngine { namespace Editor { struct SceneViewportToolState { bool usingViewMoveTool = false; bool usingTransformTool = false; bool showingMoveGizmo = false; bool showingRotateGizmo = false; bool showingScaleGizmo = false; bool useCenterPivot = false; bool localSpace = false; SceneViewportTransformGizmoFrameOptions gizmoFrameOptions = {}; }; inline SceneViewportToolState BuildSceneViewportToolState( SceneViewportToolMode toolMode, SceneViewportPivotMode pivotMode, SceneViewportTransformSpaceMode transformSpaceMode) { SceneViewportToolState state = {}; state.usingViewMoveTool = toolMode == SceneViewportToolMode::ViewMove; state.usingTransformTool = toolMode == SceneViewportToolMode::Transform; state.showingMoveGizmo = toolMode == SceneViewportToolMode::Move || state.usingTransformTool; state.showingRotateGizmo = toolMode == SceneViewportToolMode::Rotate || state.usingTransformTool; state.showingScaleGizmo = toolMode == SceneViewportToolMode::Scale || state.usingTransformTool; state.useCenterPivot = pivotMode == SceneViewportPivotMode::Center; state.localSpace = transformSpaceMode == SceneViewportTransformSpaceMode::Local; state.gizmoFrameOptions = BuildSceneViewportTransformGizmoFrameOptions( state.useCenterPivot, state.localSpace, state.usingTransformTool, state.showingMoveGizmo, state.showingRotateGizmo, state.showingScaleGizmo); return state; } struct SceneViewportFrameGeometry { Math::Vector2 viewportSize = Math::Vector2::Zero(); Math::Vector2 localMousePosition = Math::Vector2::Zero(); }; inline SceneViewportFrameGeometry BuildSceneViewportFrameGeometry( const ImVec2& viewportSize, const ImVec2& viewportMin, const ImVec2& absoluteMousePosition) { SceneViewportFrameGeometry geometry = {}; geometry.viewportSize = Math::Vector2(viewportSize.x, viewportSize.y); geometry.localMousePosition = Math::Vector2( absoluteMousePosition.x - viewportMin.x, absoluteMousePosition.y - viewportMin.y); return geometry; } struct SceneViewportInteractionFrameState { bool hasInteractiveViewport = false; SceneViewportOverlayData overlay = {}; SceneViewportTransformGizmoFrameUpdate gizmoFrameUpdate = {}; SceneViewportTransformGizmoFrameState gizmoFrameState = {}; const SceneViewportOverlayFrameData* overlayFrameData = nullptr; SceneViewportActiveGizmoKind activeGizmoKind = SceneViewportActiveGizmoKind::None; bool gizmoActive = false; SceneViewportHudOverlayData hudOverlay = {}; }; inline SceneViewportInteractionFrameState BuildSceneViewportInteractionFrameState( IEditorContext& context, IViewportHostService& viewportHostService, bool hasInteractiveViewport, const SceneViewportFrameGeometry& geometry, const SceneViewportTransformGizmoFrameOptions& gizmoFrameOptions, SceneViewportMoveGizmo& moveGizmo, SceneViewportRotateGizmo& rotateGizmo, SceneViewportScaleGizmo& scaleGizmo, const SceneViewportOverlayFrameData& emptyOverlayFrameData) { SceneViewportInteractionFrameState state = {}; state.hasInteractiveViewport = hasInteractiveViewport; state.overlayFrameData = &emptyOverlayFrameData; if (!hasInteractiveViewport) { CancelSceneViewportTransformGizmoFrame(context, moveGizmo, rotateGizmo, scaleGizmo); state.hudOverlay = BuildSceneViewportHudOverlayData(state.overlay); return state; } state.overlay = viewportHostService.GetSceneViewOverlayData(); state.gizmoFrameUpdate = RefreshAndSubmitSceneViewportTransformGizmoFrame( viewportHostService, BuildSceneViewportTransformGizmoRefreshRequest( context, state.overlay, geometry.viewportSize, geometry.localMousePosition, gizmoFrameOptions), moveGizmo, rotateGizmo, scaleGizmo); state.gizmoFrameState = state.gizmoFrameUpdate.frameState; state.overlayFrameData = &viewportHostService.GetSceneViewEditorOverlayFrameData(context); state.activeGizmoKind = state.gizmoFrameUpdate.overlaySubmission.activeGizmoKind; state.gizmoActive = state.gizmoFrameUpdate.overlaySubmission.GizmoActive(); state.hudOverlay = BuildSceneViewportHudOverlayData(state.overlay); return state; } inline SceneViewportInteractionResolveRequest BuildSceneViewportInteractionResolveRequest( const SceneViewportInteractionFrameState& frameState, const SceneViewportFrameGeometry& geometry, const ImVec2& viewportMin, const ImVec2& viewportMax, const ImVec2& absoluteMousePosition) { SceneViewportInteractionResolveRequest request = {}; request.overlayFrameData = frameState.overlayFrameData; request.viewportSize = geometry.viewportSize; request.localMousePosition = geometry.localMousePosition; request.hudOverlay = &frameState.hudOverlay; request.viewportMin = viewportMin; request.viewportMax = viewportMax; request.absoluteMousePosition = absoluteMousePosition; return request; } inline bool ShouldFocusSceneViewportAfterInteraction( bool toolCommandTriggered, const SceneViewportInteractionActions& interactionActions, const SceneViewportNavigationUpdate& navigationUpdate) { return toolCommandTriggered || interactionActions.HasClickAction() || navigationUpdate.beginLookDrag || navigationUpdate.beginPanDrag; } struct SceneViewportPresentationRequest { IEditorContext* context = nullptr; IViewportHostService* viewportHostService = nullptr; const SceneViewportOverlayFrameData* overlayFrameData = nullptr; bool hasInteractiveViewport = false; SceneViewportFrameGeometry geometry = {}; SceneViewportTransformGizmoFrameOptions gizmoFrameOptions = {}; SceneViewportMoveGizmo* moveGizmo = nullptr; SceneViewportRotateGizmo* rotateGizmo = nullptr; SceneViewportScaleGizmo* scaleGizmo = nullptr; ImDrawList* drawList = nullptr; ImVec2 viewportMin = ImVec2(0.0f, 0.0f); ImVec2 viewportMax = ImVec2(0.0f, 0.0f); bool IsValid() const { return context != nullptr && viewportHostService != nullptr && moveGizmo != nullptr && rotateGizmo != nullptr && scaleGizmo != nullptr; } }; inline void RefreshAndDrawSceneViewportPresentation(const SceneViewportPresentationRequest& request) { if (!request.IsValid() || !request.hasInteractiveViewport) { return; } const SceneViewportOverlayData overlay = request.viewportHostService->GetSceneViewOverlayData(); RefreshAndSubmitSceneViewportTransformGizmoFrame( *request.viewportHostService, BuildSceneViewportTransformGizmoRefreshRequest( *request.context, overlay, request.geometry.viewportSize, request.geometry.localMousePosition, request.gizmoFrameOptions), *request.moveGizmo, *request.rotateGizmo, *request.scaleGizmo); DrawSceneViewportHudOverlay( request.drawList, BuildSceneViewportHudOverlayData( overlay, true, request.overlayFrameData), request.viewportMin, request.viewportMax); } } // namespace Editor } // namespace XCEngine