Unify editor scene edit history
This commit is contained in:
@@ -451,7 +451,129 @@ TEST(SceneViewportRuntimeTests, TransformSetterApisWriteLocalValuesOnSelectedTra
|
||||
EXPECT_FLOAT_EQ(scale.x, 2.0f);
|
||||
EXPECT_FLOAT_EQ(scale.y, 3.0f);
|
||||
EXPECT_FLOAT_EQ(scale.z, 4.0f);
|
||||
EXPECT_TRUE(runtime.CanUndoTransformEdit());
|
||||
EXPECT_TRUE(runtime.CanUndoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.UndoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
|
||||
const Math::Vector3 undonePosition = transform->GetLocalPosition();
|
||||
const Math::Quaternion undoneRotation = transform->GetLocalRotation();
|
||||
const Math::Vector3 undoneScale = transform->GetLocalScale();
|
||||
EXPECT_FLOAT_EQ(undonePosition.x, 8.0f);
|
||||
EXPECT_FLOAT_EQ(undonePosition.y, 9.0f);
|
||||
EXPECT_FLOAT_EQ(undonePosition.z, 10.0f);
|
||||
EXPECT_GT(std::abs(undoneRotation.Dot(expectedRotation)), 0.9999f);
|
||||
EXPECT_FLOAT_EQ(undoneScale.x, 1.0f);
|
||||
EXPECT_FLOAT_EQ(undoneScale.y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(undoneScale.z, 1.0f);
|
||||
EXPECT_TRUE(runtime.CanRedoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.RedoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
|
||||
const Math::Vector3 redoneScale = transform->GetLocalScale();
|
||||
EXPECT_FLOAT_EQ(redoneScale.x, 2.0f);
|
||||
EXPECT_FLOAT_EQ(redoneScale.y, 3.0f);
|
||||
EXPECT_FLOAT_EQ(redoneScale.z, 4.0f);
|
||||
}
|
||||
|
||||
TEST(SceneViewportRuntimeTests, DeleteGameObjectUndoRedoRestoresSceneAndSelection) {
|
||||
ScopedSceneManagerReset reset = {};
|
||||
TemporaryProjectRoot projectRoot = {};
|
||||
SaveMainScene(projectRoot, Math::Vector3(0.0f, 0.0f, 0.0f));
|
||||
|
||||
EditorSceneRuntime runtime = {};
|
||||
BindEngineSceneBackend(runtime);
|
||||
ASSERT_TRUE(runtime.Initialize(projectRoot.Root()));
|
||||
|
||||
Scene* scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
GameObject* secondary = scene->CreateGameObject("Secondary");
|
||||
ASSERT_NE(secondary, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(secondary->GetID()));
|
||||
|
||||
const std::string secondaryItemId =
|
||||
MakeEditorGameObjectItemId(secondary->GetID());
|
||||
ASSERT_TRUE(runtime.DeleteGameObject(secondaryItemId));
|
||||
EXPECT_EQ(scene->Find("Secondary"), nullptr);
|
||||
EXPECT_EQ(runtime.GetSelectedDisplayName(), "Target");
|
||||
EXPECT_TRUE(runtime.CanUndoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.UndoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
GameObject* restoredSecondary = scene->Find("Secondary");
|
||||
ASSERT_NE(restoredSecondary, nullptr);
|
||||
ASSERT_TRUE(runtime.GetSelectedObjectId().has_value());
|
||||
EXPECT_EQ(runtime.GetSelectedObjectId().value(), restoredSecondary->GetID());
|
||||
EXPECT_EQ(runtime.GetSelectedDisplayName(), "Secondary");
|
||||
EXPECT_TRUE(runtime.CanRedoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.RedoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
EXPECT_EQ(scene->Find("Secondary"), nullptr);
|
||||
EXPECT_EQ(runtime.GetSelectedDisplayName(), "Target");
|
||||
}
|
||||
|
||||
TEST(SceneViewportRuntimeTests, RemoveSelectedComponentUndoRedoRestoresComponentDescriptors) {
|
||||
ScopedSceneManagerReset reset = {};
|
||||
TemporaryProjectRoot projectRoot = {};
|
||||
SaveMainScene(projectRoot, Math::Vector3(0.0f, 0.0f, 0.0f));
|
||||
|
||||
EditorSceneRuntime runtime = {};
|
||||
BindEngineSceneBackend(runtime);
|
||||
ASSERT_TRUE(runtime.Initialize(projectRoot.Root()));
|
||||
|
||||
Scene* scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
GameObject* target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
ASSERT_NE(target->AddComponent<::XCEngine::Components::CameraComponent>(), nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()));
|
||||
|
||||
ASSERT_TRUE(runtime.RemoveSelectedComponent("Camera#0"));
|
||||
std::vector<EditorSceneComponentDescriptor> descriptors =
|
||||
runtime.GetSelectedComponents();
|
||||
ASSERT_EQ(descriptors.size(), 1u);
|
||||
EXPECT_EQ(descriptors[0].typeName, "Transform");
|
||||
EXPECT_TRUE(runtime.CanUndoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.UndoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()) ||
|
||||
(runtime.GetSelectedObjectId().has_value() &&
|
||||
runtime.GetSelectedObjectId().value() == target->GetID()));
|
||||
descriptors = runtime.GetSelectedComponents();
|
||||
ASSERT_EQ(descriptors.size(), 2u);
|
||||
EXPECT_NE(FindComponentDescriptor(descriptors, "Camera"), nullptr);
|
||||
EXPECT_NE(target->GetComponent<::XCEngine::Components::CameraComponent>(), nullptr);
|
||||
EXPECT_TRUE(runtime.CanRedoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.RedoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()) ||
|
||||
(runtime.GetSelectedObjectId().has_value() &&
|
||||
runtime.GetSelectedObjectId().value() == target->GetID()));
|
||||
descriptors = runtime.GetSelectedComponents();
|
||||
ASSERT_EQ(descriptors.size(), 1u);
|
||||
EXPECT_EQ(target->GetComponent<::XCEngine::Components::CameraComponent>(), nullptr);
|
||||
}
|
||||
|
||||
TEST(SceneViewportRuntimeTests, SelectionStampAdvancesOnSceneSelectionChanges) {
|
||||
@@ -1027,27 +1149,31 @@ TEST(SceneViewportRuntimeTests, TranslateGizmoDragAppliesPreviewToSelectedObject
|
||||
auto* transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
|
||||
SceneViewportTransformGizmo gizmo = {};
|
||||
const UIRect viewportRect(0.0f, 0.0f, 640.0f, 360.0f);
|
||||
const std::optional<UIPoint> hoverPoint =
|
||||
FindHoveredTransformGizmoPoint(gizmo, runtime, session, viewportRect);
|
||||
ASSERT_TRUE(hoverPoint.has_value());
|
||||
|
||||
const std::array<UIPoint, 6u> dragTargets = {
|
||||
UIPoint(hoverPoint->x + 40.0f, hoverPoint->y),
|
||||
UIPoint(hoverPoint->x - 40.0f, hoverPoint->y),
|
||||
UIPoint(hoverPoint->x, hoverPoint->y + 40.0f),
|
||||
UIPoint(hoverPoint->x, hoverPoint->y - 40.0f),
|
||||
UIPoint(hoverPoint->x + 32.0f, hoverPoint->y + 32.0f),
|
||||
UIPoint(hoverPoint->x - 32.0f, hoverPoint->y - 32.0f)
|
||||
const std::array<UIPoint, 6u> dragOffsets = {
|
||||
UIPoint(40.0f, 0.0f),
|
||||
UIPoint(-40.0f, 0.0f),
|
||||
UIPoint(0.0f, 40.0f),
|
||||
UIPoint(0.0f, -40.0f),
|
||||
UIPoint(32.0f, 32.0f),
|
||||
UIPoint(-32.0f, -32.0f)
|
||||
};
|
||||
|
||||
bool previewApplied = false;
|
||||
for (const UIPoint& dragPoint : dragTargets) {
|
||||
for (const UIPoint& dragOffset : dragOffsets) {
|
||||
SceneViewportTransformGizmo gizmo = {};
|
||||
transform->SetPosition(Math::Vector3(0.0f, 0.0f, 0.0f));
|
||||
const std::optional<UIPoint> hoverPoint =
|
||||
FindHoveredTransformGizmoPoint(gizmo, runtime, session, viewportRect);
|
||||
ASSERT_TRUE(hoverPoint.has_value());
|
||||
const UIPoint dragPoint(
|
||||
hoverPoint->x + dragOffset.x,
|
||||
hoverPoint->y + dragOffset.y);
|
||||
|
||||
gizmo.Refresh(runtime, session, viewportRect, hoverPoint.value(), true);
|
||||
ASSERT_TRUE(gizmo.IsHoveringHandle());
|
||||
ASSERT_TRUE(gizmo.TryBeginDrag(runtime, session));
|
||||
EXPECT_TRUE(runtime.HasPendingSceneEditTransaction());
|
||||
|
||||
gizmo.Refresh(runtime, session, viewportRect, dragPoint, true);
|
||||
ASSERT_TRUE(gizmo.UpdateDrag(runtime));
|
||||
@@ -1058,15 +1184,127 @@ TEST(SceneViewportRuntimeTests, TranslateGizmoDragAppliesPreviewToSelectedObject
|
||||
std::abs(previewPosition.z) > 0.0001f) {
|
||||
previewApplied = true;
|
||||
gizmo.CancelDrag(runtime);
|
||||
EXPECT_FALSE(runtime.HasPendingSceneEditTransaction());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()) ||
|
||||
(runtime.GetSelectedObjectId().has_value() &&
|
||||
runtime.GetSelectedObjectId().value() == target->GetID()));
|
||||
const Math::Vector3 canceledPosition = transform->GetPosition();
|
||||
EXPECT_FLOAT_EQ(canceledPosition.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(canceledPosition.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(canceledPosition.z, 0.0f);
|
||||
EXPECT_FALSE(runtime.CanUndoSceneEdit());
|
||||
break;
|
||||
}
|
||||
|
||||
gizmo.CancelDrag(runtime);
|
||||
EXPECT_FALSE(runtime.HasPendingSceneEditTransaction());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()) ||
|
||||
(runtime.GetSelectedObjectId().has_value() &&
|
||||
runtime.GetSelectedObjectId().value() == target->GetID()));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(previewApplied);
|
||||
}
|
||||
|
||||
TEST(SceneViewportRuntimeTests, TranslateGizmoEndDragRecordsUnifiedSceneEditHistory) {
|
||||
ScopedSceneManagerReset reset = {};
|
||||
TemporaryProjectRoot projectRoot = {};
|
||||
SaveMainScene(projectRoot, Math::Vector3(0.0f, 0.0f, 0.0f));
|
||||
|
||||
EditorSceneRuntime runtime = {};
|
||||
BindEngineSceneBackend(runtime);
|
||||
ASSERT_TRUE(runtime.Initialize(projectRoot.Root()));
|
||||
SceneViewportSession session = {};
|
||||
session.SetToolMode(SceneToolMode::Translate);
|
||||
runtime.EnsureSceneSelection();
|
||||
|
||||
Scene* scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
GameObject* target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
auto* transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
|
||||
const UIRect viewportRect(0.0f, 0.0f, 640.0f, 360.0f);
|
||||
const std::array<UIPoint, 6u> dragOffsets = {
|
||||
UIPoint(40.0f, 0.0f),
|
||||
UIPoint(-40.0f, 0.0f),
|
||||
UIPoint(0.0f, 40.0f),
|
||||
UIPoint(0.0f, -40.0f),
|
||||
UIPoint(32.0f, 32.0f),
|
||||
UIPoint(-32.0f, -32.0f)
|
||||
};
|
||||
|
||||
bool committed = false;
|
||||
for (const UIPoint& dragOffset : dragOffsets) {
|
||||
SceneViewportTransformGizmo gizmo = {};
|
||||
transform->SetPosition(Math::Vector3(0.0f, 0.0f, 0.0f));
|
||||
const std::optional<UIPoint> hoverPoint =
|
||||
FindHoveredTransformGizmoPoint(gizmo, runtime, session, viewportRect);
|
||||
ASSERT_TRUE(hoverPoint.has_value());
|
||||
const UIPoint dragPoint(
|
||||
hoverPoint->x + dragOffset.x,
|
||||
hoverPoint->y + dragOffset.y);
|
||||
|
||||
gizmo.Refresh(runtime, session, viewportRect, hoverPoint.value(), true);
|
||||
ASSERT_TRUE(gizmo.IsHoveringHandle());
|
||||
ASSERT_TRUE(gizmo.TryBeginDrag(runtime, session));
|
||||
|
||||
gizmo.Refresh(runtime, session, viewportRect, dragPoint, true);
|
||||
ASSERT_TRUE(gizmo.UpdateDrag(runtime));
|
||||
|
||||
const Math::Vector3 previewPosition = transform->GetPosition();
|
||||
if (std::abs(previewPosition.x) <= 0.0001f &&
|
||||
std::abs(previewPosition.y) <= 0.0001f &&
|
||||
std::abs(previewPosition.z) <= 0.0001f) {
|
||||
gizmo.CancelDrag(runtime);
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
ASSERT_TRUE(runtime.SetSelection(target->GetID()) ||
|
||||
(runtime.GetSelectedObjectId().has_value() &&
|
||||
runtime.GetSelectedObjectId().value() == target->GetID()));
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(gizmo.EndDrag(runtime));
|
||||
committed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(committed);
|
||||
EXPECT_FALSE(runtime.HasPendingSceneEditTransaction());
|
||||
EXPECT_TRUE(runtime.CanUndoSceneEdit());
|
||||
|
||||
ASSERT_TRUE(runtime.UndoSceneEdit());
|
||||
scene = GetLoadedActiveScene();
|
||||
ASSERT_NE(scene, nullptr);
|
||||
target = scene->Find("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
transform = target->GetTransform();
|
||||
ASSERT_NE(transform, nullptr);
|
||||
const Math::Vector3 undonePosition = transform->GetPosition();
|
||||
EXPECT_FLOAT_EQ(undonePosition.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(undonePosition.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(undonePosition.z, 0.0f);
|
||||
EXPECT_TRUE(runtime.CanRedoSceneEdit());
|
||||
}
|
||||
|
||||
TEST(SceneViewportRuntimeTests, SceneViewportRendererDeclaresExplicitAuxiliaryResourceRequirements) {
|
||||
const ViewportResourceRequirements requirements =
|
||||
SceneViewportRenderService::GetViewportResourceRequirements();
|
||||
|
||||
Reference in New Issue
Block a user