Add scene transform toolbar and scale gizmo

This commit is contained in:
2026-04-01 16:42:57 +08:00
parent 4e8ad9a706
commit 3f18530396
23 changed files with 1668 additions and 198 deletions

View File

@@ -221,6 +221,62 @@ TEST_F(SceneViewportRotateGizmoTest, DraggingXAxisRotatesAroundWorldXAndCreatesU
EXPECT_NEAR(restoredForward.z, 1.0f, 1e-4f);
}
TEST_F(SceneViewportRotateGizmoTest, DraggingXAxisShowsAngleFillAndTemporarilyRotatesOtherRings) {
Components::GameObject* target = GetSceneManager().CreateEntity("Target");
ASSERT_NE(target, nullptr);
SceneViewportRotateGizmo gizmo;
const SceneViewportOverlayData overlay = MakeIsometricOverlay();
gizmo.Update(MakeContext(target, Math::Vector2(400.0f, 300.0f), overlay));
const SceneViewportRotateGizmoHandleDrawData* xHandle =
FindHandle(gizmo.GetDrawData(), SceneViewportRotateGizmoAxis::X);
const SceneViewportRotateGizmoHandleDrawData* yHandle =
FindHandle(gizmo.GetDrawData(), SceneViewportRotateGizmoAxis::Y);
ASSERT_NE(xHandle, nullptr);
ASSERT_NE(yHandle, nullptr);
const SceneViewportRotateGizmoSegmentDrawData* xStartSegment = FindLongestVisibleSegment(*xHandle, true);
const SceneViewportRotateGizmoSegmentDrawData* xEndSegment =
FindFarthestVisibleSegment(*xHandle, SegmentMidpoint(*xStartSegment), true);
const SceneViewportRotateGizmoSegmentDrawData* yInitialSegment = FindLongestVisibleSegment(*yHandle, false);
ASSERT_NE(xStartSegment, nullptr);
ASSERT_NE(xEndSegment, nullptr);
ASSERT_NE(yInitialSegment, nullptr);
const Math::Vector2 initialYMidpoint = SegmentMidpoint(*yInitialSegment);
const auto startContext = MakeContext(target, SegmentMidpoint(*xStartSegment), overlay);
gizmo.Update(startContext);
ASSERT_TRUE(gizmo.TryBeginDrag(startContext, m_context.GetUndoManager()));
const auto dragContext = MakeContext(target, SegmentMidpoint(*xEndSegment), overlay);
gizmo.Update(dragContext);
gizmo.UpdateDrag(dragContext);
ASSERT_TRUE(gizmo.GetDrawData().angleFill.visible);
EXPECT_GT(gizmo.GetDrawData().angleFill.arcPointCount, 2u);
const SceneViewportRotateGizmoHandleDrawData* yHandleDuring =
FindHandle(gizmo.GetDrawData(), SceneViewportRotateGizmoAxis::Y);
ASSERT_NE(yHandleDuring, nullptr);
const SceneViewportRotateGizmoSegmentDrawData* yDuringSegment = FindLongestVisibleSegment(*yHandleDuring, false);
ASSERT_NE(yDuringSegment, nullptr);
const Math::Vector2 duringYMidpoint = SegmentMidpoint(*yDuringSegment);
EXPECT_GT((duringYMidpoint - initialYMidpoint).Magnitude(), 2.0f);
gizmo.EndDrag(m_context.GetUndoManager());
gizmo.Update(dragContext);
EXPECT_FALSE(gizmo.GetDrawData().angleFill.visible);
const SceneViewportRotateGizmoHandleDrawData* yHandleAfter =
FindHandle(gizmo.GetDrawData(), SceneViewportRotateGizmoAxis::Y);
ASSERT_NE(yHandleAfter, nullptr);
const SceneViewportRotateGizmoSegmentDrawData* yAfterSegment = FindLongestVisibleSegment(*yHandleAfter, false);
ASSERT_NE(yAfterSegment, nullptr);
const Math::Vector2 afterYMidpoint = SegmentMidpoint(*yAfterSegment);
EXPECT_LT((afterYMidpoint - initialYMidpoint).Magnitude(), 1.0f);
}
TEST_F(SceneViewportRotateGizmoTest, DraggingEdgeOnXAxisFallsBackToScreenSpaceRotation) {
Components::GameObject* target = GetSceneManager().CreateEntity("Target");
ASSERT_NE(target, nullptr);