diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py index 047f46a40f..e62ab5e5dc 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py @@ -7,8 +7,10 @@ SPDX-License-Identifier: Apache-2.0 OR MIT Tests that require a GPU in order to run. """ +import datetime import logging import os +import zipfile import pytest @@ -40,6 +42,33 @@ def golden_images_directory(): return golden_images_dir +def create_screenshots_archive(screenshot_path): + """ + Creates a new zip file archive at archive_path containing all files listed within archive_path. + :param screenshot_path: location containing the files to archive, the zip archive file will also be saved here. + :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path. + """ + files_to_archive = [] + + # Search for .png and .ppm files to add to the zip archive file. + for (folder_name, sub_folders, file_names) in os.walk(screenshot_path): + for file_name in file_names: + if file_name.endswith(".png") or file_name.endswith(".ppm"): + file_path = os.path.join(folder_name, file_name) + files_to_archive.append(file_path) + + # Setup variables for naming the zip archive file. + timestamp = datetime.datetime.now().timestamp() + formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S") + screenshots_file = os.path.join(screenshot_path, f'zip_archive_{formatted_timestamp}.zip') + + # Write all of the valid .png and .ppm files to the archive file. + with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive: + for file_path in files_to_archive: + file_name = os.path.basename(file_path) + zip_archive.write(file_path, file_name) + + @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ["windows_editor"]) @pytest.mark.parametrize("level", ["auto_test"]) @@ -53,8 +82,8 @@ class TestAllComponentsIndepthTests(object): Tests that a basic rendering level setup can be created (lighting, meshes, materials, etc.). """ # Clear existing test screenshots before starting test. - test_screenshots = [os.path.join( - workspace.paths.project(), DEFAULT_SUBFOLDER_PATH, screenshot_name)] + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) + test_screenshots = [os.path.join(screenshot_directory, screenshot_name)] file_system.delete(test_screenshots, True, True) golden_images = [os.path.join(golden_images_directory(), screenshot_name)] @@ -86,6 +115,8 @@ class TestAllComponentsIndepthTests(object): for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): compare_screenshots(test_screenshot, golden_screenshot) + create_screenshots_archive(screenshot_directory) + def test_LightComponent_ScreenshotMatchesGoldenImage( self, request, editor, workspace, project, launcher_platform, level): """ @@ -105,9 +136,10 @@ class TestAllComponentsIndepthTests(object): "SpotLight_5.ppm", "SpotLight_6.ppm", ] + screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH) test_screenshots = [] for screenshot in screenshot_names: - screenshot_path = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH, screenshot) + screenshot_path = os.path.join(screenshot_directory, screenshot) test_screenshots.append(screenshot_path) file_system.delete(test_screenshots, True, True) @@ -139,6 +171,8 @@ class TestAllComponentsIndepthTests(object): for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): compare_screenshots(test_screenshot, golden_screenshot) + create_screenshots_archive(screenshot_directory) + @pytest.mark.parametrize('rhi', ['dx12', 'vulkan']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index b33469affb..736bbe5feb 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -1087,6 +1087,7 @@ void EditorViewportWidget::ConnectViewportInteractionRequestBus() { AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler::BusConnect(GetViewportId()); AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusConnect(GetViewportId()); + AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(GetViewportId()); m_viewportUi.ConnectViewportUiBus(GetViewportId()); AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusConnect(); @@ -1097,6 +1098,7 @@ void EditorViewportWidget::DisconnectViewportInteractionRequestBus() AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusDisconnect(); m_viewportUi.DisconnectViewportUiBus(); + AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect(); AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusDisconnect(); AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler::BusDisconnect(); } diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h index 5d332ae3f0..dff0adb55a 100644 --- a/Code/Editor/EditorViewportWidget.h +++ b/Code/Editor/EditorViewportWidget.h @@ -91,6 +91,7 @@ class SANDBOX_API EditorViewportWidget final , private AzFramework::InputSystemCursorConstraintRequestBus::Handler , private AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler , private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler + , private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler , private AZ::RPI::SceneNotificationBus::Handler { @@ -128,10 +129,12 @@ private: CameraComponent, ViewSourceTypesCount, }; + enum class PlayInEditorState { Editor, Starting, Started }; + enum class KeyPressedState { AllUp, @@ -142,7 +145,7 @@ private: //////////////////////////////////////////////////////////////////////// // Method overrides ... - // QWidget + // QWidget overrides ... void focusOutEvent(QFocusEvent* event) override; void keyPressEvent(QKeyEvent* event) override; bool event(QEvent* event) override; @@ -150,7 +153,7 @@ private: void paintEvent(QPaintEvent* event) override; void mousePressEvent(QMouseEvent* event) override; - // QtViewport/IDisplayViewport/CViewport + // QtViewport/IDisplayViewport/CViewport overrides ... EViewportType GetType() const override { return ET_ViewportCamera; } void SetType([[maybe_unused]] EViewportType type) override { assert(type == ET_ViewportCamera); }; AzToolsFramework::ViewportInteraction::MouseInteraction BuildMouseInteraction( @@ -176,16 +179,17 @@ private: void Update() override; void UpdateContent(int flags) override; - // SceneNotificationBus + // SceneNotificationBus overrides ... void OnBeginPrepareRender() override; - // Camera::CameraNotificationBus + // Camera::CameraNotificationBus overrides ... void OnActiveViewChanged(const AZ::EntityId&) override; - // IEditorEventListener + // IEditorEventListener overrides ... void OnEditorNotifyEvent(EEditorNotifyEvent event) override; - // AzToolsFramework::EditorEntityContextNotificationBus (handler moved to cpp to resolve link issues in unity builds) + // AzToolsFramework::EditorEntityContextNotificationBus overrides ... + // note: handler moved to cpp to resolve link issues in unity builds void OnStartPlayInEditor(); void OnStopPlayInEditor(); void OnStartPlayInEditorBegin(); @@ -194,10 +198,10 @@ private: void BeginUndoTransaction() override; void EndUndoTransaction() override; - // AzFramework::InputSystemCursorConstraintRequestBus + // AzFramework::InputSystemCursorConstraintRequestBus overrides ... void* GetSystemCursorConstraintWindow() const override; - // AzToolsFramework::ViewportFreezeRequestBus + // AzToolsFramework::ViewportFreezeRequestBus overrides ... bool IsViewportInputFrozen() override; void FreezeViewportInput(bool freeze) override; @@ -205,13 +209,15 @@ private: AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) override; AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) override; float TerrainHeight(const AZ::Vector2& position) override; - void FindVisibleEntities(AZStd::vector& visibleEntitiesOut) override; bool ShowingWorldSpace() override; QWidget* GetWidgetForViewportContextMenu() override; void BeginWidgetContext() override; void EndWidgetContext() override; - // Camera::EditorCameraRequestBus + // EditorEntityViewportInteractionRequestBus overrides ... + void FindVisibleEntities(AZStd::vector& visibleEntities) override; + + // Camera::EditorCameraRequestBus overrides ... void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override; void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override; AZ::EntityId GetCurrentViewEntityId() override; @@ -327,7 +333,7 @@ private: // Determines also if the current camera for this viewport is default editor camera ViewSourceType m_viewSourceType = ViewSourceType::None; - // During play game in editor, holds the editor entity ID of the last + // During play game in editor, holds the editor entity ID of the last AZ::EntityId m_viewEntityIdCachedForEditMode; // The editor camera TM before switching to game mode diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp index 92e193bddf..9c6088e340 100644 --- a/Code/Editor/Viewport.cpp +++ b/Code/Editor/Viewport.cpp @@ -1092,9 +1092,8 @@ bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo) const int viewportId = GetViewportId(); AzToolsFramework::EntityIdList visibleEntityIds; - AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Event( - viewportId, - &AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequests::FindVisibleEntities, + AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Event( + viewportId, &AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Events::FindVisibleEntities, visibleEntityIds); // Look through all visible entities to find the closest one to the specified mouse point diff --git a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h index fddaddf303..68af9dbb26 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,8 @@ namespace AzFramework virtual AZ::u32 SetState(AZ::u32 state) { (void)state; return 0; } virtual void PushMatrix(const AZ::Transform& tm) { (void)tm; } virtual void PopMatrix() {} + virtual void PushPremultipliedMatrix(const AZ::Matrix3x4& matrix) { (void)matrix; } + virtual AZ::Matrix3x4 PopPremultipliedMatrix() { return AZ::Matrix3x4::CreateIdentity(); } protected: ~DebugDisplayRequests() = default; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 89338a355f..18667ac153 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -588,6 +588,12 @@ namespace AzFramework // pass through the camera's position and look vector for use in the lookAt function if (const auto lookAt = lookAtFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY())) { + // default to internal look at behavior if the look at point matches the camera translation + if (targetCamera.m_lookAt.IsClose(*lookAt)) + { + return false; + } + auto transform = AZ::Transform::CreateLookAt(targetCamera.m_lookAt, *lookAt); nextCamera.m_lookDist = -lookAt->GetDistance(targetCamera.m_lookAt); UpdateCameraFromTransform(nextCamera, transform); diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h index ebd9484c55..7a60d5fdc5 100644 --- a/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h +++ b/Code/Framework/AzFramework/AzFramework/Visibility/BoundsBus.h @@ -45,6 +45,7 @@ namespace AzFramework protected: ~BoundsRequests() = default; }; + using BoundsRequestBus = AZ::EBus; //! Returns a union of all local Aabbs provided by components implementing the BoundsRequestBus. diff --git a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp index 486cca2af0..df7d22f7ca 100644 --- a/Code/Framework/AzFramework/Tests/CameraInputTests.cpp +++ b/Code/Framework/AzFramework/Tests/CameraInputTests.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -47,18 +48,17 @@ namespace UnitTest m_firstPersonTranslateCamera = AZStd::make_shared(AzFramework::LookTranslation, m_translateCameraInputChannelIds); - auto orbitCamera = - AZStd::make_shared(AzFramework::InputChannelId("keyboard_key_modifier_alt_l")); + m_orbitCamera = AZStd::make_shared(m_orbitChannelId); auto orbitRotateCamera = AZStd::make_shared(AzFramework::InputDeviceMouse::Button::Left); auto orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation, m_translateCameraInputChannelIds); - orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); - orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); + m_orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonRotateCamera); m_cameraSystem->m_cameras.AddCamera(m_firstPersonTranslateCamera); - m_cameraSystem->m_cameras.AddCamera(orbitCamera); + m_cameraSystem->m_cameras.AddCamera(m_orbitCamera); // these tests rely on using motion delta, not cursor positions (default is true) AzFramework::ed_cameraSystemUseCursor = false; @@ -68,6 +68,7 @@ namespace UnitTest { AzFramework::ed_cameraSystemUseCursor = true; + m_orbitCamera.reset(); m_firstPersonRotateCamera.reset(); m_firstPersonTranslateCamera.reset(); @@ -77,12 +78,14 @@ namespace UnitTest AllocatorsTestFixture::TearDown(); } + AzFramework::InputChannelId m_orbitChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l"); AzFramework::TranslateCameraInputChannelIds m_translateCameraInputChannelIds; AZStd::shared_ptr m_firstPersonRotateCamera; AZStd::shared_ptr m_firstPersonTranslateCamera; + AZStd::shared_ptr m_orbitCamera; }; - TEST_F(CameraInputFixture, Begin_and_end_OrbitCameraInput_consumes_correct_events) + TEST_F(CameraInputFixture, BeginAndEndOrbitCameraInputConsumesCorrectEvents) { // begin orbit camera const bool consumed1 = HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceKeyboard::Key::ModifierAltL, @@ -102,7 +105,7 @@ namespace UnitTest EXPECT_THAT(allConsumed, ElementsAre(true, false, true, false)); } - TEST_F(CameraInputFixture, Begin_CameraInput_notifies_ActivationBeganFn_for_TranslateCameraInput) + TEST_F(CameraInputFixture, BeginCameraInputNotifiesActivationBeganFnForTranslateCameraInput) { bool activationBegan = false; m_firstPersonTranslateCamera->SetActivationBeganFn( @@ -111,13 +114,13 @@ namespace UnitTest activationBegan = true; }); - HandleEventAndUpdate( - AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); EXPECT_TRUE(activationBegan); } - TEST_F(CameraInputFixture, Begin_CameraInput_notifies_ActivationBeganFn_after_delta_for_RotateCameraInput) + TEST_F(CameraInputFixture, BeginCameraInputNotifiesActivationBeganFnAfterDeltaForRotateCameraInput) { bool activationBegan = false; m_firstPersonRotateCamera->SetActivationBeganFn( @@ -133,7 +136,7 @@ namespace UnitTest EXPECT_TRUE(activationBegan); } - TEST_F(CameraInputFixture, Begin_CameraInput_does_not_notify_ActivationBeganFn_with_no_delta_for_RotateCameraInput) + TEST_F(CameraInputFixture, BeginCameraInputDoesNotNotifyActivationBeganFnWithNoDeltaForRotateCameraInput) { bool activationBegan = false; m_firstPersonRotateCamera->SetActivationBeganFn( @@ -148,7 +151,7 @@ namespace UnitTest EXPECT_FALSE(activationBegan); } - TEST_F(CameraInputFixture, End_CameraInput_notifies_ActivationEndFn_after_delta_for_RotateCameraInput) + TEST_F(CameraInputFixture, EndCameraInputNotifiesActivationEndFnAfterDeltaForRotateCameraInput) { bool activationEnded = false; m_firstPersonRotateCamera->SetActivationEndedFn( @@ -166,7 +169,7 @@ namespace UnitTest EXPECT_TRUE(activationEnded); } - TEST_F(CameraInputFixture, End_CameraInput_does_not_notify_ActivationBeganFn_or_ActivationBeganFn_with_no_delta_for_RotateCameraInput) + TEST_F(CameraInputFixture, EndCameraInputDoesNotNotifyActivationBeganFnOrActivationBeganFnWithNoDeltaForRotateCameraInput) { bool activationBegan = false; m_firstPersonRotateCamera->SetActivationBeganFn( @@ -191,7 +194,7 @@ namespace UnitTest EXPECT_FALSE(activationEnded); } - TEST_F(CameraInputFixture, End_CameraInput_notifies_ActivationBeganFn_or_ActivationEndFn_with_TranslateCamera) + TEST_F(CameraInputFixture, End_CameraInputNotifiesActivationBeganFnOrActivationEndFnWithTranslateCamera) { bool activationBegan = false; m_firstPersonTranslateCamera->SetActivationBeganFn( @@ -207,16 +210,16 @@ namespace UnitTest activationEnded = true; }); - HandleEventAndUpdate( - AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, AzFramework::InputChannel::State::Began }); - HandleEventAndUpdate( - AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, AzFramework::InputChannel::State::Ended }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Ended }); EXPECT_TRUE(activationBegan); EXPECT_TRUE(activationEnded); } - TEST_F(CameraInputFixture, End_activation_called_for_CameraInput_if_active_when_cameras_are_cleared) + TEST_F(CameraInputFixture, EndActivationCalledForCameraInputIfActiveWhenCamerasAreCleared) { bool activationEnded = false; m_firstPersonTranslateCamera->SetActivationEndedFn( @@ -225,11 +228,37 @@ namespace UnitTest activationEnded = true; }); - HandleEventAndUpdate( - AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, AzFramework::InputChannel::State::Began }); + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId, + AzFramework::InputChannel::State::Began }); m_cameraSystem->m_cameras.Clear(); EXPECT_TRUE(activationEnded); } + + TEST_F(CameraInputFixture, OrbitCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenOrbiting) + { + // create pathological lookAtFn that just returns the same position as the camera + m_orbitCamera->SetLookAtFn( + [](const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction) + { + return position; + }); + + AzFramework::UpdateCameraFromTransform( + m_targetCamera, + AZ::Transform::CreateFromQuaternionAndTranslation( + AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), AZ::Vector3(10.0f, 10.0f, 10.0f))); + + m_camera = m_targetCamera; + + HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began }); + + // verify the camera yaw has not changed and the look at point + // does not match that of the camera translation + using ::testing::Eq; + using ::testing::Not; + EXPECT_THAT(m_camera.m_yaw, Eq(AZ::DegToRad(90.0f))); + EXPECT_THAT(m_camera.m_lookAt, Not(IsClose(m_camera.Translation()))); + } } // namespace UnitTest diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h index 5e907ae680..7f838b0073 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFramework.h @@ -45,6 +45,9 @@ namespace AzManipulatorTestFramework virtual void SetAngularStep(float step) = 0; //! Get the viewport id. virtual int GetViewportId() const = 0; + //! Updates the visibility state. + //! Updates which entities are currently visible given the current camera state. + virtual void UpdateVisibility() = 0; }; //! This interface is used to simulate the manipulator manager while the manipulators are under test. diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h index 9b253c718b..f87f83c1b2 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include #include namespace UnitTest @@ -21,20 +21,18 @@ namespace UnitTest //! Fixture to provide the indirect call viewport interaction that is dependent on AzToolsFramework::ToolsApplication. //! \tparam ToolsApplicationFixtureT The fixture that provides the AzToolsFramework::ToolsApplication functionality. template - class IndirectCallManipulatorViewportInteractionFixtureMixin - : public ToolsApplicationFixtureT + class IndirectCallManipulatorViewportInteractionFixtureMixin : public ToolsApplicationFixtureT { - using IndirectCallManipulatorViewportInteraction = - AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction; + using IndirectCallManipulatorViewportInteraction = AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction; using ImmediateModeActionDispatcher = AzManipulatorTestFramework::ImmediateModeActionDispatcher; - + void SetUpEditorFixtureImpl() override { ToolsApplicationFixtureT::SetUpEditorFixtureImpl(); m_viewportManipulatorInteraction = AZStd::make_unique(); m_actionDispatcher = AZStd::make_unique(*m_viewportManipulatorInteraction); - m_cameraState = AzFramework::CreateIdentityDefaultCamera( - AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); + m_cameraState = + AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } void TearDownEditorFixtureImpl() override diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h index dabcf567db..a7b1be2c7d 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h @@ -9,8 +9,8 @@ #pragma once #include -#include #include +#include namespace AzManipulatorTestFramework { @@ -18,13 +18,12 @@ namespace AzManipulatorTestFramework class IndirectCallManipulatorManager; //! Implementation of manipulator viewport interaction that manipulates the manager indirectly via bus calls. - class IndirectCallManipulatorViewportInteraction - : public ManipulatorViewportInteraction + class IndirectCallManipulatorViewportInteraction : public ManipulatorViewportInteraction { public: IndirectCallManipulatorViewportInteraction(); ~IndirectCallManipulatorViewportInteraction(); - + // ManipulatorViewportInteractionInterface ... const ViewportInteractionInterface& GetViewportInteraction() const override; const ManipulatorManagerInterface& GetManipulatorManager() const override; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h index b6944e0355..8b6ea5c59b 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h @@ -8,6 +8,7 @@ #pragma once +#include #include namespace AzManipulatorTestFramework @@ -19,6 +20,7 @@ namespace AzManipulatorTestFramework : public ViewportInteractionInterface , public AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler , public AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler + , private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler { public: ViewportInteraction(); @@ -34,6 +36,7 @@ namespace AzManipulatorTestFramework void SetGridSize(float size) override; void SetAngularStep(float step) override; int GetViewportId() const override; + void UpdateVisibility() override; // ViewportInteractionRequestBus overrides ... AzFramework::CameraState GetCameraState() override; @@ -52,7 +55,11 @@ namespace AzManipulatorTestFramework float ManipulatorLineBoundWidth() const override; float ManipulatorCircleBoundWidth() const override; + // EditorEntityViewportInteractionRequestBus overrides ... + void FindVisibleEntities(AZStd::vector& visibleEntities) override; + private: + AzFramework::EntityVisibilityQuery m_entityVisibilityQuery; AZStd::unique_ptr m_nullDebugDisplayRequests; const int m_viewportId = 1234; // Arbitrary viewport id for manipulator tests AzFramework::CameraState m_cameraState; diff --git a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp index 1b68a3d0cd..4f1e108a14 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp @@ -91,12 +91,12 @@ namespace AzManipulatorTestFramework AzToolsFramework::ViewportInteraction::MousePick BuildMousePick( const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState) { - const auto screenToWorld = AzFramework::ScreenToWorld(screenPoint, cameraState); + const auto nearPlaneWorldPosition = AzFramework::ScreenToWorld(screenPoint, cameraState); AzToolsFramework::ViewportInteraction::MousePick mousePick; mousePick.m_screenCoordinates = screenPoint; - mousePick.m_rayOrigin = screenToWorld; - mousePick.m_rayDirection = (screenToWorld - cameraState.m_position).GetNormalized(); + mousePick.m_rayOrigin = cameraState.m_position; + mousePick.m_rayDirection = (nearPlaneWorldPosition - cameraState.m_position).GetNormalized(); return mousePick; } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp index ff5e3981ef..14723800ff 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/IndirectManipulatorViewportInteraction.cpp @@ -16,8 +16,7 @@ namespace AzManipulatorTestFramework using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent; //! Implementation of the manipulator interface using bus calls to access to the manipulator manager. - class IndirectCallManipulatorManager - : public ManipulatorManagerInterface + class IndirectCallManipulatorManager : public ManipulatorManagerInterface { public: IndirectCallManipulatorManager(ViewportInteractionInterface& viewportInteraction); @@ -39,11 +38,12 @@ namespace AzManipulatorTestFramework void IndirectCallManipulatorManager::ConsumeMouseInteractionEvent(const MouseInteractionEvent& event) { + m_viewportInteraction.UpdateVisibility(); + DrawManipulators(); AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, - event); + &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, event); DrawManipulators(); } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp index 0817df3849..4dae4fc00d 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp @@ -26,10 +26,12 @@ namespace AzManipulatorTestFramework { AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId); AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(m_viewportId); + AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(m_viewportId); } ViewportInteraction::~ViewportInteraction() { + AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect(); AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusDisconnect(); AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusDisconnect(); } @@ -74,6 +76,16 @@ namespace AzManipulatorTestFramework return 0.1f; } + void ViewportInteraction::FindVisibleEntities(AZStd::vector& visibleEntitiesOut) + { + visibleEntitiesOut.assign(m_entityVisibilityQuery.Begin(), m_entityVisibilityQuery.End()); + } + + void ViewportInteraction::UpdateVisibility() + { + m_entityVisibilityQuery.UpdateVisibility(m_cameraState); + } + AzFramework::ScreenPoint ViewportInteraction::ViewportWorldToScreen(const AZ::Vector3& worldPosition) { return AzFramework::WorldToScreen(worldPosition, m_cameraState); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentEntitySelectionBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentEntitySelectionBus.h index 64cae9ca3d..dd5af35649 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentEntitySelectionBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ComponentEntitySelectionBus.h @@ -96,7 +96,7 @@ namespace AzToolsFramework { AZ::EBusReduceResult aabbResult(AZ::Aabb::CreateNull()); EditorComponentSelectionRequestsBus::EventResult( - aabbResult, entityId, &EditorComponentSelectionRequests::GetEditorSelectionBoundsViewport, viewportInfo); + aabbResult, entityId, &EditorComponentSelectionRequestsBus::Events::GetEditorSelectionBoundsViewport, viewportInfo); return aabbResult.value; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp index 955ee61525..e3b45aca2b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp @@ -10,6 +10,25 @@ namespace AzToolsFramework { + AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction( + const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + { + if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left()) + { + if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down) + { + return AzFramework::ClickDetector::ClickEvent::Down; + } + + if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up) + { + return AzFramework::ClickDetector::ClickEvent::Up; + } + } + + return AzFramework::ClickDetector::ClickEvent::Nil; + } + float ManipulatorLineBoundWidth(const AzFramework::ViewportId viewportId /*= AzFramework::InvalidViewportId*/) { float lineBoundWidth = 0.0f; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 147c71c8e8..942fee1a49 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -250,8 +250,6 @@ namespace AzToolsFramework virtual AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) = 0; //! Return the terrain height given a world position in 2d (xy plane). virtual float TerrainHeight(const AZ::Vector2& position) = 0; - //! Given the current view frustum (viewport) return all visible entities. - virtual void FindVisibleEntities(AZStd::vector& visibleEntities) = 0; //! Is the user holding a modifier key to move the manipulator space from local to world. virtual bool ShowingWorldSpace() = 0; //! Return the widget to use as the parent for the viewport context menu. @@ -269,7 +267,20 @@ namespace AzToolsFramework //! Type to inherit to implement MainEditorViewportInteractionRequests. using MainEditorViewportInteractionRequestBus = AZ::EBus; - //! Viewport requests for managing the viewport's cursor state. + //! Editor entity requests to be made about the viewport. + class EditorEntityViewportInteractionRequests + { + public: + //! Given the current view frustum (viewport) return all visible entities. + virtual void FindVisibleEntities(AZStd::vector& visibleEntities) = 0; + + protected: + ~EditorEntityViewportInteractionRequests() = default; + }; + + using EditorEntityViewportInteractionRequestBus = AZ::EBus; + + //! Viewport requests for managing the viewport cursor state. class ViewportMouseCursorRequests { public: @@ -321,23 +332,8 @@ namespace AzToolsFramework //! Maps a mouse interaction event to a ClickDetector event. //! @note Function only cares about up or down events, all other events are mapped to Nil (ignored). - inline AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) - { - if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left()) - { - if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down) - { - return AzFramework::ClickDetector::ClickEvent::Down; - } - - if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Up) - { - return AzFramework::ClickDetector::ClickEvent::Up; - } - } - return AzFramework::ClickDetector::ClickEvent::Nil; - } + AzFramework::ClickDetector::ClickEvent ClickDetectorEventFromViewportInteraction( + const ViewportInteraction::MouseInteractionEvent& mouseInteraction); //! Wrap EBus call to retrieve manipulator line bound width. //! @note It is possible to pass AzFramework::InvalidViewportId (the default) to perform a Broadcast as opposed to a targeted Event. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp index 7cb0e718a8..f4b68b5970 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp @@ -19,7 +19,7 @@ namespace AzToolsFramework { // default ray length for picking in the viewport - static const float s_pickRayLength = 1000.0f; + static const float EditorPickRayLength = 1000.0f; AZ::Vector3 CalculateCenterOffset(const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot) { @@ -60,16 +60,27 @@ namespace AzToolsFramework return screenPosition; } - bool AabbIntersectMouseRay(const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb) + bool AabbIntersectRay(const AZ::Vector3& origin, const AZ::Vector3& direction, const AZ::Aabb& aabb, float& distance) { AZ_PROFILE_FUNCTION(AzToolsFramework); - const AZ::Vector3 rayScaledDir = mouseInteraction.m_mousePick.m_rayDirection * s_pickRayLength; + const AZ::Vector3 rayScaledDir = direction * EditorPickRayLength; - AZ::Vector3 startNormal; float t, end; - return AZ::Intersect::IntersectRayAABB( - mouseInteraction.m_mousePick.m_rayOrigin, rayScaledDir, rayScaledDir.GetReciprocal(), aabb, t, end, startNormal) > 0; + AZ::Vector3 startNormal; + if (AZ::Intersect::IntersectRayAABB(origin, rayScaledDir, rayScaledDir.GetReciprocal(), aabb, t, end, startNormal) > 0) + { + distance = t * EditorPickRayLength; + return true; + } + + return false; + } + + bool AabbIntersectMouseRay(const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb) + { + float unused; + return AabbIntersectRay(mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection, aabb, unused); } bool PickEntity( @@ -117,8 +128,7 @@ namespace AzToolsFramework { float scaling = 1.0f; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - scaling, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::DeviceScalingFactor); + scaling, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::DeviceScalingFactor); return scaling; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h index aa1b3ae5ce..ec9bde9f9c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h @@ -46,6 +46,10 @@ namespace AzToolsFramework //! in screen space intersected an aabb in world space. bool AabbIntersectMouseRay(const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb); + //! Wrapper to perform an intersection between a ray and an aabb. + //! Note: direction should be normalized (it is scaled internally by the editor pick distance). + bool AabbIntersectRay(const AZ::Vector3& origin, const AZ::Vector3& direction, const AZ::Aabb& aabb, float& distance); + //! Return if a mouse interaction (pick ray) did intersect the tested EntityId. bool PickEntity( AZ::EntityId entityId, const ViewportInteraction::MouseInteraction& mouseInteraction, float& closestDistance, int viewportId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp index c65f494b72..5da827244f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp @@ -161,8 +161,8 @@ namespace AzToolsFramework // request list of visible entities from authoritative system EntityIdList nextVisibleEntityIds; - ViewportInteraction::MainEditorViewportInteractionRequestBus::Event( - viewportInfo.m_viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::FindVisibleEntities, + ViewportInteraction::EditorEntityViewportInteractionRequestBus::Event( + viewportInfo.m_viewportId, &ViewportInteraction::EditorEntityViewportInteractionRequestBus::Events::FindVisibleEntities, nextVisibleEntityIds); // only bother resorting if we know the lists have changed diff --git a/Code/Framework/AzToolsFramework/Tests/ComponentModeTestFixture.cpp b/Code/Framework/AzToolsFramework/Tests/ComponentModeTestFixture.cpp index cfdd2d082c..672a0d6705 100644 --- a/Code/Framework/AzToolsFramework/Tests/ComponentModeTestFixture.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ComponentModeTestFixture.cpp @@ -6,8 +6,8 @@ * */ -#include "ComponentModeTestDoubles.h" #include "ComponentModeTestFixture.h" +#include "ComponentModeTestDoubles.h" #include @@ -15,17 +15,15 @@ namespace UnitTest { void ComponentModeTestFixture::SetUpEditorFixtureImpl() { - using namespace AzToolsFramework; - using namespace AzToolsFramework::ComponentModeFramework; + namespace AztfCmf = AzToolsFramework::ComponentModeFramework; auto* app = GetApplication(); - ASSERT_TRUE(app); - app->RegisterComponentDescriptor(PlaceholderEditorComponent::CreateDescriptor()); - app->RegisterComponentDescriptor(AnotherPlaceholderEditorComponent::CreateDescriptor()); - app->RegisterComponentDescriptor(DependentPlaceholderEditorComponent::CreateDescriptor()); + app->RegisterComponentDescriptor(AztfCmf::PlaceholderEditorComponent::CreateDescriptor()); + app->RegisterComponentDescriptor(AztfCmf::AnotherPlaceholderEditorComponent::CreateDescriptor()); + app->RegisterComponentDescriptor(AztfCmf::DependentPlaceholderEditorComponent::CreateDescriptor()); app->RegisterComponentDescriptor( - TestComponentModeComponent::CreateDescriptor()); - app->RegisterComponentDescriptor(IncompatiblePlaceholderEditorComponent::CreateDescriptor()); + AztfCmf::TestComponentModeComponent::CreateDescriptor()); + app->RegisterComponentDescriptor(AztfCmf::IncompatiblePlaceholderEditorComponent::CreateDescriptor()); } } // namespace UnitTest diff --git a/Code/Legacy/CrySystem/SystemCFG.cpp b/Code/Legacy/CrySystem/SystemCFG.cpp index 52e377db7f..802e577386 100644 --- a/Code/Legacy/CrySystem/SystemCFG.cpp +++ b/Code/Legacy/CrySystem/SystemCFG.cpp @@ -178,7 +178,7 @@ void CSystem::LogVersion() strftime(s, 128, "%d %b %y (%H %M %S)", today); #endif - const SFileVersion& ver = GetFileVersion(); + [[maybe_unused]] const SFileVersion& ver = GetFileVersion(); CryLogAlways("BackupNameAttachment=\" Build(%d) %s\" -- used by backup system\n", ver.v[0], s); // read by CreateBackupFile() @@ -249,7 +249,7 @@ void CSystem::LogVersion() ////////////////////////////////////////////////////////////////////////// void CSystem::LogBuildInfo() { - auto projectName = AZ::Utils::GetProjectName(); + [[maybe_unused]] auto projectName = AZ::Utils::GetProjectName(); CryLogAlways("GameName: %s", projectName.c_str()); CryLogAlways("BuildTime: " __DATE__ " " __TIME__); } diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp index 4e84187165..af17e3a1da 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp @@ -115,10 +115,13 @@ namespace AZ AZ_Assert(m_shaderResourceGroup, "RayTracingPass [%s]: Failed to create RayTracingGlobalSrg", GetPathName().GetCStr()); RPI::PassUtils::BindDataMappingsToSrg(m_passDescriptor, m_shaderResourceGroup.get()); - // check to see if the shader requires the View and RayTracingMaterial Srgs + // check to see if the shader requires the View, Scene, or RayTracingMaterial Srgs const auto& viewSrgLayout = m_rayGenerationShader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::View); m_requiresViewSrg = (viewSrgLayout != nullptr); + const auto& sceneSrgLayout = m_rayGenerationShader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Scene); + m_requiresSceneSrg = (sceneSrgLayout != nullptr); + const auto& rayTracingMaterialSrgLayout = m_rayGenerationShader->FindShaderResourceGroupLayout(RayTracingMaterialSrgBindingSlot); m_requiresRayTracingMaterialSrg = (rayTracingMaterialSrgLayout != nullptr); @@ -324,6 +327,11 @@ namespace AZ } } + if (m_requiresSceneSrg) + { + shaderResourceGroups.push_back(scene->GetShaderResourceGroup()->GetRHIShaderResourceGroup()); + } + if (m_requiresRayTracingMaterialSrg) { shaderResourceGroups.push_back(rayTracingFeatureProcessor->GetRayTracingMaterialSrg()->GetRHIShaderResourceGroup()); diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h index 5eafa5b2f4..6ef97e0f10 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h @@ -72,6 +72,7 @@ namespace AZ RHI::ConstPtr m_globalPipelineState; RHI::Ptr m_rayTracingShaderTable; bool m_requiresViewSrg = false; + bool m_requiresSceneSrg = false; bool m_requiresRayTracingMaterialSrg = false; }; } // namespace RPI diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 0fc55e2363..4419e0c49f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -73,6 +73,7 @@ namespace AtomToolsFramework return AZ::Transform::CreateIdentity(); } + void ModularCameraViewportContextImpl::SetCameraTransform(const AZ::Transform& transform) { if (auto viewportContext = RetrieveViewportContext(m_viewportId)) @@ -80,6 +81,7 @@ namespace AtomToolsFramework viewportContext->SetCameraTransform(transform); } } + void ModularCameraViewportContextImpl::ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler& handler) { if (auto viewportContext = RetrieveViewportContext(m_viewportId)) diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index d720463ce2..b45fbe05f6 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -1552,6 +1552,26 @@ namespace AZ::AtomBridge } } + void AtomDebugDisplayViewportInterface::PushPremultipliedMatrix(const AZ::Matrix3x4& matrix) + { + AZ_Assert(m_rendState.m_currentTransform < RenderState::TransformStackSize, "Exceeded AtomDebugDisplayViewportInterface matrix stack size"); + if (m_rendState.m_currentTransform < RenderState::TransformStackSize) + { + m_rendState.m_currentTransform++; + m_rendState.m_transformStack[m_rendState.m_currentTransform] = matrix; + } + } + + AZ::Matrix3x4 AtomDebugDisplayViewportInterface::PopPremultipliedMatrix() + { + AZ_Assert(m_rendState.m_currentTransform > 0, "Underflowed AtomDebugDisplayViewportInterface matrix stack"); + if (m_rendState.m_currentTransform > 0) + { + m_rendState.m_currentTransform--; + } + return m_rendState.m_transformStack[m_rendState.m_currentTransform + 1]; + } + const AZ::Matrix3x4& AtomDebugDisplayViewportInterface::GetCurrentTransform() const { return m_rendState.m_transformStack[m_rendState.m_currentTransform]; diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index 22fb8875a4..07f4efdf50 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -193,6 +193,8 @@ namespace AZ::AtomBridge AZ::u32 SetState(AZ::u32 state) override; void PushMatrix(const AZ::Transform& tm) override; void PopMatrix() override; + void PushPremultipliedMatrix(const AZ::Matrix3x4& matrix) override; + AZ::Matrix3x4 PopPremultipliedMatrix() override; private: diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/Config_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/Config_wwise.cpp index 9bd376b641..437c1d156a 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/Config_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/Config_wwise.cpp @@ -11,8 +11,8 @@ #include #include #include +#include #include -#include // For AZ_Printf statements... #define WWISE_CONFIG_WINDOW "WwiseConfig" @@ -56,7 +56,7 @@ namespace Audio::Wwise bool ConfigurationSettings::Load(const AZStd::string& filePath) { AZ::IO::Path fileIoPath(filePath); - auto outcome = AzFramework::FileFunc::ReadJsonFile(fileIoPath); + auto outcome = AZ::JsonSerializationUtils::ReadJsonFile(fileIoPath.Native()); if (!outcome) { AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: %s\n", outcome.GetError().c_str()); @@ -92,7 +92,7 @@ namespace Audio::Wwise return false; } - auto outcome = AzFramework::FileFunc::WriteJsonFile(jsonDoc, filePath); + auto outcome = AZ::JsonSerializationUtils::WriteJsonFile(jsonDoc, filePath); if (!outcome) { AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: %s\n", outcome.GetError().c_str()); diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp index 07113e09d3..cf042dc4ac 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp @@ -19,9 +19,7 @@ #include #include -#define MAX_NUMBER_STRING_SIZE (10) // 4G -#define ID_TO_STRING_FORMAT_BANK AKTEXT("%u.bnk") -#define ID_TO_STRING_FORMAT_WEM AKTEXT("%u.wem") +#define MAX_NUMBER_STRING_SIZE (10) // max digits in u32 base-10 number #define MAX_EXTENSION_SIZE (4) // .xxx #define MAX_FILETITLE_SIZE (MAX_NUMBER_STRING_SIZE + MAX_EXTENSION_SIZE + 1) // null-terminated @@ -442,11 +440,16 @@ namespace Audio } } - AkOSChar fileName[MAX_FILETITLE_SIZE] = { '\0' }; + AkOSChar fileName[MAX_FILETITLE_SIZE] = { 0 }; - const AkOSChar* const filenameFormat = (flags->uCodecID == AKCODECID_BANK ? ID_TO_STRING_FORMAT_BANK : ID_TO_STRING_FORMAT_WEM); - - AK_OSPRINTF(fileName, MAX_FILETITLE_SIZE, filenameFormat, static_cast(fileID)); + if (flags->uCodecID == AKCODECID_BANK) + { + AK_OSPRINTF(fileName, MAX_FILETITLE_SIZE, AKTEXT("%u.bnk"), static_cast(fileID)); + } + else + { + AK_OSPRINTF(fileName, MAX_FILETITLE_SIZE, AKTEXT("%u.wem"), static_cast(fileID)); + } AKPLATFORM::SafeStrCat(finalFilePath, fileName, AK_MAX_PATH); diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 78742028f9..31cf68e9a0 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -72,6 +72,7 @@ // Shape components #include "Shape/SphereShapeComponent.h" #include "Shape/DiskShapeComponent.h" +#include "Shape/AxisAlignedBoxShapeComponent.h" #include "Shape/BoxShapeComponent.h" #include "Shape/QuadShapeComponent.h" #include "Shape/CylinderShapeComponent.h" @@ -202,6 +203,7 @@ namespace LmbrCentral SphereShapeComponent::CreateDescriptor(), DiskShapeComponent::CreateDescriptor(), BoxShapeComponent::CreateDescriptor(), + AxisAlignedBoxShapeComponent::CreateDescriptor(), QuadShapeComponent::CreateDescriptor(), CylinderShapeComponent::CreateDescriptor(), CapsuleShapeComponent::CreateDescriptor(), @@ -215,6 +217,7 @@ namespace LmbrCentral SphereShapeDebugDisplayComponent::CreateDescriptor(), DiskShapeDebugDisplayComponent::CreateDescriptor(), BoxShapeDebugDisplayComponent::CreateDescriptor(), + AxisAlignedBoxShapeDebugDisplayComponent::CreateDescriptor(), QuadShapeDebugDisplayComponent::CreateDescriptor(), CapsuleShapeDebugDisplayComponent::CreateDescriptor(), CylinderShapeDebugDisplayComponent::CreateDescriptor(), diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp index b15a31f8b3..511bf98582 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp @@ -24,6 +24,7 @@ #include "Scripting/EditorSpawnerComponent.h" #include "Scripting/EditorTagComponent.h" +#include "Shape/EditorAxisAlignedBoxShapeComponent.h" #include "Shape/EditorBoxShapeComponent.h" #include "Shape/EditorQuadShapeComponent.h" #include "Shape/EditorSphereShapeComponent.h" @@ -67,6 +68,7 @@ namespace LmbrCentral EditorDiskShapeComponent::CreateDescriptor(), EditorTubeShapeComponent::CreateDescriptor(), EditorBoxShapeComponent::CreateDescriptor(), + EditorAxisAlignedBoxShapeComponent::CreateDescriptor(), EditorQuadShapeComponent::CreateDescriptor(), EditorLookAtComponent::CreateDescriptor(), EditorCylinderShapeComponent::CreateDescriptor(), diff --git a/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.cpp b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.cpp new file mode 100644 index 0000000000..2553f8ab3e --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.cpp @@ -0,0 +1,59 @@ +/* + * 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 "AxisAlignedBoxShape.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace LmbrCentral +{ + AxisAlignedBoxShape::AxisAlignedBoxShape() + : BoxShape() + { + } + + void AxisAlignedBoxShape::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ; + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class("Axis Aligned Box Shape", "Axis Aligned Box shape configuration parameters") + ; + } + } + } + + void AxisAlignedBoxShape::Activate(AZ::EntityId entityId) + { + BoxShape::Activate(entityId); + m_currentTransform.SetRotation(AZ::Quaternion::CreateIdentity()); + } + + void AxisAlignedBoxShape::OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) + { + AZ::Transform worldNoRotation(world.GetTranslation(), AZ::Quaternion::CreateIdentity(), world.GetUniformScale()); + BoxShape::OnTransformChanged(local, worldNoRotation); + } +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.h b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.h new file mode 100644 index 0000000000..724092b608 --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShape.h @@ -0,0 +1,44 @@ +/* + * 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 + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "BoxShape.h" + +namespace AzFramework +{ + class DebugDisplayRequests; +} + +namespace LmbrCentral +{ + struct ShapeDrawParams; + + class AxisAlignedBoxShape + : public BoxShape + { + public: + AZ_CLASS_ALLOCATOR(AxisAlignedBoxShape, AZ::SystemAllocator, 0) + AZ_RTTI(AxisAlignedBoxShape, "{CFDC96C5-287A-4033-8D7D-BA9331C13F25}", BoxShape) + + AxisAlignedBoxShape(); + + static void Reflect(AZ::ReflectContext* context); + + void Activate(AZ::EntityId entityId) override; + + // AZ::TransformNotificationBus::Handler + void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; + }; +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.cpp new file mode 100644 index 0000000000..7f919bc097 --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.cpp @@ -0,0 +1,159 @@ +/* + * 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 "AxisAlignedBoxShapeComponent.h" +#include +#include +#include +#include +#include + +namespace LmbrCentral +{ + void AxisAlignedBoxShapeComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("ShapeService")); + provided.push_back(AZ_CRC_CE("BoxShapeService")); + provided.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService")); + } + + void AxisAlignedBoxShapeComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("ShapeService")); + incompatible.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService")); + } + + void AxisAlignedBoxShapeComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("TransformService")); + } + + void AxisAlignedBoxShapeComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + dependent.push_back(AZ_CRC_CE("NonUniformScaleService")); + } + + void AxisAlignedBoxShapeDebugDisplayComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1)->Field( + "Configuration", &AxisAlignedBoxShapeDebugDisplayComponent::m_boxShapeConfig) + ; + } + } + + void AxisAlignedBoxShapeDebugDisplayComponent::Activate() + { + EntityDebugDisplayComponent::Activate(); + ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId()); + m_nonUniformScale = AZ::Vector3::CreateOne(); + AZ::NonUniformScaleRequestBus::EventResult(m_nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale); + } + + void AxisAlignedBoxShapeDebugDisplayComponent::Deactivate() + { + ShapeComponentNotificationsBus::Handler::BusDisconnect(); + EntityDebugDisplayComponent::Deactivate(); + } + + void AxisAlignedBoxShapeDebugDisplayComponent::Draw(AzFramework::DebugDisplayRequests& debugDisplay) + { + AZ::Matrix3x4 saveMatrix; + ShapeDrawParams drawParams = g_defaultShapeDrawParams; + drawParams.m_shapeColor = m_boxShapeConfig.GetDrawColor(); + drawParams.m_filled = m_boxShapeConfig.IsFilled(); + AZ::Transform transform = GetCurrentTransform(); + transform.SetRotation(AZ::Quaternion::CreateIdentity()); + saveMatrix = debugDisplay.PopPremultipliedMatrix(); + debugDisplay.PushMatrix(transform); + DrawBoxShape(drawParams, m_boxShapeConfig, debugDisplay, m_nonUniformScale); + debugDisplay.PopMatrix(); + debugDisplay.PushPremultipliedMatrix(saveMatrix); + } + + bool AxisAlignedBoxShapeDebugDisplayComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) + { + if (const auto config = azrtti_cast(baseConfig)) + { + m_boxShapeConfig = *config; + return true; + } + return false; + } + + bool AxisAlignedBoxShapeDebugDisplayComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const + { + if (auto outConfig = azrtti_cast(outBaseConfig)) + { + *outConfig = m_boxShapeConfig; + return true; + } + return false; + } + + void AxisAlignedBoxShapeDebugDisplayComponent::OnShapeChanged(ShapeChangeReasons changeReason) + { + if (changeReason == ShapeChangeReasons::ShapeChanged) + { + BoxShapeComponentRequestsBus::EventResult(m_boxShapeConfig, GetEntityId(), &BoxShapeComponentRequests::GetBoxConfiguration); + AZ::NonUniformScaleRequestBus::EventResult(m_nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale); + } + } + + void AxisAlignedBoxShapeComponent::Reflect(AZ::ReflectContext* context) + { + AxisAlignedBoxShape::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("AxisAlignedBoxShape", &AxisAlignedBoxShapeComponent::m_aaboxShape) + ; + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Constant("AxisAlignedBoxShapeComponentTypeId", BehaviorConstant(AxisAlignedBoxShapeComponentTypeId)); + } + } + + void AxisAlignedBoxShapeComponent::Activate() + { + m_aaboxShape.Activate(GetEntityId()); + } + + void AxisAlignedBoxShapeComponent::Deactivate() + { + m_aaboxShape.Deactivate(); + } + + bool AxisAlignedBoxShapeComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) + { + if (const auto config = azrtti_cast(baseConfig)) + { + m_aaboxShape.SetBoxConfiguration(*config); + return true; + } + return false; + } + + bool AxisAlignedBoxShapeComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const + { + if (auto config = azrtti_cast(outBaseConfig)) + { + *config = m_aaboxShape.GetBoxConfiguration(); + return true; + } + return false; + } + +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.h b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.h new file mode 100644 index 0000000000..094f9591d1 --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/AxisAlignedBoxShapeComponent.h @@ -0,0 +1,76 @@ +/* + * 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 + * + */ + +#pragma once + +#include + +#include "Rendering/EntityDebugDisplayComponent.h" +#include "AxisAlignedBoxShape.h" + +namespace LmbrCentral +{ + /// Type ID for the AxisAlignedBoxShapeComponent + static const AZ::Uuid AxisAlignedBoxShapeComponentTypeId = "{641D817E-1BC6-406A-BBB2-218541808E45}"; + + /// Type ID for the EditorAxisAlignedBoxShapeComponent + static const AZ::Uuid EditorAxisAlignedBoxShapeComponentTypeId = "{8C027DF6-E157-4159-9BF8-F1B925466F1F}"; + + /// Provide a Component interface for AxisAlignedBoxShape functionality. + class AxisAlignedBoxShapeComponent + : public AZ::Component + { + public: + AZ_COMPONENT(AxisAlignedBoxShapeComponent, AxisAlignedBoxShapeComponentTypeId) + static void Reflect(AZ::ReflectContext* context); + + // AZ::Component + void Activate() override; + void Deactivate() override; + bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; + bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + AxisAlignedBoxShape m_aaboxShape; ///< Stores underlying box type for this component. + }; + + /// Concrete EntityDebugDisplay implementation for BoxShape. + class AxisAlignedBoxShapeDebugDisplayComponent + : public EntityDebugDisplayComponent + , public ShapeComponentNotificationsBus::Handler + { + public: + AZ_COMPONENT(AxisAlignedBoxShapeDebugDisplayComponent, "{BA93F933-1DC9-4E0E-B930-A7E3968D5DD1}", EntityDebugDisplayComponent) + static void Reflect(AZ::ReflectContext* context); + + AxisAlignedBoxShapeDebugDisplayComponent() = default; + + // AZ::Component + void Activate() override; + void Deactivate() override; + bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; + bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; + + // EntityDebugDisplayComponent + void Draw(AzFramework::DebugDisplayRequests& debugDisplay) override; + + private: + AZ_DISABLE_COPY_MOVE(AxisAlignedBoxShapeDebugDisplayComponent) + + // ShapeComponentNotificationsBus + void OnShapeChanged(ShapeChangeReasons changeReason) override; + + BoxShapeConfig m_boxShapeConfig; ///< Stores configuration data for box shape. + AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); ///< Caches non-uniform scale for this entity. + }; +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/BoxShape.h b/Gems/LmbrCentral/Code/Source/Shape/BoxShape.h index a3831fbee6..a9dfd5c35f 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/BoxShape.h +++ b/Gems/LmbrCentral/Code/Source/Shape/BoxShape.h @@ -37,7 +37,7 @@ namespace LmbrCentral static void Reflect(AZ::ReflectContext* context); - void Activate(AZ::EntityId entityId); + virtual void Activate(AZ::EntityId entityId); void Deactivate(); void InvalidateCache(InvalidateShapeCacheReason reason); @@ -67,12 +67,9 @@ namespace LmbrCentral void SetDrawColor(const AZ::Color& color) { m_boxShapeConfig.SetDrawColor(color); } - protected: - - friend class EditorBoxShapeComponent; BoxShapeConfig& ModifyConfiguration() { return m_boxShapeConfig; } - private: + protected: /// Runtime data - cache potentially expensive operations. class BoxIntersectionDataCache : public IntersectionTestDataCache @@ -82,6 +79,7 @@ namespace LmbrCentral const AZ::Vector3& currentNonUniformScale = AZ::Vector3::CreateOne()) override; friend BoxShape; + friend class AxisAlignedBoxShape; AZ::Aabb m_aabb; ///< Aabb representing this Box (including the effects of scale). AZ::Obb m_obb; ///< Obb representing this Box (including the effects of scale). @@ -90,12 +88,12 @@ namespace LmbrCentral bool m_axisAligned = true; ///< Indicates whether the box is axis or object aligned. }; - BoxShapeConfig m_boxShapeConfig; ///< Underlying box configuration. BoxIntersectionDataCache m_intersectionDataCache; ///< Caches transient intersection data. AZ::Transform m_currentTransform; ///< Caches the current transform for the entity on which this component lives. AZ::EntityId m_entityId; ///< Id of the entity the box shape is attached to. AZ::NonUniformScaleChangedEvent::Handler m_nonUniformScaleChangedHandler; ///< Responds to changes in non-uniform scale. AZ::Vector3 m_currentNonUniformScale = AZ::Vector3::CreateOne(); ///< Caches the current non-uniform scale. + BoxShapeConfig m_boxShapeConfig; ///< Underlying box configuration. }; void DrawBoxShape( diff --git a/Gems/LmbrCentral/Code/Source/Shape/BoxShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/BoxShapeComponent.cpp index 40d5dce3cc..ce4a934e91 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/BoxShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/BoxShapeComponent.cpp @@ -101,23 +101,15 @@ namespace LmbrCentral } } - namespace ClassConverters - { - static bool DeprecateBoxColliderConfiguration(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); - static bool DeprecateBoxColliderComponent(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); - } - void BoxShapeConfig::Reflect(AZ::ReflectContext* context) { + // Don't reflect again if we're already reflected to the passed in context + if (context->IsTypeReflected(BoxShapeConfigTypeId)) + { + return; + } if (auto serializeContext = azrtti_cast(context)) { - // Deprecate: BoxColliderConfiguration -> BoxShapeConfig - serializeContext->ClassDeprecate( - "BoxColliderConfiguration", - "{282E47CB-9F6D-47AE-A210-4CE879527EFD}", - &ClassConverters::DeprecateBoxColliderConfiguration) - ; - serializeContext->Class() ->Version(2) ->Field("Dimensions", &BoxShapeConfig::m_dimensions) @@ -151,13 +143,6 @@ namespace LmbrCentral if (auto serializeContext = azrtti_cast(context)) { - // Deprecate: BoxColliderComponent -> BoxShapeComponent - serializeContext->ClassDeprecate( - "BoxColliderComponent", - "{C215EB2A-1803-4EDC-B032-F7C92C142337}", - &ClassConverters::DeprecateBoxColliderComponent) - ; - serializeContext->Class() ->Version(2, &ClassConverters::UpgradeBoxShapeComponent) ->Field("BoxShape", &BoxShapeComponent::m_boxShape) @@ -205,85 +190,4 @@ namespace LmbrCentral } return false; } - - namespace ClassConverters - { - static bool DeprecateBoxColliderConfiguration(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) - { - /* - Old: - - - - - New: - - - - */ - - // Cache the Dimensions - AZ::Vector3 oldDimensions; - const int oldIndex = classElement.FindElement(AZ_CRC("Size", 0xf7c0246a)); - if (oldIndex != -1) - { - classElement.GetSubElement(oldIndex).GetData(oldDimensions); - } - - // Convert to BoxShapeConfig - const bool result = classElement.Convert(context, "{F034FBA2-AC2F-4E66-8152-14DFB90D6283}"); - if (result) - { - const int newIndex = classElement.AddElement(context, "Dimensions"); - if (newIndex != -1) - { - classElement.GetSubElement(newIndex).SetData(context, oldDimensions); - return true; - } - } - return false; - } - - static bool DeprecateBoxColliderComponent(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) - { - /* - Old: - - - - - - - New: - - - - - - */ - - // Cache the Configuration - BoxShapeConfig configuration; - int configIndex = classElement.FindElement(AZ_CRC("Configuration", 0xa5e2a5d7)); - if (configIndex != -1) - { - classElement.GetSubElement(configIndex).GetData(configuration); - } - - // Convert to BoxShapeComponent - const bool result = classElement.Convert(context, BoxShapeComponentTypeId); - if (result) - { - configIndex = classElement.AddElement(context, "Configuration"); - if (configIndex != -1) - { - classElement.GetSubElement(configIndex).SetData(context, configuration); - } - return true; - } - return false; - } - - } // namespace ClassConverters - } // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.cpp new file mode 100644 index 0000000000..c833677b1d --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.cpp @@ -0,0 +1,168 @@ +/* + * 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 +#include +#include +#include +#include + +#include "AxisAlignedBoxShapeComponent.h" +#include "EditorAxisAlignedBoxShapeComponent.h" +#include "EditorShapeComponentConverters.h" +#include "ShapeDisplay.h" + +namespace LmbrCentral +{ + void EditorAxisAlignedBoxShapeComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("AxisAlignedBoxShape", &EditorAxisAlignedBoxShapeComponent::m_aaboxShape) + ->Field("ComponentMode", &EditorAxisAlignedBoxShapeComponent::m_componentModeDelegate) + ; + + if (auto editContext = serializeContext->GetEditContext()) + { + editContext->Class( + "Axis Aligned Box Shape", "The Axis Aligned Box Shape component creates a box around the associated entity") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Shape") + ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Box_Shape.svg") + ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Box_Shape.svg") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/shape/axis-aligned-box-shape/") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAxisAlignedBoxShapeComponent::m_aaboxShape, "Axis Aligned Box Shape", "Axis Aligned Box Shape Configuration") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAxisAlignedBoxShapeComponent::ConfigurationChanged) + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorAxisAlignedBoxShapeComponent::m_componentModeDelegate, "Component Mode", "Axis Aligned Box Shape Component Mode") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ; + } + } + } + + void EditorAxisAlignedBoxShapeComponent::Init() + { + EditorBaseShapeComponent::Init(); + + SetShapeComponentConfig(&m_aaboxShape.ModifyConfiguration()); + } + + void EditorAxisAlignedBoxShapeComponent::Activate() + { + EditorBaseShapeComponent::Activate(); + m_aaboxShape.Activate(GetEntityId()); + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId()); + AzToolsFramework::BoxManipulatorRequestBus::Handler::BusConnect( + AZ::EntityComponentIdPair(GetEntityId(), GetId())); + + // ComponentMode + m_componentModeDelegate.ConnectWithSingleComponentMode< + EditorAxisAlignedBoxShapeComponent, AzToolsFramework::BoxComponentMode>( + AZ::EntityComponentIdPair(GetEntityId(), GetId()), this); + } + + void EditorAxisAlignedBoxShapeComponent::Deactivate() + { + m_componentModeDelegate.Disconnect(); + + AzToolsFramework::BoxManipulatorRequestBus::Handler::BusDisconnect(); + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + m_aaboxShape.Deactivate(); + EditorBaseShapeComponent::Deactivate(); + } + + void EditorAxisAlignedBoxShapeComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + EditorBaseShapeComponent::GetProvidedServices(provided); + provided.push_back(AZ_CRC_CE("BoxShapeService")); + provided.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService")); + } + + void EditorAxisAlignedBoxShapeComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + dependent.push_back(AZ_CRC_CE("NonUniformScaleService")); + } + + void EditorAxisAlignedBoxShapeComponent::DisplayEntityViewport( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay) + { + DisplayShape( + debugDisplay, [this]() { return CanDraw(); }, + [this](AzFramework::DebugDisplayRequests& debugDisplay) + { + DrawBoxShape( + { m_aaboxShape.GetBoxConfiguration().GetDrawColor(), m_shapeWireColor, m_aaboxShape.GetBoxConfiguration().IsFilled() }, + m_aaboxShape.GetBoxConfiguration(), debugDisplay, m_aaboxShape.GetCurrentNonUniformScale()); + }, + m_aaboxShape.GetCurrentTransform()); + } + + void EditorAxisAlignedBoxShapeComponent::ConfigurationChanged() + { + m_aaboxShape.InvalidateCache(InvalidateShapeCacheReason::ShapeChange); + + ShapeComponentNotificationsBus::Event(GetEntityId(), + &ShapeComponentNotificationsBus::Events::OnShapeChanged, + ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged); + + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::Refresh, + AZ::EntityComponentIdPair(GetEntityId(), GetId())); + } + + void EditorAxisAlignedBoxShapeComponent::BuildGameEntity(AZ::Entity* gameEntity) + { + if (AxisAlignedBoxShapeComponent* boxShapeComponent = gameEntity->CreateComponent()) + { + boxShapeComponent->SetConfiguration(m_aaboxShape.GetBoxConfiguration()); + } + + if (m_visibleInGameView) + { + if (auto component = gameEntity->CreateComponent()) + { + component->SetConfiguration(m_aaboxShape.GetBoxConfiguration()); + } + } + } + + void EditorAxisAlignedBoxShapeComponent::OnTransformChanged( + const AZ::Transform& /*local*/, const AZ::Transform& /*world*/) + { + AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast( + &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::Refresh, + AZ::EntityComponentIdPair(GetEntityId(), GetId())); + } + + AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetDimensions() + { + return m_aaboxShape.GetBoxDimensions(); + } + + void EditorAxisAlignedBoxShapeComponent::SetDimensions(const AZ::Vector3& dimensions) + { + return m_aaboxShape.SetBoxDimensions(dimensions); + } + + AZ::Transform EditorAxisAlignedBoxShapeComponent::GetCurrentTransform() + { + return AzToolsFramework::TransformNormalizedScale(m_aaboxShape.GetCurrentTransform()); + } + + AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetBoxScale() + { + return AZ::Vector3(m_aaboxShape.GetCurrentTransform().GetUniformScale() * m_aaboxShape.GetCurrentNonUniformScale()); + } +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.h b/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.h new file mode 100644 index 0000000000..8bff4ea7e1 --- /dev/null +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorAxisAlignedBoxShapeComponent.h @@ -0,0 +1,71 @@ +/* + * 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 + * + */ + +#pragma once + +#include "AxisAlignedBoxShape.h" +#include "AxisAlignedBoxShapeComponent.h" +#include "EditorBaseShapeComponent.h" + +#include +#include +#include + + +namespace LmbrCentral +{ + /// Editor representation of Box Shape Component. + class EditorAxisAlignedBoxShapeComponent + : public EditorBaseShapeComponent + , private AzFramework::EntityDebugDisplayEventBus::Handler + , private AzToolsFramework::BoxManipulatorRequestBus::Handler + { + public: + AZ_EDITOR_COMPONENT(EditorAxisAlignedBoxShapeComponent, EditorAxisAlignedBoxShapeComponentTypeId, EditorBaseShapeComponent); + static void Reflect(AZ::ReflectContext* context); + + EditorAxisAlignedBoxShapeComponent() = default; + + // AZ::Component + void Init() override; + void Activate() override; + void Deactivate() override; + + protected: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // EditorComponentBase + void BuildGameEntity(AZ::Entity* gameEntity) override; + + // AZ::TransformNotificationBus::Handler + void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; + + private: + AZ_DISABLE_COPY_MOVE(EditorAxisAlignedBoxShapeComponent) + + // AzFramework::EntityDebugDisplayEventBus + void DisplayEntityViewport( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay) override; + + // AzToolsFramework::BoxManipulatorRequestBus + AZ::Vector3 GetDimensions() override; + void SetDimensions(const AZ::Vector3& dimensions) override; + AZ::Transform GetCurrentTransform() override; + AZ::Vector3 GetBoxScale() override; + + void ConfigurationChanged(); + + AxisAlignedBoxShape m_aaboxShape; ///< Stores underlying box representation for this component. + + using ComponentModeDelegate = AzToolsFramework::ComponentModeFramework::ComponentModeDelegate; + ComponentModeDelegate m_componentModeDelegate; /**< Responsible for detecting ComponentMode activation + * and creating a concrete ComponentMode.*/ + }; +} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Shape/EditorBoxShapeComponent.cpp b/Gems/LmbrCentral/Code/Source/Shape/EditorBoxShapeComponent.cpp index f645c54610..2983ca7753 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/EditorBoxShapeComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/EditorBoxShapeComponent.cpp @@ -49,7 +49,7 @@ namespace LmbrCentral ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/shape/box-shape/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBoxShapeComponent::m_boxShape, "Box Shape", "Box Shape Configuration") - // ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) // disabled - prevents ChangeNotify attribute firing correctly + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBoxShapeComponent::ConfigurationChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBoxShapeComponent::m_componentModeDelegate, "Component Mode", "Box Shape Component Mode") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) diff --git a/Gems/LmbrCentral/Code/Tests/AxisAlignedBoxShapeTest.cpp b/Gems/LmbrCentral/Code/Tests/AxisAlignedBoxShapeTest.cpp new file mode 100644 index 0000000000..c3e8d06791 --- /dev/null +++ b/Gems/LmbrCentral/Code/Tests/AxisAlignedBoxShapeTest.cpp @@ -0,0 +1,238 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace UnitTest +{ + class AxisAlignedBoxShapeTest : public AllocatorsFixture + { + AZStd::unique_ptr m_serializeContext; + AZStd::unique_ptr m_transformComponentDescriptor; + AZStd::unique_ptr m_axisAlignedBoxShapeComponentDescriptor; + AZStd::unique_ptr m_axisAlignedBoxShapeDebugDisplayComponentDescriptor; + AZStd::unique_ptr m_nonUniformScaleComponentDescriptor; + + public: + void SetUp() override + { + AllocatorsFixture::SetUp(); + m_serializeContext = AZStd::make_unique(); + + m_transformComponentDescriptor = + AZStd::unique_ptr(AzFramework::TransformComponent::CreateDescriptor()); + m_transformComponentDescriptor->Reflect(&(*m_serializeContext)); + m_axisAlignedBoxShapeComponentDescriptor = + AZStd::unique_ptr(LmbrCentral::AxisAlignedBoxShapeComponent::CreateDescriptor()); + m_axisAlignedBoxShapeComponentDescriptor->Reflect(&(*m_serializeContext)); + m_axisAlignedBoxShapeDebugDisplayComponentDescriptor = + AZStd::unique_ptr(LmbrCentral::AxisAlignedBoxShapeDebugDisplayComponent::CreateDescriptor()); + m_axisAlignedBoxShapeDebugDisplayComponentDescriptor->Reflect(&(*m_serializeContext)); + m_nonUniformScaleComponentDescriptor = + AZStd::unique_ptr(AzFramework::NonUniformScaleComponent::CreateDescriptor()); + m_nonUniformScaleComponentDescriptor->Reflect(&(*m_serializeContext)); + } + + void TearDown() override + { + m_transformComponentDescriptor.reset(); + m_axisAlignedBoxShapeComponentDescriptor.reset(); + m_axisAlignedBoxShapeDebugDisplayComponentDescriptor.reset(); + m_nonUniformScaleComponentDescriptor.reset(); + m_serializeContext.reset(); + AllocatorsFixture::TearDown(); + } + }; + + void CreateAxisAlignedBox(const AZ::Transform& transform, const AZ::Vector3& dimensions, AZ::Entity& entity) + { + entity.CreateComponent(); + entity.CreateComponent(); + entity.CreateComponent(); + + entity.Init(); + entity.Activate(); + + AZ::TransformBus::Event(entity.GetId(), &AZ::TransformBus::Events::SetWorldTM, transform); + LmbrCentral::BoxShapeComponentRequestsBus::Event( + entity.GetId(), &LmbrCentral::BoxShapeComponentRequestsBus::Events::SetBoxDimensions, dimensions); + } + + void CreateAxisAlignedBoxWithNonUniformScale( + const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& dimensions, AZ::Entity& entity) + { + entity.CreateComponent(); + entity.CreateComponent(); + entity.CreateComponent(); + entity.CreateComponent(); + + entity.Init(); + entity.Activate(); + + AZ::TransformBus::Event(entity.GetId(), &AZ::TransformBus::Events::SetWorldTM, transform); + LmbrCentral::BoxShapeComponentRequestsBus::Event( + entity.GetId(), &LmbrCentral::BoxShapeComponentRequestsBus::Events::SetBoxDimensions, dimensions); + AZ::NonUniformScaleRequestBus::Event(entity.GetId(), &AZ::NonUniformScaleRequests::SetScale, nonUniformScale); + } + + void CreateDefaultAxisAlignedBox(const AZ::Transform& transform, AZ::Entity& entity) + { + CreateAxisAlignedBox(transform, AZ::Vector3(10.0f, 10.0f, 10.0f), entity); + } + + TEST_F(AxisAlignedBoxShapeTest, EntityTransformIsCorrect) + { + AZ::Entity entity; + CreateAxisAlignedBox( + AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi), + AZ::Vector3(1.0f), entity); + + AZ::Transform transform; + AZ::TransformBus::EventResult(transform, entity.GetId(), &AZ::TransformBus::Events::GetWorldTM); + + EXPECT_EQ(transform, AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi)); + } + + TEST_F(AxisAlignedBoxShapeTest, BoxWithZRotationHasCorrectRayIntersection) + { + AZ::Entity entity; + CreateAxisAlignedBox( + AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi), + AZ::Vector3(1.0f), entity); + + bool rayHit = false; + float distance; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(5.0f, 0.0f, 0.0f), + AZ::Vector3(-1.0f, 0.0f, 0.0f), distance); + + // This test creates a unit box centered on (0, 0, 0) and rotated by 45 degrees. The distance to the box should + // be 4.5 if it isn't rotated but less if there is any rotation. + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 4.5f, 1e-2f); + } + + TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationAndRotationsHasCorrectRayIntersection) + { + AZ::Entity entity; + CreateAxisAlignedBox( + AZ::Transform::CreateFromQuaternionAndTranslation( + AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), AZ::Constants::HalfPi) * + AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), AZ::Constants::QuarterPi), + AZ::Vector3(-10.0f, -10.0f, -10.0f)), + AZ::Vector3(4.0f, 4.0f, 2.0f), entity); + + bool rayHit = false; + float distance; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(-10.0f, -10.0f, 0.0f), + AZ::Vector3(0.0f, 0.0f, -1.0f), distance); + + // This test creates a box of dimensions (4.0, 4.0, 2.0) centered on (-10, -10, 0) and rotated in X and Z. The distance to the box should + // be 9.0 if it isn't rotated but less if there is any rotation. + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 9.00f, 1e-2f); + } + + TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationHasCorrectRayIntersection) + { + AZ::Entity entity; + CreateAxisAlignedBox( + AZ::Transform::CreateTranslation(AZ::Vector3(100.0f, 100.0f, 0.0f)), + AZ::Vector3(5.0f, 5.0f, 5.0f), entity); + + bool rayHit = false; + float distance; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(100.0f, 100.0f, -100.0f), + AZ::Vector3(0.0f, 0.0f, 1.0f), distance); + + // This test creates a box of dimensions (5.0, 5.0, 5.0) centered on (100, 100, 0) and not rotated. The distance to the box + // should be 97.5. + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 97.5f, 1e-2f); + } + + TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationRotationAndScaleHasCorrectRayIntersection) + { + AZ::Entity entity; + CreateAxisAlignedBox( + AZ::Transform( + AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi), 3.0f), + AZ::Vector3(2.0f, 4.0f, 1.0f), entity); + + bool rayHit = false; + float distance; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.0f, -10.0f, 4.0f), + AZ::Vector3(0.0f, 1.0f, 0.0f), distance); + + // This test creates a box of dimensions (2.0, 4.0, 1.0) centered on (0, 0, 5) and rotated about the Y axis by 45 degrees. + // The distance to the box should be 4.0 if not rotated but scaled and less if it is. + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 4.0f, 1e-2f); + } + + TEST_F(AxisAlignedBoxShapeTest, RayIntersectWithBoxRotatedNonUniformScale) + { + AZ::Entity entity; + CreateAxisAlignedBoxWithNonUniformScale( + AZ::Transform( + AZ::Vector3(2.0f, -5.0f, 3.0f), AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi), + 0.5f), + AZ::Vector3(2.2f, 1.8f, 0.4f), AZ::Vector3(0.2f, 2.6f, 1.2f), entity); + + // This test creates a box of dimensions (2.2, 1.8, 0.4) centered on (2.0, -5, 3) and rotated about the Y axis by 45 degrees. + // The box is tested for axis-alignment by firing various rays and ensuring they either hit or miss the box. Any failure here + // would show the box has been rotated. + + // Ray should just miss the box + bool rayHit = false; + float distance = AZ::Constants::FloatMax; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.8f, -6.2f, 3.0f), + AZ::Vector3(1.0f, 0.0f, 0.0f), distance); + EXPECT_FALSE(rayHit); + + // Ray should just hit the box + rayHit = false; + distance = AZ::Constants::FloatMax; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.8f, -6.1f, 3.0f), + AZ::Vector3(1.0f, 0.0f, 0.0f), distance); + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 0.09f, 1e-3f); + + // Ray should just miss the box + rayHit = false; + distance = AZ::Constants::FloatMax; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(2.2f, -6.2f, 3.0f), + AZ::Vector3(0.0f, 1.0f, 0.0f), distance); + EXPECT_FALSE(rayHit); + + // Ray should just hit the box + rayHit = false; + distance = AZ::Constants::FloatMax; + LmbrCentral::ShapeComponentRequestsBus::EventResult( + rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(2.1f, -6.2f, 3.0f), + AZ::Vector3(0.0f, 1.0f, 0.0f), distance); + EXPECT_TRUE(rayHit); + EXPECT_NEAR(distance, 0.03f, 1e-3f); + } +} // namespace UnitTest diff --git a/Gems/LmbrCentral/Code/Tests/DiskShapeTest.cpp b/Gems/LmbrCentral/Code/Tests/DiskShapeTest.cpp index e9c19585cc..65693a2a2e 100644 --- a/Gems/LmbrCentral/Code/Tests/DiskShapeTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/DiskShapeTest.cpp @@ -34,10 +34,10 @@ namespace 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, }; - const uint32_t RayCount = 5; + const uint32_t RayCountDisk = 5; // Various normalized offset directions from center of disk along disk's surface. - const AZStd::array OffsetsFromCenter = + const AZStd::array OffsetsFromCenterDisk = { AZ::Vector3(0.18f, -0.50f, 0.0f).GetNormalized(), AZ::Vector3(-0.08f, 0.59f, 0.0f).GetNormalized(), @@ -47,7 +47,7 @@ namespace }; // Various directions away from a point on the disk's surface - const AZStd::array OffsetsFromSurface = + const AZStd::array OffsetsFromSurfaceDisk = { AZ::Vector3(0.69f, 0.38f, 0.09f).GetNormalized(), AZ::Vector3(-0.98f, -0.68f, -0.28f).GetNormalized(), @@ -57,7 +57,7 @@ namespace }; // Various distance away from the surface for the rays - const AZStd::array RayDistances = + const AZStd::array RayDistancesDisk = { 0.5f, 1.0f, 2.0f, 4.0f, 8.0f }; @@ -185,7 +185,7 @@ namespace UnitTest } // Offsets from center scaled down from the disk edge so that all the rays should hit - const AZStd::array offsetFromCenterScale = + const AZStd::array offsetFromCenterScale = { 0.8f, 0.2f, @@ -197,20 +197,20 @@ namespace UnitTest // Construct rays and test against the different disks for (uint32_t diskIndex = 0; diskIndex < DiskCount; ++diskIndex) { - for (uint32_t rayIndex = 0; rayIndex < RayCount; ++rayIndex) + for (uint32_t rayIndex = 0; rayIndex < RayCountDisk; ++rayIndex) { - AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenter[rayIndex] * DiskRadii[diskIndex] * offsetFromCenterScale[rayIndex]; + AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenterDisk[rayIndex] * DiskRadii[diskIndex] * offsetFromCenterScale[rayIndex]; AZ::Vector3 positionOnDiskSurface = DiskTransforms[diskIndex].TransformPoint(scaledOffsetFromCenter); - AZ::Vector3 rayOrigin = positionOnDiskSurface + OffsetsFromSurface[rayIndex] * RayDistances[rayIndex]; + AZ::Vector3 rayOrigin = positionOnDiskSurface + OffsetsFromSurfaceDisk[rayIndex] * RayDistancesDisk[rayIndex]; bool rayHit2 = false; float distance2; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit2, diskEntities[diskIndex].GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, - rayOrigin, -OffsetsFromSurface[rayIndex], distance2); + rayOrigin, -OffsetsFromSurfaceDisk[rayIndex], distance2); EXPECT_TRUE(rayHit2); - EXPECT_NEAR(distance2, RayDistances[rayIndex], 1e-4f); + EXPECT_NEAR(distance2, RayDistancesDisk[rayIndex], 1e-4f); } } @@ -241,7 +241,7 @@ namespace UnitTest } // Offsets from center scaled up from the disk edge so that all the rays should miss - const AZStd::array offsetFromCenterScale = + const AZStd::array offsetFromCenterScale = { 1.8f, 1.2f, @@ -253,17 +253,17 @@ namespace UnitTest // Construct rays and test against the different disks for (uint32_t diskIndex = 0; diskIndex < DiskCount; ++diskIndex) { - for (uint32_t rayIndex = 0; rayIndex < RayCount; ++rayIndex) + for (uint32_t rayIndex = 0; rayIndex < RayCountDisk; ++rayIndex) { - AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenter[rayIndex] * DiskRadii[diskIndex] * offsetFromCenterScale[rayIndex]; + AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenterDisk[rayIndex] * DiskRadii[diskIndex] * offsetFromCenterScale[rayIndex]; AZ::Vector3 positionOnDiskSurface = DiskTransforms[diskIndex].TransformPoint(scaledOffsetFromCenter); - AZ::Vector3 rayOrigin = positionOnDiskSurface + OffsetsFromSurface[rayIndex] * RayDistances[rayIndex]; + AZ::Vector3 rayOrigin = positionOnDiskSurface + OffsetsFromSurfaceDisk[rayIndex] * RayDistancesDisk[rayIndex]; bool rayHit2 = false; float distance2; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit2, diskEntities[diskIndex].GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, - rayOrigin, -OffsetsFromSurface[rayIndex], distance2); + rayOrigin, -OffsetsFromSurfaceDisk[rayIndex], distance2); EXPECT_FALSE(rayHit2); } diff --git a/Gems/LmbrCentral/Code/Tests/QuadShapeTest.cpp b/Gems/LmbrCentral/Code/Tests/QuadShapeTest.cpp index a28916bb24..c02cf18aca 100644 --- a/Gems/LmbrCentral/Code/Tests/QuadShapeTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/QuadShapeTest.cpp @@ -41,10 +41,10 @@ namespace LmbrCentral::QuadShapeConfig(1.0f, 0.5f), }; - const uint32_t RayCount = 5; + const uint32_t RayCountQuad = 5; // Various normalized offset directions from center of quad along quad's surface. - const AZStd::array OffsetsFromCenter = + const AZStd::array OffsetsFromCenterQuad = { AZ::Vector3( 0.18f, -0.50f, 0.0f).GetNormalized(), AZ::Vector3(-0.08f, 0.59f, 0.0f).GetNormalized(), @@ -54,7 +54,7 @@ namespace }; // Various directions away from a point on the quad's surface - const AZStd::array OffsetsFromSurface = + const AZStd::array OffsetsFromSurfaceQuad = { AZ::Vector3( 0.69f, 0.38f, 0.09f).GetNormalized(), AZ::Vector3(-0.98f, -0.68f, -0.28f).GetNormalized(), @@ -64,7 +64,7 @@ namespace }; // Various distance away from the surface for the rays - const AZStd::array RayDistances = + const AZStd::array RayDistancesQuad = { 0.5f, 1.0f, 2.0f, 4.0f, 8.0f }; @@ -248,23 +248,23 @@ namespace UnitTest // Construct rays and test against the different quads for (uint32_t quadIndex = 0; quadIndex < QuadCount; ++quadIndex) { - for (uint32_t rayIndex = 0; rayIndex < RayCount; ++rayIndex) + for (uint32_t rayIndex = 0; rayIndex < RayCountQuad; ++rayIndex) { - // OffsetsFromCenter are all less than 1, so scale by the dimensions of the quad. + // OffsetsFromCenterQuad are all less than 1, so scale by the dimensions of the quad. AZ::Vector3 scaledWidthHeight = AZ::Vector3(QuadDims[quadIndex].m_width, QuadDims[quadIndex].m_height, 0.0f); // Scale the offset and multiply by 0.5 because distance from center is half the width/height - AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenter[rayIndex] * scaledWidthHeight * 0.5f; + AZ::Vector3 scaledOffsetFromCenter = OffsetsFromCenterQuad[rayIndex] * scaledWidthHeight * 0.5f; AZ::Vector3 positionOnQuadSurface = QuadTransforms[quadIndex].TransformPoint(scaledOffsetFromCenter); - AZ::Vector3 rayOrigin = positionOnQuadSurface + OffsetsFromSurface[rayIndex] * RayDistances[rayIndex]; + AZ::Vector3 rayOrigin = positionOnQuadSurface + OffsetsFromSurfaceQuad[rayIndex] * RayDistancesQuad[rayIndex]; bool rayHit2 = false; float distance2; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit2, quadEntities[quadIndex].GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, - rayOrigin, -OffsetsFromSurface[rayIndex], distance2); + rayOrigin, -OffsetsFromSurfaceQuad[rayIndex], distance2); EXPECT_TRUE(rayHit2); - EXPECT_NEAR(distance2, RayDistances[rayIndex], 1e-4f); + EXPECT_NEAR(distance2, RayDistancesQuad[rayIndex], 1e-4f); } } @@ -297,20 +297,20 @@ namespace UnitTest // Construct rays and test against the different quads for (uint32_t quadIndex = 0; quadIndex < QuadCount; ++quadIndex) { - for (uint32_t rayIndex = 0; rayIndex < RayCount; ++rayIndex) + for (uint32_t rayIndex = 0; rayIndex < RayCountQuad; ++rayIndex) { - // OffsetsFromCenter are all less than 1, so scale by the dimensions of the quad. + // OffsetsFromCenterQuad are all less than 1, so scale by the dimensions of the quad. AZ::Vector3 scaledWidthHeight = AZ::Vector3(QuadDims[quadIndex].m_width, QuadDims[quadIndex].m_height, 0.0f); - // Scale the offset and add 1.0 to OffsetsFromCenter to ensure the point is outside the quad. - AZ::Vector3 scaledOffsetFromCenter = (AZ::Vector3::CreateOne() + OffsetsFromCenter[rayIndex]) * scaledWidthHeight; + // Scale the offset and add 1.0 to OffsetsFromCenterQuad to ensure the point is outside the quad. + AZ::Vector3 scaledOffsetFromCenter = (AZ::Vector3::CreateOne() + OffsetsFromCenterQuad[rayIndex]) * scaledWidthHeight; AZ::Vector3 positionOnQuadSurface = QuadTransforms[quadIndex].TransformPoint(scaledOffsetFromCenter); - AZ::Vector3 rayOrigin = positionOnQuadSurface + OffsetsFromSurface[rayIndex] * RayDistances[rayIndex]; + AZ::Vector3 rayOrigin = positionOnQuadSurface + OffsetsFromSurfaceQuad[rayIndex] * RayDistancesQuad[rayIndex]; bool rayHit2 = false; float distance2; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit2, quadEntities[quadIndex].GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, - rayOrigin, -OffsetsFromSurface[rayIndex], distance2); + rayOrigin, -OffsetsFromSurfaceQuad[rayIndex], distance2); EXPECT_FALSE(rayHit2); } diff --git a/Gems/LmbrCentral/Code/include/LmbrCentral/Shape/BoxShapeComponentBus.h b/Gems/LmbrCentral/Code/include/LmbrCentral/Shape/BoxShapeComponentBus.h index a84b0e2a4f..488e8b5617 100644 --- a/Gems/LmbrCentral/Code/include/LmbrCentral/Shape/BoxShapeComponentBus.h +++ b/Gems/LmbrCentral/Code/include/LmbrCentral/Shape/BoxShapeComponentBus.h @@ -21,13 +21,16 @@ namespace LmbrCentral /// Type ID for the EditorBoxShapeComponent static const AZ::Uuid EditorBoxShapeComponentTypeId = "{2ADD9043-48E8-4263-859A-72E0024372BF}"; + /// Type ID for the BoxShapeConfig + static const AZ::Uuid BoxShapeConfigTypeId = "{F034FBA2-AC2F-4E66-8152-14DFB90D6283}"; + /// Configuration data for BoxShapeComponent class BoxShapeConfig : public ShapeComponentConfig { public: AZ_CLASS_ALLOCATOR(BoxShapeConfig, AZ::SystemAllocator, 0) - AZ_RTTI(BoxShapeConfig, "{F034FBA2-AC2F-4E66-8152-14DFB90D6283}", ShapeComponentConfig) + AZ_RTTI(BoxShapeConfig, BoxShapeConfigTypeId, ShapeComponentConfig) static void Reflect(AZ::ReflectContext* context); diff --git a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake index f96fd7a3b2..5c77888922 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake @@ -50,6 +50,8 @@ set(FILES Source/Shape/EditorDiskShapeComponent.cpp Source/Shape/EditorBoxShapeComponent.h Source/Shape/EditorBoxShapeComponent.cpp + Source/Shape/EditorAxisAlignedBoxShapeComponent.h + Source/Shape/EditorAxisAlignedBoxShapeComponent.cpp Source/Shape/EditorCylinderShapeComponent.h Source/Shape/EditorCylinderShapeComponent.cpp Source/Shape/EditorCapsuleShapeComponent.h diff --git a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake index d663d2ec06..18412e2a38 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake @@ -106,6 +106,10 @@ set(FILES Source/Shape/SphereShape.cpp Source/Shape/SphereShapeComponent.h Source/Shape/SphereShapeComponent.cpp + Source/Shape/AxisAlignedBoxShape.h + Source/Shape/AxisAlignedBoxShape.cpp + Source/Shape/AxisAlignedBoxShapeComponent.h + Source/Shape/AxisAlignedBoxShapeComponent.cpp Source/Shape/BoxShape.h Source/Shape/BoxShape.cpp Source/Shape/BoxShapeComponent.h diff --git a/Gems/LmbrCentral/Code/lmbrcentral_tests_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_tests_files.cmake index 5c4da3db73..c0f1ffd9ec 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_tests_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_tests_files.cmake @@ -8,6 +8,7 @@ set(FILES Tests/AudioComponentTests.cpp + Tests/AxisAlignedBoxShapeTest.cpp Tests/BoxShapeTest.cpp Tests/BundlingSystemComponentTests.cpp Tests/SphereShapeTest.cpp diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp index ef73bb967d..4e2d740656 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/EBusEventHandler.cpp @@ -78,6 +78,8 @@ namespace ScriptCanvas variableIds.insert(scopedVariableId->m_identifier); } } + + Node::CollectVariableReferences(variableIds); } bool EBusEventHandler::ContainsReferencesToVariables(const AZStd::unordered_set< ScriptCanvas::VariableId >& variableIds) const @@ -90,11 +92,14 @@ namespace ScriptCanvas if (scopedVariableId) { - return variableIds.find(scopedVariableId->m_identifier) != variableIds.end(); + if(variableIds.find(scopedVariableId->m_identifier) != variableIds.end()) + { + return true; + } } } - return false; + return Node::ContainsReferencesToVariables(variableIds); } size_t EBusEventHandler::GenerateFingerprint() const diff --git a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp index 06372a3490..1c296b2e2c 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.cpp @@ -105,17 +105,19 @@ namespace Terrain AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId()); LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId()); TerrainAreaRequestBus::Handler::BusConnect(GetEntityId()); + TerrainSpawnerRequestBus::Handler::BusConnect(GetEntityId()); TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RegisterArea, GetEntityId()); } void TerrainLayerSpawnerComponent::Deactivate() { - TerrainAreaRequestBus::Handler::BusDisconnect(); TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::UnregisterArea, GetEntityId()); - - AZ::TransformNotificationBus::Handler::BusDisconnect(); + TerrainSpawnerRequestBus::Handler::BusDisconnect(); + TerrainAreaRequestBus::Handler::BusDisconnect(); LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect(); + AZ::TransformNotificationBus::Handler::BusDisconnect(); + } bool TerrainLayerSpawnerComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) @@ -147,6 +149,17 @@ namespace Terrain { RefreshArea(); } + + void TerrainLayerSpawnerComponent::GetPriority(AZ::u32& outLayer, AZ::u32& outPriority) + { + outLayer = m_configuration.m_layer; + outPriority = m_configuration.m_priority; + } + + bool TerrainLayerSpawnerComponent::GetUseGroundPlane() + { + return m_configuration.m_useGroundPlane; + } void TerrainLayerSpawnerComponent::RegisterArea() { diff --git a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.h b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.h index 1f1ae90227..3f8e72e1b8 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainLayerSpawnerComponent.h @@ -59,6 +59,7 @@ namespace Terrain , private AZ::TransformNotificationBus::Handler , private LmbrCentral::ShapeComponentNotificationsBus::Handler , private Terrain::TerrainAreaRequestBus::Handler + , private Terrain::TerrainSpawnerRequestBus::Handler { public: template @@ -80,7 +81,6 @@ namespace Terrain bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; - ////////////////////////////////////////////////////////////////////////// // AZ::TransformNotificationBus::Handler void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; @@ -88,6 +88,10 @@ namespace Terrain // ShapeComponentNotificationsBus void OnShapeChanged(ShapeChangeReasons changeReason) override; + // TerrainSpawnerRequestBus + void GetPriority(AZ::u32& outLayer, AZ::u32& outPriority) override; + bool GetUseGroundPlane() override; + void RegisterArea() override; void RefreshArea() override; diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 90b74f08ba..a271d624f5 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -17,6 +17,33 @@ using namespace Terrain; +bool TerrainLayerPriorityComparator::operator()(const AZ::EntityId& layer1id, const AZ::EntityId& layer2id) const +{ + // Comparator for insertion/keylookup. + // Sorts into layer/priority order, highest priority first. + AZ::u32 priority1, layer1; + Terrain::TerrainSpawnerRequestBus::Event(layer1id, &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer1, priority1); + + AZ::u32 priority2, layer2; + Terrain::TerrainSpawnerRequestBus::Event(layer2id, &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer2, priority2); + + if (layer1 < layer2) + { + return false; + } + else if (layer1 > layer2) + { + return true; + } + + if (priority1 != priority2) + { + return priority1 > priority2; + } + + return layer1id > layer2id; +} + TerrainSystem::TerrainSystem() { Terrain::TerrainSystemServiceRequestBus::Handler::BusConnect(); @@ -78,17 +105,14 @@ float TerrainSystem::GetHeightSynchronous(float x, float y) const AZStd::shared_lock lock(m_areaMutex); - if (!m_registeredAreas.empty()) + for (auto& [areaId, areaBounds] : m_registeredAreas) { - for (auto& [areaId, areaBounds] : m_registeredAreas) + inPosition.SetZ(areaBounds.GetMin().GetZ()); + if (areaBounds.Contains(inPosition)) { - inPosition.SetZ(areaBounds.GetMin().GetZ()); - if (areaBounds.Contains(inPosition)) - { - Terrain::TerrainAreaHeightRequestBus::Event( - areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, - Terrain::TerrainAreaHeightRequestBus::Events::Sampler::DEFAULT); - } + Terrain::TerrainAreaHeightRequestBus::Event( + areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, + Terrain::TerrainAreaHeightRequestBus::Events::Sampler::DEFAULT); } } @@ -305,26 +329,34 @@ void TerrainSystem::SystemDeactivate() void TerrainSystem::RegisterArea(AZ::EntityId areaId) { - { - AZStd::unique_lock lock(m_areaMutex); - AZ::Aabb aabb = AZ::Aabb::CreateNull(); - LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); - m_registeredAreas[areaId] = aabb; - } - - RefreshArea(areaId); + AZStd::unique_lock lock(m_areaMutex); + AZ::Aabb aabb = AZ::Aabb::CreateNull(); + LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); + m_registeredAreas[areaId] = aabb; + m_dirtyRegion.AddAabb(aabb); + m_terrainHeightDirty = true; } void TerrainSystem::UnregisterArea(AZ::EntityId areaId) { - { - AZStd::unique_lock lock(m_areaMutex); - AZ::Aabb aabb = AZ::Aabb::CreateNull(); - LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); - m_registeredAreas.erase(areaId); - } + AZStd::unique_lock lock(m_areaMutex); - RefreshArea(areaId); + // Remove the data for this entity from the registered areas. + // Erase_if is used as erase would use the comparator to lookup the entity id in the map. + // As the comparator will get the new layer/priority data for the entity, the id lookup will fail. + AZStd::erase_if( + m_registeredAreas, + [areaId, this](const auto& item) + { + auto const& [entityId, aabb] = item; + if (areaId == entityId) + { + m_dirtyRegion.AddAabb(aabb); + m_terrainHeightDirty = true; + return true; + } + return false; + }); } void TerrainSystem::RefreshArea(AZ::EntityId areaId) @@ -336,7 +368,6 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId) AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second : AZ::Aabb::CreateNull(); AZ::Aabb newAabb = AZ::Aabb::CreateNull(); LmbrCentral::ShapeComponentRequestsBus::EventResult(newAabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb); - m_registeredAreas[areaId] = newAabb; AZ::Aabb expandedAabb = oldAabb; @@ -400,31 +431,37 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/) const uint32_t pixelDataSize = width * height * sizeof(float); memset(pixels.data(), 0, pixelDataSize); - for (auto& [areaId, areaBounds] : m_registeredAreas) + for (uint32_t y = 0; y < height; y++) { - for (uint32_t y = 0; y < height; y++) + for (uint32_t x = 0; x < width; x++) { - for (uint32_t x = 0; x < width; x++) + // Find the first terrain layer that covers this position. This will be the highest priority, so others can be ignored. + for (auto& [areaId, areaBounds] : m_registeredAreas) { AZ::Vector3 inPosition( (x * m_currentSettings.m_heightQueryResolution.GetX()) + m_currentSettings.m_worldBounds.GetMin().GetX(), (y * m_currentSettings.m_heightQueryResolution.GetY()) + m_currentSettings.m_worldBounds.GetMin().GetY(), areaBounds.GetMin().GetZ()); - if (areaBounds.Contains(inPosition)) + + if (!areaBounds.Contains(inPosition)) { - AZ::Vector3 outPosition; - const Terrain::TerrainAreaHeightRequests::Sampler sampleFilter = - Terrain::TerrainAreaHeightRequests::Sampler::DEFAULT; - - Terrain::TerrainAreaHeightRequestBus::Event( - areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, sampleFilter); - - pixels[(y * width) + x] = (outPosition.GetZ() - m_currentSettings.m_worldBounds.GetMin().GetZ()) / - m_currentSettings.m_worldBounds.GetExtents().GetZ(); + continue; } + + AZ::Vector3 outPosition; + const Terrain::TerrainAreaHeightRequests::Sampler sampleFilter = Terrain::TerrainAreaHeightRequests::Sampler::DEFAULT; + + Terrain::TerrainAreaHeightRequestBus::Event( + areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, sampleFilter); + + pixels[(y * width) + x] = (outPosition.GetZ() - m_currentSettings.m_worldBounds.GetMin().GetZ()) / + m_currentSettings.m_worldBounds.GetExtents().GetZ(); + + break; } } } + const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); auto terrainFeatureProcessor = scene->GetFeatureProcessor(); diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 2d2286a0c3..0239170640 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -25,6 +25,11 @@ namespace Terrain { + struct TerrainLayerPriorityComparator + { + bool operator()(const AZ::EntityId& layer1id, const AZ::EntityId& layer2id) const; + }; + class TerrainSystem : public AzFramework::Terrain::TerrainDataRequestBus::Handler , private Terrain::TerrainSystemServiceRequestBus::Handler @@ -112,6 +117,6 @@ namespace Terrain AZ::Aabb m_dirtyRegion; mutable AZStd::shared_mutex m_areaMutex; - AZStd::unordered_map m_registeredAreas; + AZStd::map m_registeredAreas; }; } // namespace Terrain diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h index e999cbf8be..cb41ba9957 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystemBus.h @@ -112,5 +112,26 @@ namespace Terrain }; using TerrainAreaHeightRequestBus = AZ::EBus; + + /** + * A bus for the TerrainSystem to interrogate TerrainLayerSpawners. + */ + class TerrainSpawnerRequests + : public AZ::ComponentBus + { + public: + //////////////////////////////////////////////////////////////////////// + // EBusTraits + using MutexType = AZStd::recursive_mutex; + //////////////////////////////////////////////////////////////////////// + + virtual ~TerrainSpawnerRequests() = default; + + virtual void GetPriority(AZ::u32& outLayer, AZ::u32& outPriority) = 0; + virtual bool GetUseGroundPlane() = 0; + + }; + + using TerrainSpawnerRequestBus = AZ::EBus; } diff --git a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp new file mode 100644 index 0000000000..91d6a26f75 --- /dev/null +++ b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp @@ -0,0 +1,222 @@ +/* + * 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 +#include + +#include + +#include +#include +#include + +#include + +class LayerSpawnerComponentTest + : public ::testing::Test +{ +protected: + AZ::ComponentApplication m_app; + + AZStd::unique_ptr m_entity; + Terrain::TerrainLayerSpawnerComponent* m_layerSpawnerComponent; + UnitTest::MockBoxShapeComponent* m_shapeComponent; + AZStd::unique_ptr m_terrainSystem; + + void SetUp() override + { + AZ::ComponentApplication::Descriptor appDesc; + appDesc.m_memoryBlocksByteSize = 20 * 1024 * 1024; + appDesc.m_recordingMode = AZ::Debug::AllocationRecords::RECORD_NO_RECORDS; + appDesc.m_stackRecordLevels = 20; + + m_app.Create(appDesc); + } + + void TearDown() override + { + if (m_terrainSystem) + { + m_terrainSystem->Deactivate(); + } + m_app.Destroy(); + } + + void CreateEntity() + { + m_entity = AZStd::make_unique(); + m_entity->Init(); + + ASSERT_TRUE(m_entity); + } + + void AddLayerSpawnerAndShapeComponentToEntity() + { + AddLayerSpawnerAndShapeComponentToEntity(Terrain::TerrainLayerSpawnerConfig()); + } + + void AddLayerSpawnerAndShapeComponentToEntity(const Terrain::TerrainLayerSpawnerConfig& config) + { + m_layerSpawnerComponent = m_entity->CreateComponent(config); + m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor()); + + m_shapeComponent = m_entity->CreateComponent(); + m_app.RegisterComponentDescriptor(m_shapeComponent->CreateDescriptor()); + + ASSERT_TRUE(m_layerSpawnerComponent); + ASSERT_TRUE(m_shapeComponent); + } + + void ResetEntity() + { + m_entity->Deactivate(); + m_entity->Reset(); + } + + void CreateMockTerrainSystem() + { + m_terrainSystem = AZStd::make_unique(); + m_terrainSystem->Activate(); + } +}; + +TEST_F(LayerSpawnerComponentTest, ActivatEntityActivateSuccess) +{ + CreateEntity(); + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerDefaultValuesCorrect) +{ + CreateEntity(); + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + + AZ::u32 priority = 999, layer = 999; + Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + + EXPECT_EQ(0, priority); + EXPECT_EQ(1, layer); + + bool useGroundPlane = false; + + Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + + EXPECT_TRUE(useGroundPlane); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) +{ + CreateEntity(); + + constexpr static AZ::u32 testPriority = 15; + constexpr static AZ::u32 testLayer = 0; + + Terrain::TerrainLayerSpawnerConfig config; + config.m_layer = testLayer; + config.m_priority = testPriority; + config.m_useGroundPlane = false; + + AddLayerSpawnerAndShapeComponentToEntity(config); + + m_entity->Activate(); + + AZ::u32 priority = 999, layer = 999; + Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + + EXPECT_EQ(testPriority, priority); + EXPECT_EQ(testLayer, layer); + + bool useGroundPlane = true; + + Terrain::TerrainSpawnerRequestBus::EventResult( + useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + + EXPECT_FALSE(useGroundPlane); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerRegisterAreaUpdatesTerrainSystem) +{ + CreateEntity(); + + CreateMockTerrainSystem(); + + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + + // The Activate call should have registered the area. + EXPECT_EQ(1, m_terrainSystem->m_registerAreaCalledCount); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerUnregisterAreaUpdatesTerrainSystem) +{ + CreateEntity(); + + CreateMockTerrainSystem(); + + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + + m_layerSpawnerComponent->Deactivate(); + + // The Deactivate call should have unregistered the area. + EXPECT_EQ(1, m_terrainSystem->m_unregisterAreaCalledCount); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerTransformChangedUpdatesTerrainSystem) +{ + CreateEntity(); + + CreateMockTerrainSystem(); + + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + + AZ::TransformNotificationBus::Event( + m_entity->GetId(), &AZ::TransformNotificationBus::Events::OnTransformChanged, AZ::Transform(), AZ::Transform()); + + EXPECT_EQ(1, m_terrainSystem->m_refreshAreaCalledCount); + + ResetEntity(); +} + +TEST_F(LayerSpawnerComponentTest, LayerSpawnerShapeChangedUpdatesTerrainSystem) +{ + CreateEntity(); + + CreateMockTerrainSystem(); + + AddLayerSpawnerAndShapeComponentToEntity(); + + m_entity->Activate(); + + LmbrCentral::ShapeComponentNotificationsBus::Event( + m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, + LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged); + + EXPECT_EQ(1, m_terrainSystem->m_refreshAreaCalledCount); + + ResetEntity(); +} diff --git a/Gems/Terrain/Code/Tests/TerrainMocks.h b/Gems/Terrain/Code/Tests/TerrainMocks.h new file mode 100644 index 0000000000..5f90cafd69 --- /dev/null +++ b/Gems/Terrain/Code/Tests/TerrainMocks.h @@ -0,0 +1,104 @@ +/* + * 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 + * + */ +#pragma once + +#include +#include + +namespace UnitTest +{ + static const AZ::Uuid BoxShapeComponentTypeId = "{5EDF4B9E-0D3D-40B8-8C91-5142BCFC30A6}"; + + class MockBoxShapeComponent + : public AZ::Component + { + public: + AZ_COMPONENT(MockBoxShapeComponent, BoxShapeComponentTypeId) + static void Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + } + + void Activate() override + { + } + + void Deactivate() override + { + } + + bool ReadInConfig([[maybe_unused]] const AZ::ComponentConfig* baseConfig) override + { + return true; + } + + bool WriteOutConfig([[maybe_unused]] AZ::ComponentConfig* outBaseConfig) const override + { + return true; + } + + private: + static void GetProvidedServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC("ShapeService", 0xe86aa5fe)); + provided.push_back(AZ_CRC("BoxShapeService", 0x946a0032)); + } + + static void GetIncompatibleServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + } + + static void GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + } + + static void GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + }; + + class MockTerrainSystem : private Terrain::TerrainSystemServiceRequestBus::Handler + { + public: + void Activate() override + { + Terrain::TerrainSystemServiceRequestBus::Handler::BusConnect(); + } + + void Deactivate() override + { + Terrain::TerrainSystemServiceRequestBus::Handler::BusDisconnect(); + } + + void SetWorldBounds(const AZ::Aabb& worldBounds) override + { + } + + void SetHeightQueryResolution([[maybe_unused]] AZ::Vector2 queryResolution) override + { + } + + void RegisterArea([[maybe_unused]] AZ::EntityId areaId) override + { + m_registerAreaCalledCount++; + } + + void UnregisterArea([[maybe_unused]] AZ::EntityId areaId) override + { + m_unregisterAreaCalledCount++; + } + + void RefreshArea([[maybe_unused]] AZ::EntityId areaId) override + { + m_refreshAreaCalledCount++; + } + + int m_registerAreaCalledCount = 0; + int m_refreshAreaCalledCount = 0; + int m_unregisterAreaCalledCount = 0; + }; +} diff --git a/Gems/Terrain/Code/terrain_tests_files.cmake b/Gems/Terrain/Code/terrain_tests_files.cmake index beed6bd83d..b44f143f3b 100644 --- a/Gems/Terrain/Code/terrain_tests_files.cmake +++ b/Gems/Terrain/Code/terrain_tests_files.cmake @@ -7,5 +7,7 @@ # set(FILES + Tests/TerrainMocks.h Tests/TerrainTest.cpp + Tests/LayerSpawnerTests.cpp ) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index fe03f2e7c9..f22de7e4c8 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -11,7 +11,6 @@ ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev1-android TARGETS lz4 PACKAGE_HASH da8ec7736640a3e9834f6db1c69e8a0ea61c054fe8b6324509f36928cfc21dc9) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) @@ -28,3 +27,5 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS Goo ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) +ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-android TARGETS lz4 PACKAGE_HASH f5b22642d218dbbb442cae61e469e5b241c4740acd258c3e8678e60dec61ea93) + diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 1e0de4f2ed..c9315336b9 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -15,7 +15,6 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev1-linux TARGETS lz4 PACKAGE_HASH 2e2653ce04a036c38fe28f3971bc3bfb8a4e771335aa8d1b95b0feb3423f1b0a) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) @@ -28,7 +27,7 @@ ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-linux TARGETS freetype PACKAGE_HASH 9ad246873067717962c6b780d28a5ce3cef3321b73c9aea746a039c798f52e93) ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-linux TARGETS tiff PACKAGE_HASH ae92b4d3b189c42ef644abc5cac865d1fb2eb7cb5622ec17e35642b00d1a0a76) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev5-linux TARGETS AWSNativeSDK PACKAGE_HASH 0101a4052d9fce83a6f5515e00f366e97b308ecb8261ad23a6e4eb4365212ab6) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-linux TARGETS AWSNativeSDK PACKAGE_HASH 490291e4c8057975c3ab86feb971b8a38871c58bac5e5d86abdd1aeb7141eec4) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-linux TARGETS Lua PACKAGE_HASH 1adc812abe3dd0dbb2ca9756f81d8f0e0ba45779ac85bf1d8455b25c531a38b0) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-linux TARGETS PhysX PACKAGE_HASH a110249cbef4f266b0002c4ee9a71f59f373040cefbe6b82f1e1510c811edde6) ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-linux TARGETS etc2comp PACKAGE_HASH 9283aa5db5bb7fb90a0ddb7a9f3895317c8ebe8044943124bbb3673a41407430) @@ -46,5 +45,4 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev2-linux ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-linux TARGETS zlib PACKAGE_HASH 16f3b9e11cda525efb62144f354c1cfc30a5def9eff020dbe49cb00ee7d8234f) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-linux TARGETS squish-ccr PACKAGE_HASH 85fecafbddc6a41a27c5f59ed4a5dfb123a94cb4666782cf26e63c0a4724c530) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-linux TARGETS ISPCTexComp PACKAGE_HASH 065fd12abe4247dde247330313763cf816c3375c221da030bdec35024947f259) - - +ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-linux TARGETS lz4 PACKAGE_HASH 5de3dbd3e2a3537c6555d759b3c5bb98e5456cf85c74ff6d046f809b7087290d) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 58c6849657..4d62f6a7bf 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -15,7 +15,6 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev1-mac TARGETS lz4 PACKAGE_HASH 3ce6866b43d024452c0412f385ae46aba0e1ae99eb64f7099d3fc539c8460881) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) @@ -30,7 +29,7 @@ ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-ma ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-mac TARGETS SPIRVCross PACKAGE_HASH 78c6376ed2fd195b9b1f5fb2b56e5267a32c3aa21fb399e905308de470eb4515) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-mac-ios TARGETS freetype PACKAGE_HASH 67b4f57aed92082d3fd7c16aa244a7d908d90122c296b0a63f73e0a0b8761977) ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-mac-ios TARGETS tiff PACKAGE_HASH a23ae1f8991a29f8e5df09d6d5b00d7768a740f90752cef465558c1768343709) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-mac TARGETS AWSNativeSDK PACKAGE_HASH 89e1651cde6b4e6bd80cdb96ed6b624accad9f9688ff38bfca226777f4fcb678) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev5-mac TARGETS AWSNativeSDK PACKAGE_HASH ffb890bd9cf23afb429b9214ad9bac1bf04696f07a0ebb93c42058c482ab2f01) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev6-mac TARGETS Lua PACKAGE_HASH b9079fd35634774c9269028447562c6b712dbc83b9c64975c095fd423ff04c08) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-mac TARGETS PhysX PACKAGE_HASH 5e092a11d5c0a50c4dd99bb681a04b566a4f6f29aa08443d9bffc8dc12c27c8e) ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-mac TARGETS etc2comp PACKAGE_HASH 1966ab101c89db7ecf30984917e0a48c0d02ee0e4d65b798743842b9469c0818) @@ -44,4 +43,5 @@ ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-mac TARGETS zlib PACKAGE_HASH 21714e8a6de4f2523ee92a7f52d51fbee29c5f37ced334e00dc3c029115b472e) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) +ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-mac TARGETS lz4 PACKAGE_HASH 891ff630bf34f7ab1d8eaee2ea0a8f1fca89dbdc63fca41ee592703dd488a73b) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 17792675d3..64cbfa05dd 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -15,7 +15,6 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev1-windows TARGETS lz4 PACKAGE_HASH 02e6ba2ca1407483bac082fd97803c5e19f48bc576171bfc8cec62412efe639c) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) @@ -31,7 +30,7 @@ ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-wi ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-windows TARGETS freetype PACKAGE_HASH 88dedc86ccb8c92f14c2c033e51ee7d828fa08eafd6475c6aa963938a99f4bf3) ly_associate_package(PACKAGE_NAME tiff-4.2.0.14-windows TARGETS tiff PACKAGE_HASH ab60d1398e4e1e375ec0f1a00cdb1d812a07c0096d827db575ce52dd6d714207) -ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev3-windows TARGETS AWSNativeSDK PACKAGE_HASH 929873d4252c464620a9d288e41bd5d47c0bd22750aeb3a1caa68a3da8247c48) +ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-windows TARGETS AWSNativeSDK PACKAGE_HASH a900e80f7259e43aed5c847afee2599ada37f29db70505481397675bcbb6c76c) ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-windows TARGETS Lua PACKAGE_HASH 136faccf1f73891e3fa3b95f908523187792e56f5b92c63c6a6d7e72d1158d40) ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-windows TARGETS PhysX PACKAGE_HASH 0c5ffbd9fa588e5cf7643721a7cfe74d0fe448bf82252d39b3a96d06dfca2298) ly_associate_package(PACKAGE_NAME etc2comp-9cd0f9cae0-rev1-windows TARGETS etc2comp PACKAGE_HASH fc9ae937b2ec0d42d5e7d0e9e8c80e5e4d257673fb33bc9b7d6db76002117123) @@ -51,3 +50,4 @@ ly_associate_package(PACKAGE_NAME Crashpad-0.8.0-rev1-windows ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-windows TARGETS zlib PACKAGE_HASH 9afab1d67641ed8bef2fb38fc53942da47f2ab339d9e77d3d20704a48af2da0b) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-windows TARGETS squish-ccr PACKAGE_HASH 5c3d9fa491e488ccaf802304ad23b932268a2b2846e383f088779962af2bfa84) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-windows TARGETS ISPCTexComp PACKAGE_HASH b6fa6ea28a2808a9a5524c72c37789c525925e435770f2d94eb2d387360fa2d0) +ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-windows TARGETS lz4 PACKAGE_HASH 4ea457b833cd8cfaf8e8e06ed6df601d3e6783b606bdbc44a677f77e19e0db16) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index f98f2009f2..69576bb665 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -11,7 +11,6 @@ ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev1-ios TARGETS lz4 PACKAGE_HASH 7a9391daf53e47e529cf811dca3554c83769f62a2ee52488610ec73214961ae1) ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) @@ -29,3 +28,4 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleB ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-ios TARGETS zlib PACKAGE_HASH a59fc0f83a02c616b679799310e9d86fde84514c6d2acefa12c6def0ae4a880c) +ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-ios TARGETS lz4 PACKAGE_HASH 588ea05739caa9231a9a17a1e8cf64c5b9a265e16528bc05420af7e2534e86c1) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 328e5f8df7..5bc4b919fb 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -415,6 +415,19 @@ def ExportTestResults(Map options, String platform, String type, String workspac } } +def ExportTestScreenshots(Map options, String workspace, String platformName, String jobName, Map params) { + catchError(message: "Error exporting test screenshots (this won't fail the build)", buildResult: 'SUCCESS', stageResult: 'FAILURE') { + def screenshotsFolder = '${workspace}/${ENGINE_REPOSITORY_NAME}/AutomatedTesting/user/PythonTests/Automated/Screenshots' + def s3Uploader = '${workspace}/${ENGINE_REPOSITORY_NAME}/scripts/build/tools/upload_to_s3.py' + def command = '${options.PYTHON_DIR}/python.cmd -u ${s3Uploader} --base_dir ${screenshotsFolder} ' + + '--file_regex "(.*zip$)" --bucket ${env.TEST_SCREENSHOT_BUCKET} ' + + '--search_subdirectories True --key_prefix ${branchName}_${env.BUILD_NUMBER}' + + '--extra-args {"ACL": "bucket-owner-full-control"}' + bat label: "Uploading test screenshots for ${jobName}", + script: command + } +} + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -470,6 +483,14 @@ def CreateExportTestResultsStage(Map pipelineConfig, String platformName, String } } +def CreateExportTestScreenshotsStage(Map pipelineConfig, String platformName, String jobName, Map environmentVars, Map params) { + return { + stage("${jobName}_screenshots") { + ExportTestScreenshots(pipelineConfig, platformName, jobName, environmentVars['WORKSPACE'], params) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage('Teardown') { @@ -532,6 +553,9 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar if (params && params.containsKey('TEST_RESULTS') && params.TEST_RESULTS == 'True') { CreateExportTestResultsStage(pipelineConfig, platform.key, build_job_name, envVars, params).call() } + if (params && params.containsKey('TEST_SCREENSHOTS') && params.TEST_SCREENSHOTS == 'True' && currentResult == 'FAILURE') { + CreateExportTestScreenshotsStage(pipelineConfig, platform.key, build_job_name, envVars, params).call() + } CreateTeardownStage(envVars).call() } }