Files
XCEngine/editor/src/Viewport/SceneViewportRotateGizmo.h

134 lines
4.5 KiB
C
Raw Normal View History

2026-03-31 23:45:08 +08:00
#pragma once
#include "IViewportHostService.h"
#include <XCEngine/Core/Math/Color.h>
#include <XCEngine/Core/Math/Plane.h>
#include <XCEngine/Core/Math/Quaternion.h>
#include <XCEngine/Core/Math/Vector2.h>
#include <XCEngine/Core/Math/Vector3.h>
#include <array>
#include <cstdint>
#include <vector>
2026-03-31 23:45:08 +08:00
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;
2026-03-31 23:45:08 +08:00
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<SceneViewportRotateGizmoSegmentDrawData, kSceneViewportRotateGizmoSegmentCount> 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<Math::Vector2, kSceneViewportRotateGizmoAngleFillPointCount> arcPoints = {};
size_t arcPointCount = 0;
Math::Color fillColor = Math::Color::White();
Math::Color outlineColor = Math::Color::White();
bool visible = false;
};
2026-03-31 23:45:08 +08:00
struct SceneViewportRotateGizmoDrawData {
bool visible = false;
Math::Vector2 pivot = Math::Vector2::Zero();
std::array<SceneViewportRotateGizmoHandleDrawData, 4> handles = {};
SceneViewportRotateGizmoAngleFillDrawData angleFill = {};
2026-03-31 23:45:08 +08:00
};
struct SceneViewportRotateGizmoContext {
SceneViewportOverlayData overlay = {};
Math::Vector2 viewportSize = Math::Vector2::Zero();
Math::Vector2 mousePosition = Math::Vector2::Zero();
Components::GameObject* selectedObject = nullptr;
std::vector<Components::GameObject*> 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;
}
2026-03-31 23:45:08 +08:00
};
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);
2026-03-31 23:45:08 +08:00
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;
2026-03-31 23:45:08 +08:00
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<Components::GameObject*> m_dragObjects = {};
std::vector<Math::Vector3> m_dragStartWorldPositions = {};
std::vector<Math::Quaternion> m_dragStartWorldRotations = {};
2026-03-31 23:45:08 +08:00
};
} // namespace Editor
} // namespace XCEngine