Add scene viewport move gizmo workflow
This commit is contained in:
@@ -5,6 +5,7 @@ project(XCEngine_EditorTests)
|
||||
set(EDITOR_TEST_SOURCES
|
||||
test_action_routing.cpp
|
||||
test_scene_viewport_camera_controller.cpp
|
||||
test_scene_viewport_move_gizmo.cpp
|
||||
test_scene_viewport_picker.cpp
|
||||
test_scene_viewport_overlay_renderer.cpp
|
||||
test_scene_viewport_selection_utils.cpp
|
||||
@@ -12,6 +13,7 @@ set(EDITOR_TEST_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Managers/SceneManager.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Managers/ProjectManager.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportPicker.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportMoveGizmo.cpp
|
||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportGrid.cpp
|
||||
)
|
||||
|
||||
|
||||
96
tests/editor/test_scene_viewport_move_gizmo.cpp
Normal file
96
tests/editor/test_scene_viewport_move_gizmo.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Core/EditorContext.h"
|
||||
#include "Managers/SceneManager.h"
|
||||
#include "Viewport/SceneViewportMoveGizmo.h"
|
||||
|
||||
namespace XCEngine::Editor {
|
||||
namespace {
|
||||
|
||||
class SceneViewportMoveGizmoTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
m_context.GetSceneManager().NewScene("Move Gizmo Test Scene");
|
||||
}
|
||||
|
||||
static SceneViewportOverlayData MakeOverlay() {
|
||||
SceneViewportOverlayData overlay = {};
|
||||
overlay.valid = true;
|
||||
overlay.cameraPosition = Math::Vector3(0.0f, 0.0f, -5.0f);
|
||||
overlay.cameraForward = Math::Vector3::Forward();
|
||||
overlay.cameraRight = Math::Vector3::Right();
|
||||
overlay.cameraUp = Math::Vector3::Up();
|
||||
overlay.verticalFovDegrees = 60.0f;
|
||||
overlay.nearClipPlane = 0.03f;
|
||||
overlay.farClipPlane = 2000.0f;
|
||||
return overlay;
|
||||
}
|
||||
|
||||
static SceneViewportMoveGizmoContext MakeContext(
|
||||
Components::GameObject* selectedObject,
|
||||
const Math::Vector2& mousePosition) {
|
||||
SceneViewportMoveGizmoContext context = {};
|
||||
context.overlay = MakeOverlay();
|
||||
context.viewportSize = Math::Vector2(800.0f, 600.0f);
|
||||
context.mousePosition = mousePosition;
|
||||
context.selectedObject = selectedObject;
|
||||
return context;
|
||||
}
|
||||
|
||||
SceneManager& GetSceneManager() {
|
||||
return dynamic_cast<SceneManager&>(m_context.GetSceneManager());
|
||||
}
|
||||
|
||||
EditorContext m_context;
|
||||
};
|
||||
|
||||
TEST_F(SceneViewportMoveGizmoTest, UpdateHighlightsXAxisWhenMouseIsNearXAxisHandle) {
|
||||
Components::GameObject* target = GetSceneManager().CreateEntity("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
m_context.GetSelectionManager().SetSelectedEntity(target->GetID());
|
||||
|
||||
SceneViewportMoveGizmo gizmo;
|
||||
gizmo.Update(MakeContext(target, Math::Vector2(436.0f, 300.0f)));
|
||||
|
||||
ASSERT_TRUE(gizmo.GetDrawData().visible);
|
||||
EXPECT_TRUE(gizmo.IsHoveringHandle());
|
||||
EXPECT_TRUE(gizmo.GetDrawData().handles[0].hovered);
|
||||
EXPECT_FALSE(gizmo.GetDrawData().handles[1].hovered);
|
||||
EXPECT_FALSE(gizmo.GetDrawData().handles[2].hovered);
|
||||
}
|
||||
|
||||
TEST_F(SceneViewportMoveGizmoTest, DraggingXAxisOnlyChangesWorldXAndCreatesUndoStep) {
|
||||
Components::GameObject* target = GetSceneManager().CreateEntity("Target");
|
||||
ASSERT_NE(target, nullptr);
|
||||
const uint64_t targetId = target->GetID();
|
||||
m_context.GetSelectionManager().SetSelectedEntity(target->GetID());
|
||||
|
||||
SceneViewportMoveGizmo gizmo;
|
||||
const auto startContext = MakeContext(target, Math::Vector2(436.0f, 300.0f));
|
||||
gizmo.Update(startContext);
|
||||
|
||||
ASSERT_TRUE(gizmo.TryBeginDrag(startContext, m_context.GetUndoManager()));
|
||||
ASSERT_TRUE(gizmo.IsActive());
|
||||
|
||||
const auto dragContext = MakeContext(target, Math::Vector2(500.0f, 300.0f));
|
||||
gizmo.Update(dragContext);
|
||||
gizmo.UpdateDrag(dragContext);
|
||||
gizmo.EndDrag(m_context.GetUndoManager());
|
||||
|
||||
const Math::Vector3 movedPosition = target->GetTransform()->GetPosition();
|
||||
EXPECT_GT(movedPosition.x, 0.05f);
|
||||
EXPECT_NEAR(movedPosition.y, 0.0f, 1e-4f);
|
||||
EXPECT_NEAR(movedPosition.z, 0.0f, 1e-4f);
|
||||
EXPECT_TRUE(m_context.GetUndoManager().CanUndo());
|
||||
|
||||
m_context.GetUndoManager().Undo();
|
||||
Components::GameObject* restoredTarget = GetSceneManager().GetEntity(targetId);
|
||||
ASSERT_NE(restoredTarget, nullptr);
|
||||
const Math::Vector3 restoredPosition = restoredTarget->GetTransform()->GetPosition();
|
||||
EXPECT_NEAR(restoredPosition.x, 0.0f, 1e-4f);
|
||||
EXPECT_NEAR(restoredPosition.y, 0.0f, 1e-4f);
|
||||
EXPECT_NEAR(restoredPosition.z, 0.0f, 1e-4f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace XCEngine::Editor
|
||||
@@ -48,9 +48,11 @@ bool IsPowerOfTenSpacing(float value) {
|
||||
} // namespace
|
||||
|
||||
using XCEngine::Editor::BuildSceneGridParameters;
|
||||
using XCEngine::Editor::BuildSceneViewportAxisDragPlaneNormal;
|
||||
using XCEngine::Editor::SceneViewportCameraController;
|
||||
using XCEngine::Editor::BuildSceneViewportProjectionMatrix;
|
||||
using XCEngine::Editor::BuildSceneViewportViewMatrix;
|
||||
using XCEngine::Editor::ProjectSceneViewportWorldPoint;
|
||||
using XCEngine::Editor::SceneGridParameters;
|
||||
using XCEngine::Editor::SceneViewportOverlayData;
|
||||
using XCEngine::Components::GameObject;
|
||||
@@ -219,3 +221,34 @@ TEST(SceneViewportOverlayRenderer_Test, ViewMatrixMatchesSceneCameraTransformCon
|
||||
cameraObject.GetTransform()->GetWorldToLocalMatrix(),
|
||||
1e-3f));
|
||||
}
|
||||
|
||||
TEST(SceneViewportOverlayRenderer_Test, ProjectSceneViewportWorldPointMapsOriginToViewportCenter) {
|
||||
SceneViewportOverlayData overlay = {};
|
||||
overlay.valid = true;
|
||||
overlay.cameraPosition = Vector3(0.0f, 0.0f, -5.0f);
|
||||
overlay.cameraForward = Vector3::Forward();
|
||||
overlay.cameraRight = Vector3::Right();
|
||||
overlay.cameraUp = Vector3::Up();
|
||||
overlay.verticalFovDegrees = 60.0f;
|
||||
overlay.nearClipPlane = 0.03f;
|
||||
overlay.farClipPlane = 2000.0f;
|
||||
|
||||
const auto projected = ProjectSceneViewportWorldPoint(overlay, 800.0f, 600.0f, Vector3::Zero());
|
||||
|
||||
EXPECT_TRUE(projected.visible);
|
||||
EXPECT_NEAR(projected.screenPosition.x, 400.0f, 1e-3f);
|
||||
EXPECT_NEAR(projected.screenPosition.y, 300.0f, 1e-3f);
|
||||
}
|
||||
|
||||
TEST(SceneViewportOverlayRenderer_Test, BuildSceneViewportAxisDragPlaneNormalFallsBackWhenForwardAlignsWithAxis) {
|
||||
SceneViewportOverlayData overlay = {};
|
||||
overlay.valid = true;
|
||||
overlay.cameraForward = Vector3::Right();
|
||||
overlay.cameraRight = Vector3::Back();
|
||||
overlay.cameraUp = Vector3::Up();
|
||||
|
||||
Vector3 planeNormal = Vector3::Zero();
|
||||
ASSERT_TRUE(BuildSceneViewportAxisDragPlaneNormal(overlay, Vector3::Right(), planeNormal));
|
||||
EXPECT_NEAR(Vector3::Dot(planeNormal, Vector3::Right()), 0.0f, 1e-4f);
|
||||
EXPECT_GT(planeNormal.SqrMagnitude(), 0.5f);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user