/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include "TestColliderComponent.h" #include #include #include #include #include #include #include namespace UnitTest { class PhysXColliderComponentModeTest : public ToolsApplicationFixture { protected: using EntityPtr = AZ::Entity*; AZ::ComponentId m_colliderComponentId; EntityPtr CreateColliderComponent() { AZ::Entity* entity = nullptr; AZ::EntityId entityId = CreateDefaultEditorEntity("ComponentModeEntity", &entity); entity->Deactivate(); // Add placeholder component which implements component mode. auto colliderComponent = entity->CreateComponent(); m_colliderComponentId = colliderComponent->GetId(); entity->Activate(); AzToolsFramework::SelectEntity(entityId); return entity; } // Needed to support ViewportUi request calls. ViewportManagerWrapper m_viewportManagerWrapper; void SetUpEditorFixtureImpl() override { m_viewportManagerWrapper.Create(); } void TearDownEditorFixtureImpl() override { m_viewportManagerWrapper.Destroy(); } }; TEST_F(PhysXColliderComponentModeTest, MouseWheelUpShouldSetNextMode) { // Given there is a collider component in component mode. CreateColliderComponent(); EnterComponentMode(); PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // When the mouse wheel is scrolled while holding ctrl AzToolsFramework::ViewportInteraction::MouseInteractionEvent interactionEvent(AzToolsFramework::ViewportInteraction::MouseInteraction(), 1.0f); interactionEvent.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Wheel; interactionEvent.m_mouseInteraction.m_keyboardModifiers.m_keyModifiers = static_cast(AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl); using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult; MouseInteractionResult handled = MouseInteractionResult::None; AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::BroadcastResult(handled, &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, interactionEvent); // Then the component mode is cycled. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(handled, MouseInteractionResult::Viewport); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Offset, subMode); } TEST_F(PhysXColliderComponentModeTest, MouseWheelDownShouldSetPreviousMode) { // Given there is a collider component in component mode. CreateColliderComponent(); EnterComponentMode(); PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // When the mouse wheel is scrolled while holding ctrl AzToolsFramework::ViewportInteraction::MouseInteractionEvent interactionEvent(AzToolsFramework::ViewportInteraction::MouseInteraction(), -1.0f); interactionEvent.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Wheel; interactionEvent.m_mouseInteraction.m_keyboardModifiers.m_keyModifiers = static_cast(AzToolsFramework::ViewportInteraction::KeyboardModifier::Ctrl); using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult; MouseInteractionResult handled = MouseInteractionResult::None; AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::BroadcastResult(handled, &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, interactionEvent); // Then the component mode is cycled. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(handled, MouseInteractionResult::Viewport); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Rotation, subMode); } TEST_F(PhysXColliderComponentModeTest, PressingKey1ShouldSetSizeMode) { // Given there is a collider component in component mode. CreateColliderComponent(); EnterComponentMode(); PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // When the '1' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_1); // Then the component mode is set to Size. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); } TEST_F(PhysXColliderComponentModeTest, PressingKey2ShouldSetSizeMode) { // Given there is a collider component in component mode. auto colliderEntity = CreateColliderComponent(); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // When the '2' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_2); // Then the component mode is set to Offset. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Offset, subMode); } TEST_F(PhysXColliderComponentModeTest, PressingKey3ShouldSetSizeMode) { // Given there is a collider component in component mode. auto colliderEntity = CreateColliderComponent(); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // When the '3' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_3); // Then the component mode is set to Rotation. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Rotation, subMode); } TEST_F(PhysXColliderComponentModeTest, PressingKeyRShouldResetSphereRadius) { // Given there is a sphere collider in component mode. auto colliderEntity = CreateColliderComponent(); float radius = 5.0f; colliderEntity->FindComponent()->SetShapeType(Physics::ShapeType::Sphere); colliderEntity->FindComponent()->SetSphereRadius(radius); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, PhysX::ColliderComponentModeRequests::SubMode::Dimensions); // When the 'R' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_R); // The the sphere radius should be reset. radius = colliderEntity->FindComponent()->GetSphereRadius(); EXPECT_FLOAT_EQ(0.5f, radius); } TEST_F(PhysXColliderComponentModeTest, PressingKeyRShouldResetCapsuleSize) { // Given there is a capsule collider in component mode. auto colliderEntity = CreateColliderComponent(); float height = 10.0f; float radius = 2.5f; colliderEntity->FindComponent()->SetShapeType(Physics::ShapeType::Capsule); colliderEntity->FindComponent()->SetCapsuleHeight(height); colliderEntity->FindComponent()->SetCapsuleRadius(radius); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, PhysX::ColliderComponentModeRequests::SubMode::Dimensions); // When the 'R' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_R); // Then the capsule size should be reset. height = colliderEntity->FindComponent()->GetCapsuleHeight(); radius = colliderEntity->FindComponent()->GetCapsuleRadius(); EXPECT_FLOAT_EQ(1.0f, height); EXPECT_FLOAT_EQ(0.25f, radius); } TEST_F(PhysXColliderComponentModeTest, PressingKeyRShouldResetAssetScale) { // Given there is a sphere collider component in component mode. auto colliderEntity = CreateColliderComponent(); AZ::Vector3 assetScale(10.0f, 10.0f, 10.0f); colliderEntity->FindComponent()->SetShapeType(Physics::ShapeType::PhysicsAsset); colliderEntity->FindComponent()->SetAssetScale(assetScale); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, PhysX::ColliderComponentModeRequests::SubMode::Dimensions); // When the 'R' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_R); // Then the asset scale should be reset. assetScale = colliderEntity->FindComponent()->GetAssetScale(); EXPECT_THAT(assetScale, IsClose(AZ::Vector3::CreateOne())); } TEST_F(PhysXColliderComponentModeTest, PressingKeyRShouldResetOffset) { // Given there is a sphere collider component in component mode. auto colliderEntity = CreateColliderComponent(); AZ::Vector3 offset(5.0f, 6.0f, 7.0f); colliderEntity->FindComponent()->SetColliderOffset(offset); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, PhysX::ColliderComponentModeRequests::SubMode::Offset); // When the 'R' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_R); // Then the collider offset should be reset. offset = colliderEntity->FindComponent()->GetColliderOffset(); EXPECT_THAT(offset, IsClose(AZ::Vector3::CreateZero())); } TEST_F(PhysXColliderComponentModeTest, PressingKeyRShouldResetRotation) { // Given there is a sphere collider component in component mode. auto colliderEntity = CreateColliderComponent(); AZ::Quaternion rotation = AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), 45.0f); colliderEntity->FindComponent()->SetColliderRotation(rotation); AzToolsFramework::SelectEntity(colliderEntity->GetId()); EnterComponentMode(); PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, PhysX::ColliderComponentModeRequests::SubMode::Rotation); // When the 'R' key is pressed QTest::keyPress(&m_editorActions.m_componentModeWidget, Qt::Key_R); // Then the collider rotation should be reset. rotation = colliderEntity->FindComponent()->GetColliderRotation(); EXPECT_THAT(rotation, IsClose(AZ::Quaternion::CreateIdentity())); } TEST_F(PhysXColliderComponentModeTest, ClickingOffsetButtonShouldSetOffsetMode) { // Given there is a collider component in component mode. auto colliderEntity = CreateColliderComponent(); EnterComponentMode(); // Given // Check preconditions PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // Get the cluster and button Ids AzToolsFramework::ViewportUi::ClusterId modeSelectionClusterId; AzToolsFramework::ViewportUi::ButtonId offsetModeButtonId; AZ::EntityId entityId = colliderEntity->GetId(); PhysX::ColliderComponentModeUiRequestBus::EventResult( modeSelectionClusterId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetClusterId); PhysX::ColliderComponentModeUiRequestBus::EventResult( offsetModeButtonId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetOffsetButtonId); // When // Trigger the button m_viewportManagerWrapper.GetViewportManager()->PressButton(modeSelectionClusterId, offsetModeButtonId); // Then // Then the component mode is set to Offset. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Offset, subMode); } TEST_F(PhysXColliderComponentModeTest, ClickingRotationButtonShouldSetRotationMode) { // Given there is a collider component in component mode. auto colliderEntity = CreateColliderComponent(); EnterComponentMode(); // Given // Check preconditions PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // Get the cluster and button Ids AzToolsFramework::ViewportUi::ClusterId modeSelectionClusterId; AzToolsFramework::ViewportUi::ButtonId offsetModeButtonId; AZ::EntityId entityId = colliderEntity->GetId(); PhysX::ColliderComponentModeUiRequestBus::EventResult( modeSelectionClusterId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetClusterId); PhysX::ColliderComponentModeUiRequestBus::EventResult( offsetModeButtonId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetRotationButtonId); // When // Trigger the button m_viewportManagerWrapper.GetViewportManager()->PressButton(modeSelectionClusterId, offsetModeButtonId); // Then // Then the component mode is set to Offset. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Rotation, subMode); } TEST_F(PhysXColliderComponentModeTest, ClickingDimensionsButtonShouldSetDimensionsMode) { // Given there is a collider component in component mode. auto colliderEntity = CreateColliderComponent(); EnterComponentMode(); // Given // Check preconditions PhysX::ColliderComponentModeRequests::SubMode subMode = PhysX::ColliderComponentModeRequests::SubMode::NumModes; PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); // Get the cluster and button Ids AzToolsFramework::ViewportUi::ClusterId modeSelectionClusterId; AzToolsFramework::ViewportUi::ButtonId offsetModeButtonId; AZ::EntityId entityId = colliderEntity->GetId(); PhysX::ColliderComponentModeUiRequestBus::EventResult( modeSelectionClusterId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetClusterId); PhysX::ColliderComponentModeUiRequestBus::EventResult( offsetModeButtonId, AZ::EntityComponentIdPair(entityId, m_colliderComponentId), &PhysX::ColliderComponentModeUiRequests::GetDimensionsButtonId); // When // Trigger the button m_viewportManagerWrapper.GetViewportManager()->PressButton(modeSelectionClusterId, offsetModeButtonId); // Then // Then the component mode is set to Offset. PhysX::ColliderComponentModeRequestBus::BroadcastResult(subMode, &PhysX::ColliderComponentModeRequests::GetCurrentMode); EXPECT_EQ(PhysX::ColliderComponentModeRequests::SubMode::Dimensions, subMode); } } // namespace UnitTest