#pragma once #include "IViewportHostService.h" #include #include #include #include #include #include #include #include namespace XCEngine { namespace Components { class GameObject; } // namespace Components namespace Editor { class IUndoManager; enum class SceneViewportRotateGizmoAxis : uint8_t { None = 0, X, Y, Z, View }; constexpr size_t kSceneViewportRotateGizmoSegmentCount = 96; constexpr size_t kSceneViewportRotateGizmoAngleFillPointCount = kSceneViewportRotateGizmoSegmentCount + 1; struct SceneViewportRotateGizmoSegmentDrawData { Math::Vector2 start = Math::Vector2::Zero(); Math::Vector2 end = Math::Vector2::Zero(); float startAngle = 0.0f; float endAngle = 0.0f; bool visible = false; bool frontFacing = true; }; struct SceneViewportRotateGizmoHandleDrawData { SceneViewportRotateGizmoAxis axis = SceneViewportRotateGizmoAxis::None; std::array segments = {}; Math::Color color = Math::Color::White(); bool visible = false; bool hovered = false; bool active = false; }; struct SceneViewportRotateGizmoAngleFillDrawData { SceneViewportRotateGizmoAxis axis = SceneViewportRotateGizmoAxis::None; Math::Vector2 pivot = Math::Vector2::Zero(); std::array arcPoints = {}; size_t arcPointCount = 0; Math::Color fillColor = Math::Color::White(); Math::Color outlineColor = Math::Color::White(); bool visible = false; }; struct SceneViewportRotateGizmoDrawData { bool visible = false; Math::Vector2 pivot = Math::Vector2::Zero(); std::array handles = {}; SceneViewportRotateGizmoAngleFillDrawData angleFill = {}; }; struct SceneViewportRotateGizmoContext { SceneViewportOverlayData overlay = {}; Math::Vector2 viewportSize = Math::Vector2::Zero(); Math::Vector2 mousePosition = Math::Vector2::Zero(); Components::GameObject* selectedObject = nullptr; std::vector selectedObjects = {}; Math::Vector3 pivotWorldPosition = Math::Vector3::Zero(); Math::Quaternion axisOrientation = Math::Quaternion::Identity(); bool localSpace = false; bool rotateAroundSharedPivot = false; }; struct SceneViewportRotateGizmoHitResult { SceneViewportRotateGizmoAxis axis = SceneViewportRotateGizmoAxis::None; float distanceSq = Math::FLOAT_MAX; bool HasHit() const { return axis != SceneViewportRotateGizmoAxis::None; } }; class SceneViewportRotateGizmo { public: void Update(const SceneViewportRotateGizmoContext& context); bool TryBeginDrag(const SceneViewportRotateGizmoContext& context, IUndoManager& undoManager); void UpdateDrag(const SceneViewportRotateGizmoContext& context); void EndDrag(IUndoManager& undoManager); void CancelDrag(IUndoManager* undoManager = nullptr); bool IsHoveringHandle() const; bool IsActive() const; uint64_t GetActiveEntityId() const; const SceneViewportRotateGizmoDrawData& GetDrawData() const; SceneViewportRotateGizmoHitResult EvaluateHit(const Math::Vector2& mousePosition) const; void SetHoveredHandle(SceneViewportRotateGizmoAxis axis); private: void BuildDrawData(const SceneViewportRotateGizmoContext& context); void RefreshHandleState(); bool TryGetClosestRingAngle( SceneViewportRotateGizmoAxis axis, const Math::Vector2& mousePosition, bool allowBackFacing, float& outAngle) const; SceneViewportRotateGizmoDrawData m_drawData = {}; SceneViewportRotateGizmoAxis m_hoveredAxis = SceneViewportRotateGizmoAxis::None; SceneViewportRotateGizmoAxis m_activeAxis = SceneViewportRotateGizmoAxis::None; uint64_t m_activeEntityId = 0; bool m_screenSpaceDrag = false; bool m_localSpace = false; bool m_rotateAroundSharedPivot = false; Math::Vector3 m_activeWorldAxis = Math::Vector3::Zero(); Math::Plane m_dragPlane = {}; float m_dragStartRingAngle = 0.0f; float m_dragCurrentDeltaRadians = 0.0f; Math::Vector3 m_dragStartPivotWorldPosition = Math::Vector3::Zero(); std::vector m_dragObjects = {}; std::vector m_dragStartWorldPositions = {}; std::vector m_dragStartWorldRotations = {}; }; } // namespace Editor } // namespace XCEngine