643 lines
21 KiB
C++
643 lines
21 KiB
C++
#include "Features/Scene/LegacySceneViewportGizmo.h"
|
|
|
|
#include "Legacy/Viewport/LegacySceneViewportGizmoSupport.h"
|
|
#include "Scene/EditorSceneRuntime.h"
|
|
#include "Scene/SceneToolState.h"
|
|
|
|
#include <XCEngine/Components/CameraComponent.h>
|
|
#include <XCEngine/Components/GameObject.h>
|
|
#include <XCEngine/Components/MeshFilterComponent.h>
|
|
#include <XCEngine/Components/TransformComponent.h>
|
|
#include <XCEngine/Resources/Mesh/Mesh.h>
|
|
#include <XCEngine/Scene/Scene.h>
|
|
|
|
#include <utility>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::Components::CameraComponent;
|
|
using ::XCEngine::Components::GameObject;
|
|
using ::XCEngine::Components::MeshFilterComponent;
|
|
using ::XCEngine::Components::TransformComponent;
|
|
using ::XCEngine::Math::Color;
|
|
using ::XCEngine::Math::Quaternion;
|
|
using ::XCEngine::Math::Vector2;
|
|
using ::XCEngine::Math::Vector3;
|
|
using ::XCEngine::UI::UIColor;
|
|
using ::XCEngine::UI::UIPoint;
|
|
using ::XCEngine::UI::UIRect;
|
|
namespace LegacyViewport = ::XCEngine::UI::Editor::App::Legacy;
|
|
using LegacyViewport::BuildSceneViewportTransformGizmoOverlayFrameData;
|
|
using LegacyViewport::IUndoManager;
|
|
using LegacyViewport::SceneViewportMoveGizmo;
|
|
using LegacyViewport::SceneViewportMoveGizmoContext;
|
|
using LegacyViewport::SceneViewportOverlayData;
|
|
using LegacyViewport::SceneViewportOverlayFrameData;
|
|
using LegacyViewport::SceneViewportRotateGizmo;
|
|
using LegacyViewport::SceneViewportRotateGizmoContext;
|
|
using LegacyViewport::SceneViewportScaleGizmo;
|
|
using LegacyViewport::SceneViewportScaleGizmoContext;
|
|
using LegacyViewport::SceneViewportTransformGizmoHandleBuildInputs;
|
|
|
|
enum class ActiveLegacyGizmoKind : std::uint8_t {
|
|
None = 0,
|
|
Move,
|
|
Rotate,
|
|
Scale
|
|
};
|
|
|
|
struct LegacySelectionState {
|
|
GameObject* primaryObject = nullptr;
|
|
std::vector<GameObject*> selectedObjects = {};
|
|
Vector3 pivotWorldPosition = Vector3::Zero();
|
|
Quaternion primaryWorldRotation = Quaternion::Identity();
|
|
};
|
|
|
|
UIColor ToUIColor(const Color& color) {
|
|
return UIColor(color.r, color.g, color.b, color.a);
|
|
}
|
|
|
|
UIPoint ToScreenPoint(const Vector2& point, const UIRect& viewportRect) {
|
|
return UIPoint(viewportRect.x + point.x, viewportRect.y + point.y);
|
|
}
|
|
|
|
Vector2 ToLocalPoint(const UIRect& viewportRect, const UIPoint& point) {
|
|
return Vector2(point.x - viewportRect.x, point.y - viewportRect.y);
|
|
}
|
|
|
|
Quaternion ComputeStableWorldRotation(const GameObject* gameObject) {
|
|
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
|
|
return Quaternion::Identity();
|
|
}
|
|
|
|
return gameObject->GetTransform()->GetRotation().Normalized();
|
|
}
|
|
|
|
Vector3 ResolvePivotWorldPosition(const GameObject* gameObject) {
|
|
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
|
|
return Vector3::Zero();
|
|
}
|
|
|
|
return gameObject->GetTransform()->GetPosition();
|
|
}
|
|
|
|
Vector3 ResolveCenterWorldPosition(const GameObject* gameObject) {
|
|
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
|
|
return Vector3::Zero();
|
|
}
|
|
|
|
if (const MeshFilterComponent* meshFilter =
|
|
gameObject->GetComponent<MeshFilterComponent>();
|
|
meshFilter != nullptr) {
|
|
if (::XCEngine::Resources::Mesh* mesh = meshFilter->GetMesh();
|
|
mesh != nullptr && mesh->IsValid()) {
|
|
return gameObject->GetTransform()->TransformPoint(mesh->GetBounds().center);
|
|
}
|
|
}
|
|
|
|
return gameObject->GetTransform()->GetPosition();
|
|
}
|
|
|
|
LegacySelectionState BuildSelectionState(
|
|
EditorSceneRuntime& sceneRuntime,
|
|
bool useCenterPivot) {
|
|
LegacySelectionState state = {};
|
|
const auto selectedId = sceneRuntime.GetSelectedGameObjectId();
|
|
if (!selectedId.has_value()) {
|
|
return state;
|
|
}
|
|
|
|
GameObject* selectedObject =
|
|
sceneRuntime.GetActiveScene() != nullptr
|
|
? sceneRuntime.GetActiveScene()->FindByID(selectedId.value())
|
|
: nullptr;
|
|
if (selectedObject == nullptr || selectedObject->GetTransform() == nullptr) {
|
|
return state;
|
|
}
|
|
|
|
state.primaryObject = selectedObject;
|
|
state.selectedObjects.push_back(selectedObject);
|
|
state.primaryWorldRotation = ComputeStableWorldRotation(selectedObject);
|
|
state.pivotWorldPosition = useCenterPivot
|
|
? ResolveCenterWorldPosition(selectedObject)
|
|
: ResolvePivotWorldPosition(selectedObject);
|
|
return state;
|
|
}
|
|
|
|
SceneViewportOverlayData BuildOverlayData(const EditorSceneRuntime& sceneRuntime) {
|
|
SceneViewportOverlayData overlay = {};
|
|
const CameraComponent* camera = sceneRuntime.GetSceneViewCamera();
|
|
if (camera == nullptr || camera->GetGameObject() == nullptr) {
|
|
return overlay;
|
|
}
|
|
|
|
const TransformComponent* transform = camera->GetGameObject()->GetTransform();
|
|
if (transform == nullptr) {
|
|
return overlay;
|
|
}
|
|
|
|
overlay.valid = true;
|
|
overlay.cameraPosition = transform->GetPosition();
|
|
overlay.cameraForward = transform->GetForward();
|
|
overlay.cameraRight = transform->GetRight();
|
|
overlay.cameraUp = transform->GetUp();
|
|
overlay.verticalFovDegrees = camera->GetFieldOfView();
|
|
overlay.nearClipPlane = camera->GetNearClipPlane();
|
|
overlay.farClipPlane = camera->GetFarClipPlane();
|
|
overlay.orbitDistance = sceneRuntime.GetSceneViewOrbitDistance();
|
|
return overlay;
|
|
}
|
|
|
|
SceneViewportMoveGizmoContext BuildMoveContext(
|
|
const LegacySelectionState& selection,
|
|
const SceneViewportOverlayData& overlay,
|
|
const UIRect& viewportRect,
|
|
const Vector2& localPointer,
|
|
bool localSpace) {
|
|
SceneViewportMoveGizmoContext context = {};
|
|
context.overlay = overlay;
|
|
context.viewportSize = Vector2(viewportRect.width, viewportRect.height);
|
|
context.mousePosition = localPointer;
|
|
context.selectedObject = selection.primaryObject;
|
|
context.selectedObjects = selection.selectedObjects;
|
|
context.pivotWorldPosition = selection.pivotWorldPosition;
|
|
context.axisOrientation = localSpace
|
|
? selection.primaryWorldRotation
|
|
: Quaternion::Identity();
|
|
return context;
|
|
}
|
|
|
|
SceneViewportRotateGizmoContext BuildRotateContext(
|
|
const LegacySelectionState& selection,
|
|
const SceneViewportOverlayData& overlay,
|
|
const UIRect& viewportRect,
|
|
const Vector2& localPointer,
|
|
bool localSpace,
|
|
bool useCenterPivot) {
|
|
SceneViewportRotateGizmoContext context = {};
|
|
context.overlay = overlay;
|
|
context.viewportSize = Vector2(viewportRect.width, viewportRect.height);
|
|
context.mousePosition = localPointer;
|
|
context.selectedObject = selection.primaryObject;
|
|
context.selectedObjects = selection.selectedObjects;
|
|
context.pivotWorldPosition = selection.pivotWorldPosition;
|
|
context.axisOrientation = localSpace
|
|
? selection.primaryWorldRotation
|
|
: Quaternion::Identity();
|
|
context.localSpace = localSpace;
|
|
context.rotateAroundSharedPivot = useCenterPivot;
|
|
return context;
|
|
}
|
|
|
|
SceneViewportScaleGizmoContext BuildScaleContext(
|
|
const LegacySelectionState& selection,
|
|
const SceneViewportOverlayData& overlay,
|
|
const UIRect& viewportRect,
|
|
const Vector2& localPointer,
|
|
bool localSpace) {
|
|
SceneViewportScaleGizmoContext context = {};
|
|
context.overlay = overlay;
|
|
context.viewportSize = Vector2(viewportRect.width, viewportRect.height);
|
|
context.mousePosition = localPointer;
|
|
context.selectedObject = selection.primaryObject;
|
|
context.pivotWorldPosition = selection.pivotWorldPosition;
|
|
context.axisOrientation = localSpace
|
|
? selection.primaryWorldRotation
|
|
: Quaternion::Identity();
|
|
return context;
|
|
}
|
|
|
|
ActiveLegacyGizmoKind ResolveActiveGizmoKind(
|
|
const SceneViewportMoveGizmo& moveGizmo,
|
|
const SceneViewportRotateGizmo& rotateGizmo,
|
|
const SceneViewportScaleGizmo& scaleGizmo) {
|
|
if (moveGizmo.IsActive()) {
|
|
return ActiveLegacyGizmoKind::Move;
|
|
}
|
|
if (rotateGizmo.IsActive()) {
|
|
return ActiveLegacyGizmoKind::Rotate;
|
|
}
|
|
if (scaleGizmo.IsActive()) {
|
|
return ActiveLegacyGizmoKind::Scale;
|
|
}
|
|
|
|
return ActiveLegacyGizmoKind::None;
|
|
}
|
|
|
|
bool IsTransformToolMode(SceneToolMode mode) {
|
|
return mode == SceneToolMode::Transform;
|
|
}
|
|
|
|
bool ShouldShowMoveGizmo(SceneToolMode mode) {
|
|
return mode == SceneToolMode::Translate || IsTransformToolMode(mode);
|
|
}
|
|
|
|
bool ShouldShowRotateGizmo(SceneToolMode mode) {
|
|
return mode == SceneToolMode::Rotate || IsTransformToolMode(mode);
|
|
}
|
|
|
|
bool ShouldShowScaleGizmo(SceneToolMode mode) {
|
|
return mode == SceneToolMode::Scale || IsTransformToolMode(mode);
|
|
}
|
|
|
|
Vector2 ResolveUpdatePointerPosition(
|
|
const Vector2& pointerPosition,
|
|
bool hoverEnabled,
|
|
ActiveLegacyGizmoKind activeKind,
|
|
ActiveLegacyGizmoKind gizmoKind) {
|
|
if (!hoverEnabled && activeKind == ActiveLegacyGizmoKind::None) {
|
|
return Vector2(-1.0f, -1.0f);
|
|
}
|
|
|
|
if (activeKind != ActiveLegacyGizmoKind::None && activeKind != gizmoKind) {
|
|
return Vector2(-1.0f, -1.0f);
|
|
}
|
|
|
|
return pointerPosition;
|
|
}
|
|
|
|
class SceneGizmoUndoBridge final : public IUndoManager {
|
|
public:
|
|
void Bind(EditorSceneRuntime& sceneRuntime) {
|
|
m_sceneRuntime = &sceneRuntime;
|
|
}
|
|
|
|
void BeginInteractiveChange(const std::string& label) override {
|
|
if (m_sceneRuntime == nullptr || HasPendingInteractiveChange()) {
|
|
return;
|
|
}
|
|
|
|
SceneTransformSnapshot snapshot = {};
|
|
if (!m_sceneRuntime->CaptureSelectedTransformSnapshot(snapshot)) {
|
|
return;
|
|
}
|
|
|
|
m_pendingLabel = label;
|
|
m_beforeSnapshot = snapshot;
|
|
}
|
|
|
|
bool HasPendingInteractiveChange() const override {
|
|
return m_beforeSnapshot.IsValid();
|
|
}
|
|
|
|
void FinalizeInteractiveChange() override {
|
|
if (m_sceneRuntime == nullptr || !HasPendingInteractiveChange()) {
|
|
return;
|
|
}
|
|
|
|
SceneTransformSnapshot afterSnapshot = {};
|
|
m_sceneRuntime->CaptureSelectedTransformSnapshot(afterSnapshot);
|
|
m_sceneRuntime->RecordTransformEdit(m_beforeSnapshot, afterSnapshot);
|
|
m_pendingLabel.clear();
|
|
m_beforeSnapshot = {};
|
|
}
|
|
|
|
void CancelInteractiveChange() override {
|
|
if (m_sceneRuntime == nullptr || !HasPendingInteractiveChange()) {
|
|
return;
|
|
}
|
|
|
|
m_sceneRuntime->ApplyTransformSnapshot(m_beforeSnapshot);
|
|
m_pendingLabel.clear();
|
|
m_beforeSnapshot = {};
|
|
}
|
|
|
|
private:
|
|
EditorSceneRuntime* m_sceneRuntime = nullptr;
|
|
std::string m_pendingLabel = {};
|
|
SceneTransformSnapshot m_beforeSnapshot = {};
|
|
};
|
|
|
|
} // namespace
|
|
|
|
struct LegacySceneViewportGizmo::State {
|
|
SceneGizmoUndoBridge undoBridge = {};
|
|
SceneViewportMoveGizmo moveGizmo = {};
|
|
SceneViewportRotateGizmo rotateGizmo = {};
|
|
SceneViewportScaleGizmo scaleGizmo = {};
|
|
SceneViewportMoveGizmoContext moveContext = {};
|
|
SceneViewportRotateGizmoContext rotateContext = {};
|
|
SceneViewportScaleGizmoContext scaleContext = {};
|
|
LegacySceneViewportGizmoFrame frame = {};
|
|
};
|
|
|
|
LegacySceneViewportGizmo::LegacySceneViewportGizmo()
|
|
: m_state(std::make_unique<State>()) {
|
|
}
|
|
|
|
LegacySceneViewportGizmo::~LegacySceneViewportGizmo() = default;
|
|
|
|
LegacySceneViewportGizmo::LegacySceneViewportGizmo(LegacySceneViewportGizmo&&) noexcept =
|
|
default;
|
|
|
|
LegacySceneViewportGizmo& LegacySceneViewportGizmo::operator=(
|
|
LegacySceneViewportGizmo&&) noexcept = default;
|
|
|
|
void LegacySceneViewportGizmo::Refresh(
|
|
EditorSceneRuntime& sceneRuntime,
|
|
const UIRect& viewportRect,
|
|
const UIPoint& pointerScreen,
|
|
bool hoverEnabled) {
|
|
State& state = *m_state;
|
|
state.undoBridge.Bind(sceneRuntime);
|
|
state.frame = {};
|
|
state.frame.clipRect = viewportRect;
|
|
|
|
if (viewportRect.width <= 1.0f || viewportRect.height <= 1.0f) {
|
|
return;
|
|
}
|
|
|
|
const SceneViewportOverlayData overlay = BuildOverlayData(sceneRuntime);
|
|
if (!overlay.valid) {
|
|
CancelDrag(sceneRuntime);
|
|
return;
|
|
}
|
|
|
|
const bool useCenterPivot =
|
|
sceneRuntime.GetToolPivotMode() == SceneToolPivotMode::Center;
|
|
const bool localSpace =
|
|
sceneRuntime.GetToolSpaceMode() == SceneToolSpaceMode::Local;
|
|
const LegacySelectionState selection =
|
|
BuildSelectionState(sceneRuntime, useCenterPivot);
|
|
if (selection.primaryObject == nullptr) {
|
|
CancelDrag(sceneRuntime);
|
|
return;
|
|
}
|
|
|
|
const SceneToolMode toolMode = sceneRuntime.GetToolMode();
|
|
if (toolMode == SceneToolMode::View) {
|
|
CancelDrag(sceneRuntime);
|
|
return;
|
|
}
|
|
|
|
Vector2 localPointer = ToLocalPoint(viewportRect, pointerScreen);
|
|
const bool usingTransformTool = IsTransformToolMode(toolMode);
|
|
const bool showingMoveGizmo = ShouldShowMoveGizmo(toolMode);
|
|
const bool showingRotateGizmo = ShouldShowRotateGizmo(toolMode);
|
|
const bool showingScaleGizmo = ShouldShowScaleGizmo(toolMode);
|
|
SceneViewportTransformGizmoHandleBuildInputs inputs = {};
|
|
if (showingMoveGizmo) {
|
|
state.moveContext = BuildMoveContext(
|
|
selection,
|
|
overlay,
|
|
viewportRect,
|
|
localPointer,
|
|
localSpace);
|
|
if (state.moveGizmo.IsActive() &&
|
|
state.moveContext.selectedObject != nullptr &&
|
|
state.moveContext.selectedObject->GetID() !=
|
|
state.moveGizmo.GetActiveEntityId()) {
|
|
state.moveGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
} else if (state.moveGizmo.IsActive()) {
|
|
state.moveGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
|
|
if (showingRotateGizmo) {
|
|
state.rotateContext = BuildRotateContext(
|
|
selection,
|
|
overlay,
|
|
viewportRect,
|
|
localPointer,
|
|
localSpace,
|
|
useCenterPivot);
|
|
if (state.rotateGizmo.IsActive() &&
|
|
state.rotateContext.selectedObject != nullptr &&
|
|
state.rotateContext.selectedObject->GetID() !=
|
|
state.rotateGizmo.GetActiveEntityId()) {
|
|
state.rotateGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
} else if (state.rotateGizmo.IsActive()) {
|
|
state.rotateGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
|
|
if (showingScaleGizmo) {
|
|
state.scaleContext = BuildScaleContext(
|
|
selection,
|
|
overlay,
|
|
viewportRect,
|
|
localPointer,
|
|
localSpace);
|
|
state.scaleContext.uniformOnly = usingTransformTool;
|
|
if (state.scaleGizmo.IsActive() &&
|
|
state.scaleContext.selectedObject != nullptr &&
|
|
state.scaleContext.selectedObject->GetID() !=
|
|
state.scaleGizmo.GetActiveEntityId()) {
|
|
state.scaleGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
} else if (state.scaleGizmo.IsActive()) {
|
|
state.scaleGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
|
|
const ActiveLegacyGizmoKind activeKind = ResolveActiveGizmoKind(
|
|
state.moveGizmo,
|
|
state.rotateGizmo,
|
|
state.scaleGizmo);
|
|
|
|
if (showingMoveGizmo) {
|
|
SceneViewportMoveGizmoContext updateContext = state.moveContext;
|
|
updateContext.mousePosition = ResolveUpdatePointerPosition(
|
|
state.moveContext.mousePosition,
|
|
hoverEnabled,
|
|
activeKind,
|
|
ActiveLegacyGizmoKind::Move);
|
|
state.moveGizmo.Update(updateContext);
|
|
inputs.moveGizmo = &state.moveGizmo.GetDrawData();
|
|
inputs.moveEntityId = selection.primaryObject->GetID();
|
|
}
|
|
|
|
if (showingRotateGizmo) {
|
|
SceneViewportRotateGizmoContext updateContext = state.rotateContext;
|
|
updateContext.mousePosition = ResolveUpdatePointerPosition(
|
|
state.rotateContext.mousePosition,
|
|
hoverEnabled,
|
|
activeKind,
|
|
ActiveLegacyGizmoKind::Rotate);
|
|
state.rotateGizmo.Update(updateContext);
|
|
inputs.rotateGizmo = &state.rotateGizmo.GetDrawData();
|
|
inputs.rotateEntityId = selection.primaryObject->GetID();
|
|
}
|
|
|
|
if (showingScaleGizmo) {
|
|
SceneViewportScaleGizmoContext updateContext = state.scaleContext;
|
|
updateContext.mousePosition = ResolveUpdatePointerPosition(
|
|
state.scaleContext.mousePosition,
|
|
hoverEnabled,
|
|
activeKind,
|
|
ActiveLegacyGizmoKind::Scale);
|
|
state.scaleGizmo.Update(updateContext);
|
|
inputs.scaleGizmo = &state.scaleGizmo.GetDrawData();
|
|
inputs.scaleEntityId = selection.primaryObject->GetID();
|
|
}
|
|
|
|
const SceneViewportOverlayFrameData overlayFrame =
|
|
BuildSceneViewportTransformGizmoOverlayFrameData(overlay, inputs);
|
|
if (overlayFrame.screenTriangles.empty()) {
|
|
return;
|
|
}
|
|
|
|
state.frame.visible = true;
|
|
state.frame.triangles.reserve(overlayFrame.screenTriangles.size());
|
|
for (const auto& triangle : overlayFrame.screenTriangles) {
|
|
LegacySceneViewportTriangle triangleFrame = {};
|
|
triangleFrame.a =
|
|
ToScreenPoint(triangle.vertices[0].screenPosition, viewportRect);
|
|
triangleFrame.b =
|
|
ToScreenPoint(triangle.vertices[1].screenPosition, viewportRect);
|
|
triangleFrame.c =
|
|
ToScreenPoint(triangle.vertices[2].screenPosition, viewportRect);
|
|
triangleFrame.color = ToUIColor(triangle.vertices[0].color);
|
|
state.frame.triangles.push_back(std::move(triangleFrame));
|
|
}
|
|
}
|
|
|
|
bool LegacySceneViewportGizmo::TryBeginDrag(EditorSceneRuntime& sceneRuntime) {
|
|
State& state = *m_state;
|
|
state.undoBridge.Bind(sceneRuntime);
|
|
|
|
switch (sceneRuntime.GetToolMode()) {
|
|
case SceneToolMode::Translate:
|
|
return state.moveGizmo.TryBeginDrag(state.moveContext, state.undoBridge);
|
|
case SceneToolMode::Rotate:
|
|
return state.rotateGizmo.TryBeginDrag(state.rotateContext, state.undoBridge);
|
|
case SceneToolMode::Scale:
|
|
return state.scaleGizmo.TryBeginDrag(state.scaleContext, state.undoBridge);
|
|
case SceneToolMode::Transform:
|
|
if (state.scaleGizmo.EvaluateHit(state.scaleContext.mousePosition).HasHit()) {
|
|
return state.scaleGizmo.TryBeginDrag(
|
|
state.scaleContext,
|
|
state.undoBridge);
|
|
}
|
|
if (state.moveGizmo.EvaluateHit(state.moveContext.mousePosition).HasHit()) {
|
|
return state.moveGizmo.TryBeginDrag(
|
|
state.moveContext,
|
|
state.undoBridge);
|
|
}
|
|
if (state.rotateGizmo.EvaluateHit(state.rotateContext.mousePosition).HasHit()) {
|
|
return state.rotateGizmo.TryBeginDrag(
|
|
state.rotateContext,
|
|
state.undoBridge);
|
|
}
|
|
return false;
|
|
case SceneToolMode::View:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool LegacySceneViewportGizmo::UpdateDrag(EditorSceneRuntime& sceneRuntime) {
|
|
State& state = *m_state;
|
|
state.undoBridge.Bind(sceneRuntime);
|
|
|
|
switch (ResolveActiveGizmoKind(
|
|
state.moveGizmo,
|
|
state.rotateGizmo,
|
|
state.scaleGizmo)) {
|
|
case ActiveLegacyGizmoKind::Move:
|
|
state.moveGizmo.UpdateDrag(state.moveContext);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::Rotate:
|
|
state.rotateGizmo.UpdateDrag(state.rotateContext);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::Scale:
|
|
state.scaleGizmo.UpdateDrag(state.scaleContext);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::None:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool LegacySceneViewportGizmo::EndDrag(EditorSceneRuntime& sceneRuntime) {
|
|
State& state = *m_state;
|
|
state.undoBridge.Bind(sceneRuntime);
|
|
|
|
switch (ResolveActiveGizmoKind(
|
|
state.moveGizmo,
|
|
state.rotateGizmo,
|
|
state.scaleGizmo)) {
|
|
case ActiveLegacyGizmoKind::Move:
|
|
state.moveGizmo.EndDrag(state.undoBridge);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::Rotate:
|
|
state.rotateGizmo.EndDrag(state.undoBridge);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::Scale:
|
|
state.scaleGizmo.EndDrag(state.undoBridge);
|
|
return true;
|
|
case ActiveLegacyGizmoKind::None:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void LegacySceneViewportGizmo::CancelDrag(EditorSceneRuntime& sceneRuntime) {
|
|
State& state = *m_state;
|
|
state.undoBridge.Bind(sceneRuntime);
|
|
|
|
if (state.moveGizmo.IsActive()) {
|
|
state.moveGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
if (state.rotateGizmo.IsActive()) {
|
|
state.rotateGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
if (state.scaleGizmo.IsActive()) {
|
|
state.scaleGizmo.CancelDrag(&state.undoBridge);
|
|
}
|
|
}
|
|
|
|
void LegacySceneViewportGizmo::ResetVisualState() {
|
|
if (m_state == nullptr) {
|
|
return;
|
|
}
|
|
|
|
m_state->frame = {};
|
|
}
|
|
|
|
bool LegacySceneViewportGizmo::IsActive() const {
|
|
if (m_state == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return ResolveActiveGizmoKind(
|
|
m_state->moveGizmo,
|
|
m_state->rotateGizmo,
|
|
m_state->scaleGizmo) != ActiveLegacyGizmoKind::None;
|
|
}
|
|
|
|
bool LegacySceneViewportGizmo::IsHoveringHandle() const {
|
|
if (m_state == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return m_state->moveGizmo.IsHoveringHandle() ||
|
|
m_state->rotateGizmo.IsHoveringHandle() ||
|
|
m_state->scaleGizmo.IsHoveringHandle();
|
|
}
|
|
|
|
const LegacySceneViewportGizmoFrame& LegacySceneViewportGizmo::GetFrame() const {
|
|
return m_state->frame;
|
|
}
|
|
|
|
void AppendLegacySceneViewportGizmo(
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
const LegacySceneViewportGizmoFrame& frame) {
|
|
if (!frame.visible || frame.triangles.empty()) {
|
|
return;
|
|
}
|
|
|
|
drawList.PushClipRect(frame.clipRect);
|
|
for (const LegacySceneViewportTriangle& triangle : frame.triangles) {
|
|
drawList.AddFilledTriangle(
|
|
triangle.a,
|
|
triangle.b,
|
|
triangle.c,
|
|
triangle.color);
|
|
}
|
|
drawList.PopClipRect();
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|