diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py index a543527ed7..ff362c732c 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py @@ -342,7 +342,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> # Run a full scan to ENSURE that both caches (pc and osx) are COMPLETELY POPULATED # Needed for asset bundling # fmt:off - assert asset_processor.batch_process(fastscan=False, timeout=timeout * len(platforms), platforms=platforms_list), \ + assert asset_processor.batch_process(fastscan=True, timeout=timeout * len(platforms), platforms=platforms_list), \ "AP Batch failed to process in bundler_batch_fixture" # fmt:on diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt index 3d7a9204e2..5a5809595e 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/CMakeLists.txt @@ -92,25 +92,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetProcessor ) - # Issue #3017 - #ly_add_pytest( - # NAME AssetPipelineTests.AssetBundler - # PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py - # EXCLUDE_TEST_RUN_TARGET_FROM_IDE - # TEST_SERIAL - # TEST_SUITE periodic - # RUNTIME_DEPENDENCIES - # AZ::AssetProcessor - # AZ::AssetBundlerBatch - #) - ly_add_pytest( - NAME AssetPipelineTests.AssetBundler_SandBox - TEST_SUITE sandbox + NAME AssetPipelineTests.AssetBundler PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py - PYTEST_MARKS "SUITE_sandbox" # run only sandbox tests in this file EXCLUDE_TEST_RUN_TARGET_FROM_IDE TEST_SERIAL + TEST_SUITE periodic RUNTIME_DEPENDENCIES AZ::AssetProcessor AZ::AssetBundlerBatch diff --git a/AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override b/AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override index a329434623..aa82265c98 100644 --- a/AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override +++ b/AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override b/AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override index 44a91c67cb..7050a57206 100644 --- a/AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override +++ b/AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override b/AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override index 8de10787f1..c78018bdbb 100644 --- a/AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override +++ b/AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override index e4ea71f652..b82acaf0ae 100644 --- a/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override +++ b/AutomatedTesting/Registry/C3510644_Collider_CollisionGroups.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override b/AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override index 83f7079e1f..806d71a158 100644 --- a/AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override +++ b/AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override b/AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override index 96836b6ae4..fa77daac9f 100644 --- a/AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override +++ b/AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override index 88a7b5c309..5deb5635d1 100644 --- a/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override +++ b/AutomatedTesting/Registry/C4044459_Material_DynamicFriction.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override b/AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override index 21b285506b..b70e0f1326 100644 --- a/AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override +++ b/AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override b/AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override index d585a4c468..5a93ae2314 100644 --- a/AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override +++ b/AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override index e53d3893f8..7065f0dfeb 100644 --- a/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override +++ b/AutomatedTesting/Registry/C4976227_Collider_NewGroup.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override index e4ea71f652..b82acaf0ae 100644 --- a/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override +++ b/AutomatedTesting/Registry/C4976244_Collider_SameGroupSameLayerCollision.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override index e4ea71f652..b82acaf0ae 100644 --- a/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override +++ b/AutomatedTesting/Registry/C4976245_PhysXCollider_CollisionLayerTest.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override index e4ea71f652..b82acaf0ae 100644 --- a/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override +++ b/AutomatedTesting/Registry/C4982593_PhysXCollider_CollisionLayer.setreg_override @@ -69,7 +69,7 @@ {}, {}, {}, - "TouchBend" + {} ] }, "Groups": { diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index 6fcf3faffd..28bc6fe3b3 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -19,6 +19,66 @@ namespace UnitTest using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; + class ViewportMouseCursorRequestImpl : public AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler + { + public: + void Connect(const AzFramework::ViewportId viewportId, AzToolsFramework::QtEventToAzInputMapper* inputChannelMapper) + { + AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusConnect(viewportId); + m_inputChannelMapper = inputChannelMapper; + } + + void Disconnect() + { + AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler::BusDisconnect(); + } + + // ViewportMouseCursorRequestBus overrides ... + void BeginCursorCapture() override; + void EndCursorCapture() override; + bool IsMouseOver() const override; + + private: + AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr; + }; + + void ViewportMouseCursorRequestImpl::BeginCursorCapture() + { + m_inputChannelMapper->SetCursorCaptureEnabled(true); + } + + void ViewportMouseCursorRequestImpl::EndCursorCapture() + { + m_inputChannelMapper->SetCursorCaptureEnabled(false); + } + + bool ViewportMouseCursorRequestImpl::IsMouseOver() const + { + return true; + } + + class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext + { + public: + AZ::Transform GetCameraTransform() const override + { + return m_cameraTransform; + } + + void SetCameraTransform(const AZ::Transform& transform) override + { + m_cameraTransform = transform; + } + + void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override + { + // noop + } + + private: + AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity(); + }; + class ModularViewportCameraControllerFixture : public AllocatorsTestFixture { public: @@ -48,123 +108,159 @@ namespace UnitTest AllocatorsTestFixture::TearDown(); } + void PrepareCollaborators() + { + AzFramework::NativeWindowHandle nativeWindowHandle = nullptr; + + // listen for events signaled from QtEventToAzInputMapper and forward to the controller list + QObject::connect( + m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), + [this, nativeWindowHandle](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event) + { + m_controllerList->HandleInputChannelEvent( + AzFramework::ViewportControllerInputEvent{ TestViewportId, nativeWindowHandle, *inputChannel }); + }); + + m_mockWindowRequests.Connect(nativeWindowHandle); + + using ::testing::Return; + // note: WindowRequests is used internally by ModularViewportCameraController, this ensures it returns the viewport size we want + ON_CALL(m_mockWindowRequests, GetClientAreaSize()) + .WillByDefault(Return(AzFramework::WindowSize(WidgetSize.width(), WidgetSize.height()))); + + // respond to begin/end cursor capture events + m_viewportMouseCursorRequests.Connect(TestViewportId, m_inputChannelMapper.get()); + + // create editor modular camera + auto controller = CreateModularViewportCameraController(TestViewportId); + + // set some overrides for the test + controller->SetCameraViewportContextBuilderCallback( + [this](AZStd::unique_ptr& cameraViewportContext) + { + cameraViewportContext = AZStd::make_unique(); + m_cameraViewportContextView = cameraViewportContext.get(); + }); + + // disable smoothing in the test + controller->SetCameraPropsBuilderCallback( + [](AzFramework::CameraProps& cameraProps) + { + cameraProps.m_rotateSmoothingEnabledFn = [] + { + return false; + }; + + cameraProps.m_translateSmoothingEnabledFn = [] + { + return false; + }; + }); + + m_controllerList->Add(controller); + } + + void HaltCollaborators() + { + m_mockWindowRequests.Disconnect(); + m_viewportMouseCursorRequests.Disconnect(); + m_cameraViewportContextView = nullptr; + } + + void RepeatDiagonalMouseMovements(const AZStd::function& deltaTimeFn) + { + // move to the center of the screen + auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2); + MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + + // move mouse diagonally to top right, then to bottom left and back repeatedly + auto current = start; + auto halfDelta = QPoint(200, -200); + const int iterationsPerDiagonal = 50; + for (int diagonals = 0; diagonals < 80; ++diagonals) + { + for (int i = 0; i < iterationsPerDiagonal; ++i) + { + MousePressAndMove(m_rootWidget.get(), current, halfDelta / iterationsPerDiagonal, Qt::MouseButton::RightButton); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + current += halfDelta / iterationsPerDiagonal; + } + + if (diagonals % 2 == 0) + { + halfDelta.setX(halfDelta.x() * -1); + halfDelta.setY(halfDelta.y() * -1); + } + } + + QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::KeyboardModifier::NoModifier, current); + m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() }); + } + AZStd::unique_ptr m_rootWidget; AzFramework::ViewportControllerListPtr m_controllerList; AZStd::unique_ptr m_inputChannelMapper; + ::testing::NiceMock m_mockWindowRequests; + ViewportMouseCursorRequestImpl m_viewportMouseCursorRequests; + AtomToolsFramework::ModularCameraViewportContext* m_cameraViewportContextView = nullptr; }; const AzFramework::ViewportId ModularViewportCameraControllerFixture::TestViewportId = AzFramework::ViewportId(0); - class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext + TEST_F(ModularViewportCameraControllerFixture, MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithVaryingDeltaTime) { - public: - AZ::Transform GetCameraTransform() const override - { - return m_cameraTransform; - } - - void SetCameraTransform(const AZ::Transform& transform) override - { - m_cameraTransform = transform; - } - - void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override - { - // noop - } - - private: - AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity(); - }; - - TEST_F(ModularViewportCameraControllerFixture, Mouse_movement_does_not_accumulate_excessive_drift_in_modular_viewport_camera) - { - AzFramework::NativeWindowHandle nativeWindowHandle = nullptr; - - const float deltaTime = 1.0f / 60.0f; // mimic 60fps - // Given - // listen for events signaled from QtEventToAzInputMapper and forward to the controller list - QObject::connect( - m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), - [this, nativeWindowHandle](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event) - { - m_controllerList->HandleInputChannelEvent( - AzFramework::ViewportControllerInputEvent{ TestViewportId, nativeWindowHandle, *inputChannel }); - }); - - using ::testing::NiceMock; - using ::testing::Return; - - NiceMock mockWindowRequests; - mockWindowRequests.Connect(nativeWindowHandle); - - // note: WindowRequests is used internally by ModularViewportCameraController, this ensures it returns the viewport size we want - ON_CALL(mockWindowRequests, GetClientAreaSize()) - .WillByDefault(Return(AzFramework::WindowSize(WidgetSize.width(), WidgetSize.height()))); - - // create editor modular camera - auto controller = CreateModularViewportCameraController(TestViewportId); - - // set some overrides for the test - AtomToolsFramework::ModularCameraViewportContext* cameraViewportContextView = nullptr; - controller->SetCameraViewportContextBuilderCallback( - [&cameraViewportContextView](AZStd::unique_ptr& cameraViewportContext) - { - cameraViewportContext = AZStd::make_unique(); - cameraViewportContextView = cameraViewportContext.get(); - }); - - controller->SetCameraPropsBuilderCallback( - [](AzFramework::CameraProps& cameraProps) - { - cameraProps.m_rotateSmoothingEnabledFn = [] - { - return false; - }; - - cameraProps.m_translateSmoothingEnabledFn = [] - { - return false; - }; - }); - - m_controllerList->Add(controller); - - // move to the center of the screen - auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2); - MouseMove(m_rootWidget.get(), start, QPoint(0, 0)); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + PrepareCollaborators(); // When - // move mouse diagonally to top right, then to bottom left and back repeatedly - auto current = start; - auto halfDelta = QPoint(200, -200); - const int iterationsPerDiagonal = 50; - for (int diagonals = 0; diagonals < 80; ++diagonals) - { - for (int i = 0; i < iterationsPerDiagonal; ++i) + RepeatDiagonalMouseMovements( + [t = 0.0f]() mutable { - MousePressAndMove(m_rootWidget.get(), current, halfDelta / iterationsPerDiagonal, Qt::MouseButton::RightButton); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); - current += halfDelta / iterationsPerDiagonal; - } - - if (diagonals % 2 == 0) - { - halfDelta.setX(halfDelta.x() * -1); - halfDelta.setY(halfDelta.y() * -1); - } - } - - QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::KeyboardModifier::NoModifier, current); - m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() }); + // vary between 30 and 50 fps (40 +/- 10) + const float fps = 40.0f + (10.0f * AZStd::sin(t)); + t += AZ::DegToRad(5.0f); + return 1.0f / fps; + }); // Then // ensure the camera rotation is the identity (no significant drift has occurred as we moved the mouse) - const AZ::Transform cameraRotation = cameraViewportContextView->GetCameraTransform(); + const AZ::Transform cameraRotation = m_cameraViewportContextView->GetCameraTransform(); EXPECT_THAT(cameraRotation.GetRotation(), IsClose(AZ::Quaternion::CreateIdentity())); - mockWindowRequests.Disconnect(); + // Clean-up + HaltCollaborators(); } + + class ModularViewportCameraControllerDeltaTimeParamFixture + : public ModularViewportCameraControllerFixture + , public ::testing::WithParamInterface // delta time + { + }; + + TEST_P( + ModularViewportCameraControllerDeltaTimeParamFixture, + MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithFixedDeltaTime) + { + // Given + PrepareCollaborators(); + + // When + RepeatDiagonalMouseMovements( + [this] + { + return GetParam(); + }); + + // Then + // ensure the camera rotation is the identity (no significant drift has occurred as we moved the mouse) + const AZ::Transform cameraRotation = m_cameraViewportContextView->GetCameraTransform(); + EXPECT_THAT(cameraRotation.GetRotation(), IsClose(AZ::Quaternion::CreateIdentity())); + + // Clean-up + HaltCollaborators(); + } + + INSTANTIATE_TEST_CASE_P( + All, ModularViewportCameraControllerDeltaTimeParamFixture, testing::Values(1.0f / 60.0f, 1.0f / 50.0f, 1.0f / 30.0f)); } // namespace UnitTest diff --git a/Code/Framework/AzFramework/AzFramework/Input/Events/InputChannelEventListener.h b/Code/Framework/AzFramework/AzFramework/Input/Events/InputChannelEventListener.h index 2b45012fa3..00bdf30f0e 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Events/InputChannelEventListener.h +++ b/Code/Framework/AzFramework/AzFramework/Input/Events/InputChannelEventListener.h @@ -35,6 +35,7 @@ namespace AzFramework //! Predefined input event listener priority, used to sort handlers from highest to lowest inline static AZ::s32 GetPriorityFirst() { return std::numeric_limits::max(); } inline static AZ::s32 GetPriorityDebug() { return (GetPriorityFirst() / 4) * 3; } + inline static AZ::s32 GetPriorityDebugUI() { return (GetPriorityFirst() / 8) * 5; } inline static AZ::s32 GetPriorityUI() { return GetPriorityFirst() / 2; } inline static AZ::s32 GetPriorityDefault() { return 0; } inline static AZ::s32 GetPriorityLast() { return std::numeric_limits::min(); } diff --git a/Code/Framework/AzFramework/AzFramework/Input/Events/InputTextEventListener.h b/Code/Framework/AzFramework/AzFramework/Input/Events/InputTextEventListener.h index 32c44f83d4..4629a5a5c0 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Events/InputTextEventListener.h +++ b/Code/Framework/AzFramework/AzFramework/Input/Events/InputTextEventListener.h @@ -28,6 +28,7 @@ namespace AzFramework //! Predefined text event listener priority, used to sort handlers from highest to lowest inline static AZ::s32 GetPriorityFirst() { return std::numeric_limits::max(); } inline static AZ::s32 GetPriorityDebug() { return (GetPriorityFirst() / 4) * 3; } + inline static AZ::s32 GetPriorityDebugUI() { return (GetPriorityFirst() / 8) * 5; } inline static AZ::s32 GetPriorityUI() { return GetPriorityFirst() / 2; } inline static AZ::s32 GetPriorityDefault() { return 0; } inline static AZ::s32 GetPriorityLast() { return std::numeric_limits::min(); } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp index 3ffeb0cf5b..84e0184462 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionGroups.cpp @@ -13,14 +13,6 @@ #include -//This bit is defined in the TouchBending Gem wscript. -//Make sure the bit has a valid value. -#ifdef TOUCHBENDING_LAYER_BIT -#if (TOUCHBENDING_LAYER_BIT < 1) || (TOUCHBENDING_LAYER_BIT > 63) -#error Invalid Bit Definition For the TouchBending Layer Bit -#endif -#endif //#ifdef TOUCHBENDING_LAYER_BIT - namespace AzPhysics { AZ_CLASS_ALLOCATOR_IMPL(CollisionGroup, AZ::SystemAllocator, 0); @@ -31,10 +23,6 @@ namespace AzPhysics const CollisionGroup CollisionGroup::None = 0x0000000000000000ULL; const CollisionGroup CollisionGroup::All = 0xFFFFFFFFFFFFFFFFULL; -#ifdef TOUCHBENDING_LAYER_BIT - const CollisionGroup CollisionGroup::All_NoTouchBend = CollisionGroup::All.GetMask() & ~CollisionLayer::TouchBend.GetMask(); -#endif - void CollisionGroupScriptConstructor(CollisionGroup* thisPtr, AZ::ScriptDataContext& scriptDataContext) { if (int numArgs = scriptDataContext.GetNumArguments(); diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionLayers.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionLayers.cpp index 924af41113..42ea38961f 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionLayers.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Collision/CollisionLayers.cpp @@ -14,14 +14,6 @@ #include -//This bit is defined in the TouchBending Gem wscript. -//Make sure the bit has a valid value. -#ifdef TOUCHBENDING_LAYER_BIT -#if (TOUCHBENDING_LAYER_BIT < 1) || (TOUCHBENDING_LAYER_BIT > 63) -#error Invalid Bit Definition For the TouchBending Layer Bit -#endif -#endif //#ifdef TOUCHBENDING_LAYER_BIT - namespace AzPhysics { AZ_CLASS_ALLOCATOR_IMPL(CollisionLayer, AZ::SystemAllocator, 0); @@ -29,10 +21,6 @@ namespace AzPhysics const CollisionLayer CollisionLayer::Default = 0; -#ifdef TOUCHBENDING_LAYER_BIT - const CollisionLayer CollisionLayer::TouchBend = TOUCHBENDING_LAYER_BIT; -#endif - void CollisionLayer::Reflect(AZ::ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/StaticRigidBody.h b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/StaticRigidBody.h index 2cd3b9f7ae..8f84609379 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/StaticRigidBody.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/StaticRigidBody.h @@ -32,12 +32,20 @@ namespace AzPhysics { public: AZ_CLASS_ALLOCATOR_DECL; - AZ_RTTI(StaticRigidBody, "{13A677BB-7085-4EDB-BCC8-306548238692}", SimulatedBody); + AZ_RTTI(AzPhysics::StaticRigidBody, "{13A677BB-7085-4EDB-BCC8-306548238692}", AzPhysics::SimulatedBody); static void Reflect(AZ::ReflectContext* context); - //Legacy API - may change with LYN-438 + //! Add a shape to the static rigid body. + //! @param shape A shared pointer of the shape to add. virtual void AddShape(const AZStd::shared_ptr& shape) = 0; + + //! Returns the number of shapes that make up this static rigid body. + //! @return Returns the number of shapes as a AZ::u32. virtual AZ::u32 GetShapeCount() { return 0; } + + //! Returns a shared pointer to the requested shape index. + //! @param index The index of the shapes to return. Expected to be between 0 and GetShapeCount(). + //! @return Returns a shared pointer of the shape requested or nullptr if index is out of bounds. virtual AZStd::shared_ptr GetShape([[maybe_unused]]AZ::u32 index) { return nullptr; } }; } diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 74adcd9543..72984f8111 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -802,7 +802,6 @@ namespace AzFramework { return VerticalMotionEvent{ aznumeric_cast(inputChannel.GetValue()) }; } - else if (inputChannelId == InputDeviceMouse::Movement::Z) { return ScrollEvent{ inputChannel.GetValue() }; diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt index 1ac60e299e..1164d81f04 100644 --- a/Code/Framework/AzFramework/CMakeLists.txt +++ b/Code/Framework/AzFramework/CMakeLists.txt @@ -10,8 +10,6 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) -set(LY_TOUCHBENDING_LAYER_BIT 63 CACHE STRING "Use TouchBending as the collision layer. The TouchBending layer can be a number from 1 to 63 (Default=63).") - ly_add_target( NAME AzFramework STATIC NAMESPACE AZ @@ -37,14 +35,6 @@ ly_add_target( 3rdParty::lz4 ) -ly_add_source_properties( - SOURCES - AzFramework/Physics/Collision/CollisionGroups.cpp - AzFramework/Physics/Collision/CollisionLayers.cpp - PROPERTY COMPILE_DEFINITIONS - VALUES TOUCHBENDING_LAYER_BIT=${LY_TOUCHBENDING_LAYER_BIT} -) - if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME}) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 043f864245..54e7f7608c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -650,7 +650,10 @@ namespace AzToolsFramework AZStd::unique_ptr Instance::DetachContainerEntity() { - m_instanceEntityMapper->UnregisterEntity(m_containerEntity->GetId()); + if (m_containerEntity) + { + m_instanceEntityMapper->UnregisterEntity(m_containerEntity->GetId()); + } return AZStd::move(m_containerEntity); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp index c455873036..7b7107ae3e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp @@ -65,16 +65,24 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities(); for (auto it = entities.begin(); it != entities.end(); ) { - (*it)->InvalidateDependencies(); - AZ::Entity::DependencySortOutcome evaluation = (*it)->EvaluateDependenciesGetDetails(); - if (evaluation.IsSuccess()) + if (*it) { - ++it; + (*it)->InvalidateDependencies(); + AZ::Entity::DependencySortOutcome evaluation = (*it)->EvaluateDependenciesGetDetails(); + if (evaluation.IsSuccess()) + { + ++it; + } + else + { + AZ_Error( + "Prefabs", false, "Entity '%s' %s cannot be activated for the following reason: %s", (*it)->GetName().c_str(), + (*it)->GetId().ToString().c_str(), evaluation.GetError().m_message.c_str()); + it = entities.erase(it); + } } else { - AZ_Error("Prefabs", false, "Entity '%s' %s cannot be activated for the following reason: %s", - (*it)->GetName().c_str(), (*it)->GetId().ToString().c_str(), evaluation.GetError().m_message.c_str()); it = entities.erase(it); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 543d5fb3a5..f6ba87a0ec 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -275,9 +275,7 @@ namespace AzToolsFramework virtual void BeginCursorCapture() = 0; //! Restores the cursor and ends locking it in place, allowing it to be moved freely. virtual void EndCursorCapture() = 0; - //! Gets the most recent recorded cursor position in the viewport in screen space coordinates. - virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0; - //! Is mouse over viewport. + //! Is the mouse over the viewport. virtual bool IsMouseOver() const = 0; protected: diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 74acc1c7ef..1bd261da00 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -20,8 +20,7 @@ QPushButton:focus { QTabBar { background-color: transparent; } -QTabWidget::tab-bar -{ +QTabWidget::tab-bar { left: 78px; /* make room for the logo */ } QTabBar::tab { @@ -32,27 +31,35 @@ QTabBar::tab { margin-right:40px; border-bottom: 3px solid transparent; } -QTabBar::tab:text -{ +QTabBar::tab:text { text-align:left; } QTabWidget::pane { background-color: #333333; border:0 none; } -QTabBar::tab:selected -{ +QTabBar::tab:selected { + background-color: transparent; border-bottom: 3px solid #1e70eb; color: #1e70eb; + font-weight: 500; } -QTabBar::tab:hover -{ +QTabBar::tab:hover { color: #1e70eb; + font-weight: 500; } -QTabBar::tab:pressed -{ +QTabBar::tab:pressed { color: #0e60eb; } +QTabBar::focus { + outline: 0px; + outline: none; + outline-style: none; +} +QTabBar::tab:focus { + background-color: #525252; + color: #4082eb; +} /************** General (Forms) **************/ diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index ac8cf5d794..909cd93cda 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -117,7 +117,7 @@ namespace O3DE::ProjectManager gemNames.reserve(gems.size()); for (const QModelIndex& modelIndex : gems) { - gemNames.push_back(GemModel::GetName(modelIndex)); + gemNames.push_back(GemModel::GetDisplayName(modelIndex)); } return gemNames; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 863f611ec8..04d4d6999b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -156,7 +156,7 @@ namespace O3DE::ProjectManager if (!result.IsSuccess()) { QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str())); + QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return false; } @@ -169,7 +169,7 @@ namespace O3DE::ProjectManager if (!result.IsSuccess()) { QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str())); + QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return false; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index 6c1f5f6fec..6dd6c52612 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager m_mainWidget->hide(); } - m_nameLabel->setText(m_model->GetName(modelIndex)); + m_nameLabel->setText(m_model->GetDisplayName(modelIndex)); m_creatorLabel->setText(m_model->GetCreator(modelIndex)); m_summaryLabel->setText(m_model->GetSummary(modelIndex)); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 21bb56daef..99a2cd8db7 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -75,7 +75,7 @@ namespace O3DE::ProjectManager } // Gem name - QString gemName = GemModel::GetName(modelIndex); + QString gemName = GemModel::GetDisplayName(modelIndex); QFont gemNameFont(options.font); const int firstColumnMaxTextWidth = s_summaryStartX - 30; gemNameFont.setPixelSize(static_cast(s_gemNameFontSize)); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 3781106bdc..7daea174e7 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); item->setData(gemInfo.m_name, RoleName); + item->setData(gemInfo.m_displayName, RoleDisplayName); item->setData(gemInfo.m_creator, RoleCreator); item->setData(gemInfo.m_gemOrigin, RoleGemOrigin); item->setData(aznumeric_cast(gemInfo.m_platforms), RolePlatforms); @@ -64,6 +65,20 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleName).toString(); } + QString GemModel::GetDisplayName(const QModelIndex& modelIndex) + { + QString displayName = modelIndex.data(RoleDisplayName).toString(); + + if (displayName.isEmpty()) + { + return GetName(modelIndex); + } + else + { + return displayName; + } + } + QString GemModel::GetCreator(const QModelIndex& modelIndex) { return modelIndex.data(RoleCreator).toString(); @@ -117,7 +132,7 @@ namespace O3DE::ProjectManager QModelIndex modelIndex = FindIndexByNameString(dependingGemString); if (modelIndex.isValid()) { - dependingGemString = GetName(modelIndex); + dependingGemString = GetDisplayName(modelIndex); } } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 19172d8073..ce004ee875 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -37,6 +37,7 @@ namespace O3DE::ProjectManager QStringList GetConflictingGemNames(const QModelIndex& modelIndex); static QString GetName(const QModelIndex& modelIndex); + static QString GetDisplayName(const QModelIndex& modelIndex); static QString GetCreator(const QModelIndex& modelIndex); static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex); static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex); @@ -69,6 +70,7 @@ namespace O3DE::ProjectManager enum UserRole { RoleName = Qt::UserRole, + RoleDisplayName, RoleCreator, RoleGemOrigin, RolePlatforms, diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp index 0d5f752858..0ca5ca836f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp @@ -51,7 +51,7 @@ namespace O3DE::ProjectManager painter->fillRect(itemRect, itemBackgroundColor); // Gem name - QString gemName = GemModel::GetName(modelIndex); + QString gemName = GemModel::GetDisplayName(modelIndex); QFont gemNameFont(options.font); const int firstColumnMaxTextWidth = s_summaryStartX - 30; gemName = QFontMetrics(gemNameFont).elidedText(gemName, Qt::TextElideMode::ElideRight, firstColumnMaxTextWidth); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp index fbcf395910..6edfced6e5 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -28,9 +28,26 @@ namespace O3DE::ProjectManager return false; } - if (!m_sourceModel->GetName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive)) + // Search Bar + if (!m_sourceModel->GetDisplayName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive) && + !m_sourceModel->GetName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive) && + !m_sourceModel->GetCreator(sourceIndex).contains(m_searchString, Qt::CaseInsensitive) && + !m_sourceModel->GetSummary(sourceIndex).contains(m_searchString, Qt::CaseInsensitive)) { - return false; + bool foundFeature = false; + for (const QString& feature : m_sourceModel->GetFeatures(sourceIndex)) + { + if (feature.contains(m_searchString, Qt::CaseInsensitive)) + { + foundFeature = true; + break; + } + } + + if (!foundFeature) + { + return false; + } } // Gem status diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp index 0ff963e539..7981e9d758 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp @@ -52,6 +52,7 @@ namespace O3DE::ProjectManager if (projectButton) { + projectButton->SetProjectBuilding(); projectButton->SetProjectButtonAction(tr("Cancel Build"), [this] { HandleCancel(); }); if (m_lastProgress != 0) @@ -111,6 +112,10 @@ namespace O3DE::ProjectManager emit Done(false); return; } + else + { + m_projectInfo.m_buildFailed = false; + } emit Done(true); } diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index 82b4e8d84a..5bae3b807a 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -162,22 +162,9 @@ namespace O3DE::ProjectManager QDesktopServices::openUrl(m_logUrl); } - ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent, bool processing) + ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent) : QFrame(parent) , m_projectInfo(projectInfo) - { - BaseSetup(); - if (processing) - { - ProcessingSetup(); - } - else - { - ReadySetup(); - } - } - - void ProjectButton::BaseSetup() { setObjectName("projectButton"); @@ -199,50 +186,63 @@ namespace O3DE::ProjectManager } m_projectImageLabel->setPixmap(QPixmap(projectPreviewPath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); - m_projectFooter = new QFrame(this); + QFrame* projectFooter = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setContentsMargins(0, 0, 0, 0); - m_projectFooter->setLayout(hLayout); + projectFooter->setLayout(hLayout); { QLabel* projectNameLabel = new QLabel(m_projectInfo.GetProjectDisplayName(), this); hLayout->addWidget(projectNameLabel); + + QMenu* menu = new QMenu(this); + menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); + menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); }); + menu->addSeparator(); + menu->addAction(tr("Open Project folder..."), this, [this]() + { + AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); + }); + menu->addSeparator(); + menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); }); + menu->addSeparator(); + menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); }); + menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); }); + + m_projectMenuButton = new QPushButton(this); + m_projectMenuButton->setObjectName("projectMenuButton"); + m_projectMenuButton->setMenu(menu); + hLayout->addWidget(m_projectMenuButton); } - vLayout->addWidget(m_projectFooter); + vLayout->addWidget(projectFooter); + + connect(m_projectImageLabel->GetOpenEditorButton(), &QPushButton::clicked, [this](){ emit OpenProject(m_projectInfo.m_path); }); } - void ProjectButton::ProcessingSetup() + const ProjectInfo& ProjectButton::GetProjectInfo() const { - m_projectImageLabel->SetEnabled(false); - m_projectImageLabel->SetOverlayText(tr("Processing...\n\n")); + return m_projectInfo; + } + + void ProjectButton::RestoreDefaultState() + { + m_projectImageLabel->SetEnabled(true); + m_projectImageLabel->SetOverlayText(""); + m_projectMenuButton->setVisible(true); QProgressBar* progressBar = m_projectImageLabel->GetProgressBar(); - progressBar->setVisible(true); + progressBar->setVisible(false); progressBar->setValue(0); - } - void ProjectButton::ReadySetup() - { - connect(m_projectImageLabel->GetOpenEditorButton(), &QPushButton::clicked, [this](){ emit OpenProject(m_projectInfo.m_path); }); + QPushButton* projectActionButton = m_projectImageLabel->GetActionButton(); + projectActionButton->setVisible(false); + if (m_actionButtonConnection) + { + disconnect(m_actionButtonConnection); + } - QMenu* menu = new QMenu(this); - menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); - menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); }); - menu->addSeparator(); - menu->addAction(tr("Open Project folder..."), this, [this]() - { - AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); - }); - menu->addSeparator(); - menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); }); - menu->addSeparator(); - menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); }); - menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); }); - - QPushButton* projectMenuButton = new QPushButton(this); - projectMenuButton->setObjectName("projectMenuButton"); - projectMenuButton->setMenu(menu); - m_projectFooter->layout()->addWidget(projectMenuButton); + m_projectImageLabel->GetWarningIcon()->setVisible(false); + m_projectImageLabel->GetWarningLabel()->setVisible(false); } void ProjectButton::SetProjectButtonAction(const QString& text, AZStd::function lambda) @@ -292,9 +292,15 @@ namespace O3DE::ProjectManager SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); }); } - void ProjectButton::BuildThisProject() + void ProjectButton::SetProjectBuilding() { - emit BuildProject(m_projectInfo); + m_projectImageLabel->SetEnabled(false); + m_projectImageLabel->SetOverlayText(tr("Building...\n\n")); + m_projectMenuButton->setVisible(false); + + QProgressBar* progressBar = m_projectImageLabel->GetProgressBar(); + progressBar->setVisible(true); + progressBar->setValue(0); } void ProjectButton::SetLaunchButtonEnabled(bool enabled) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h index ff352e0afd..9f64b74eab 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h @@ -56,13 +56,14 @@ namespace O3DE::ProjectManager void OnLinkActivated(const QString& link); private: - QVBoxLayout* m_buildOverlayLayout; - QLabel* m_overlayLabel; - QProgressBar* m_progressBar; - QPushButton* m_openEditorButton; - QPushButton* m_actionButton; - QLabel* m_warningText; - QLabel* m_warningIcon; + QVBoxLayout* m_buildOverlayLayout = nullptr; + QLabel* m_overlayLabel = nullptr; + QProgressBar* m_progressBar = nullptr; + QPushButton* m_openEditorButton = nullptr; + QPushButton* m_actionButton = nullptr; + QLabel* m_warningText = nullptr; + QLabel* m_warningIcon = nullptr; + QUrl m_logUrl; bool m_enabled = true; }; @@ -73,13 +74,18 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr, bool processing = false); + explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr); ~ProjectButton() = default; + const ProjectInfo& GetProjectInfo() const; + + void RestoreDefaultState(); + void SetProjectButtonAction(const QString& text, AZStd::function lambda); void SetProjectBuildButtonAction(); void SetBuildLogsLink(const QUrl& logUrl); void ShowBuildFailed(bool show, const QUrl& logUrl); + void SetProjectBuilding(); void SetLaunchButtonEnabled(bool enabled); void SetButtonOverlayText(const QString& text); @@ -95,17 +101,14 @@ namespace O3DE::ProjectManager void BuildProject(const ProjectInfo& projectInfo); private: - void BaseSetup(); - void ProcessingSetup(); - void ReadySetup(); void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; - void BuildThisProject(); ProjectInfo m_projectInfo; - LabelButton* m_projectImageLabel; - QFrame* m_projectFooter; - QLayout* m_requiresBuildLayout; + + LabelButton* m_projectImageLabel = nullptr; + QPushButton* m_projectMenuButton = nullptr; + QLayout* m_requiresBuildLayout = nullptr; QMetaObject::Connection m_actionButtonConnection; }; diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index e27eedd122..27e39926e4 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -68,9 +68,7 @@ namespace O3DE::ProjectManager } ProjectsScreen::~ProjectsScreen() - { - delete m_currentBuilder; } QFrame* ProjectsScreen::CreateFirstTimeContent() @@ -114,10 +112,8 @@ namespace O3DE::ProjectManager return frame; } - QFrame* ProjectsScreen::CreateProjectsContent(QString buildProjectPath, ProjectButton** projectButton) + QFrame* ProjectsScreen::CreateProjectsContent() { - RemoveInvalidProjects(); - QFrame* frame = new QFrame(this); frame->setObjectName("projectsContent"); { @@ -126,7 +122,7 @@ namespace O3DE::ProjectManager layout->setContentsMargins(0, 0, 0, 0); frame->setLayout(layout); - QFrame* header = new QFrame(this); + QFrame* header = new QFrame(frame); QHBoxLayout* headerLayout = new QHBoxLayout(); { QLabel* titleLabel = new QLabel(tr("My Projects"), this); @@ -150,87 +146,34 @@ namespace O3DE::ProjectManager layout->addWidget(header); - // Get all projects and create a horizontal scrolling list of them - auto projectsResult = PythonBindingsInterface::Get()->GetProjects(); - if (projectsResult.IsSuccess() && !projectsResult.GetValue().isEmpty()) - { - QScrollArea* projectsScrollArea = new QScrollArea(this); - QWidget* scrollWidget = new QWidget(); + QScrollArea* projectsScrollArea = new QScrollArea(this); + QWidget* scrollWidget = new QWidget(); - FlowLayout* flowLayout = new FlowLayout(0, s_spacerSize, s_spacerSize); - scrollWidget->setLayout(flowLayout); + m_projectsFlowLayout = new FlowLayout(0, s_spacerSize, s_spacerSize); + scrollWidget->setLayout(m_projectsFlowLayout); - projectsScrollArea->setWidget(scrollWidget); - projectsScrollArea->setWidgetResizable(true); + projectsScrollArea->setWidget(scrollWidget); + projectsScrollArea->setWidgetResizable(true); - QVector nonProcessingProjects; - buildProjectPath = QDir::fromNativeSeparators(buildProjectPath); - for (auto& project : projectsResult.GetValue()) - { - if (projectButton && !*projectButton) - { - if (QDir::fromNativeSeparators(project.m_path) == buildProjectPath) - { - *projectButton = CreateProjectButton(project, flowLayout, true); - continue; - } - } + ResetProjectsContent(); - nonProcessingProjects.append(project); - } - - for (auto& project : nonProcessingProjects) - { - ProjectButton* projectButtonWidget = CreateProjectButton(project, flowLayout); - - if (BuildQueueContainsProject(project.m_path)) - { - projectButtonWidget->SetProjectButtonAction(tr("Cancel Queued Build"), - [this, project] - { - UnqueueBuildProject(project); - SuggestBuildProjectMsg(project, false); - }); - } - else if (RequiresBuildProjectIterator(project.m_path) != m_requiresBuild.end()) - { - auto buildProjectIterator = RequiresBuildProjectIterator(project.m_path); - if (buildProjectIterator != m_requiresBuild.end()) - { - if (buildProjectIterator->m_buildFailed) - { - projectButtonWidget->ShowBuildFailed(true, buildProjectIterator->m_logUrl); - } - else - { - projectButtonWidget->SetProjectBuildButtonAction(); - } - } - - } - } - - layout->addWidget(projectsScrollArea); - } + layout->addWidget(projectsScrollArea); } return frame; } - ProjectButton* ProjectsScreen::CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing) + ProjectButton* ProjectsScreen::CreateProjectButton(const ProjectInfo& project) { - ProjectButton* projectButton = new ProjectButton(project, this, processing); + ProjectButton* projectButton = new ProjectButton(project, this); + m_projectButtons.insert(project.m_path, projectButton); + m_projectsFlowLayout->addWidget(projectButton); - flowLayout->addWidget(projectButton); - - if (!processing) - { - connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject); - connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject); - connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject); - connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); - connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); - } + connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject); + connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject); + connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject); + connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); + connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject); return projectButton; @@ -238,29 +181,128 @@ namespace O3DE::ProjectManager void ProjectsScreen::ResetProjectsContent() { - // refresh the projects content by re-creating it for now - if (m_projectsContent) + RemoveInvalidProjects(); + + // Get all projects and create a vertical scrolling list of them + // Sort building and queued projects first + auto projectsResult = PythonBindingsInterface::Get()->GetProjects(); + if (projectsResult.IsSuccess() && !projectsResult.GetValue().isEmpty()) { - m_stack->removeWidget(m_projectsContent); - m_projectsContent->deleteLater(); + QVector projectsVector = projectsResult.GetValue(); + // If a project path is in this set then the button for it will be kept + QSet keepProject; + for (const ProjectInfo& project : projectsVector) + { + keepProject.insert(project.m_path); + } + + // Clear flow and delete buttons for removed projects + auto projectButtonsIter = m_projectButtons.begin(); + while (projectButtonsIter != m_projectButtons.end()) + { + m_projectsFlowLayout->removeWidget(projectButtonsIter.value()); + + if (!keepProject.contains(projectButtonsIter.key())) + { + projectButtonsIter = m_projectButtons.erase(projectButtonsIter); + } + else + { + ++projectButtonsIter; + } + } + + QString buildProjectPath = ""; + if (m_currentBuilder) + { + buildProjectPath = m_currentBuilder->GetProjectInfo().m_path; + } + + // Put currently building project in front, then queued projects, then sorts alphabetically + std::sort(projectsVector.begin(), projectsVector.end(), [buildProjectPath, this](const ProjectInfo& arg1, const ProjectInfo& arg2) + { + if (arg1.m_path == buildProjectPath) + { + return true; + } + else if (arg2.m_path == buildProjectPath) + { + return false; + } + + bool arg1InBuildQueue = BuildQueueContainsProject(arg1.m_path); + bool arg2InBuildQueue = BuildQueueContainsProject(arg2.m_path); + if (arg1InBuildQueue && !arg2InBuildQueue) + { + return true; + } + else if (!arg1InBuildQueue && arg2InBuildQueue) + { + return false; + } + else + { + return arg1.m_displayName.toLower() < arg2.m_displayName.toLower(); + } + }); + + // Add any missing project buttons and restore buttons to default state + for (const ProjectInfo& project : projectsVector) + { + if (!m_projectButtons.contains(project.m_path)) + { + m_projectButtons.insert(project.m_path, CreateProjectButton(project)); + } + else + { + auto projectButtonIter = m_projectButtons.find(project.m_path); + if (projectButtonIter != m_projectButtons.end()) + { + projectButtonIter.value()->RestoreDefaultState(); + m_projectsFlowLayout->addWidget(projectButtonIter.value()); + } + } + } + + // Setup building button again + auto buildProjectIter = m_projectButtons.find(buildProjectPath); + if (buildProjectIter != m_projectButtons.end()) + { + m_currentBuilder->SetProjectButton(buildProjectIter.value()); + } + + for (const ProjectInfo& project : m_buildQueue) + { + auto projectIter = m_projectButtons.find(project.m_path); + if (projectIter != m_projectButtons.end()) + { + projectIter.value()->SetProjectButtonAction( + tr("Cancel Queued Build"), + [this, project] + { + UnqueueBuildProject(project); + SuggestBuildProjectMsg(project, false); + }); + } + } + + for (const ProjectInfo& project : m_requiresBuild) + { + auto projectIter = m_projectButtons.find(project.m_path); + if (projectIter != m_projectButtons.end()) + { + if (project.m_buildFailed) + { + projectIter.value()->ShowBuildFailed(true, project.m_logUrl); + } + else + { + projectIter.value()->SetProjectBuildButtonAction(); + } + } + } } - m_background.load(":/Backgrounds/DefaultBackground.jpg"); - - // Make sure to update builder with latest Project Button - if (m_currentBuilder) - { - ProjectButton* projectButtonPtr = nullptr; - - m_projectsContent = CreateProjectsContent(m_currentBuilder->GetProjectInfo().m_path, &projectButtonPtr); - m_currentBuilder->SetProjectButton(projectButtonPtr); - } - else - { - m_projectsContent = CreateProjectsContent(); - } - - m_stack->addWidget(m_projectsContent); m_stack->setCurrentWidget(m_projectsContent); } @@ -466,7 +508,7 @@ namespace O3DE::ProjectManager if (m_buildQueue.empty() && !m_currentBuilder) { StartProjectBuild(projectInfo); - // Projects Content is already reset in fuction + // Projects Content is already reset in function } else { @@ -491,6 +533,7 @@ namespace O3DE::ProjectManager } else { + m_background.load(":/Backgrounds/DefaultBackground.jpg"); ResetProjectsContent(); } } diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h index 45605ab678..859f8d0eae 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.h +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h @@ -18,6 +18,7 @@ QT_FORWARD_DECLARE_CLASS(QPaintEvent) QT_FORWARD_DECLARE_CLASS(QFrame) QT_FORWARD_DECLARE_CLASS(QStackedWidget) QT_FORWARD_DECLARE_CLASS(QLayout) +QT_FORWARD_DECLARE_CLASS(FlowLayout) namespace O3DE::ProjectManager { @@ -59,8 +60,8 @@ namespace O3DE::ProjectManager private: QFrame* CreateFirstTimeContent(); - QFrame* CreateProjectsContent(QString buildProjectPath = "", ProjectButton** projectButton = nullptr); - ProjectButton* CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing = false); + QFrame* CreateProjectsContent(); + ProjectButton* CreateProjectButton(const ProjectInfo& project); void ResetProjectsContent(); bool ShouldDisplayFirstTimeContent(); bool RemoveInvalidProjects(); @@ -75,7 +76,9 @@ namespace O3DE::ProjectManager QPixmap m_background; QFrame* m_firstTimeContent = nullptr; QFrame* m_projectsContent = nullptr; + FlowLayout* m_projectsFlowLayout = nullptr; QStackedWidget* m_stack = nullptr; + QHash m_projectButtons; QList m_requiresBuild; QQueue m_buildQueue; ProjectBuilderController* m_currentBuilder = nullptr; diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp index 30b8ef1d34..df0bdb29f4 100644 --- a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager // add a tab widget at the bottom of the stack m_tabWidget = new QTabWidget(); + m_tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus); m_screenStack->addWidget(m_tabWidget); connect(m_tabWidget, &QTabWidget::currentChanged, this, &ScreensCtrl::TabChanged); } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 6aba261cd2..e1b6d740e2 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -54,6 +54,7 @@ namespace O3DE::ProjectManager QTabWidget* tabWidget = new QTabWidget(); tabWidget->setObjectName("projectSettingsTab"); tabWidget->tabBar()->setObjectName("projectSettingsTabBar"); + tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus); tabWidget->addTab(m_updateSettingsScreen, tr("General")); QPushButton* gemsButton = new QPushButton(tr("Configure Gems"), this); diff --git a/Code/Tools/SceneAPI/SceneCore/SceneBuilderDependencyBus.h b/Code/Tools/SceneAPI/SceneCore/SceneBuilderDependencyBus.h index 6500b5ca28..752d4a431f 100644 --- a/Code/Tools/SceneAPI/SceneCore/SceneBuilderDependencyBus.h +++ b/Code/Tools/SceneAPI/SceneCore/SceneBuilderDependencyBus.h @@ -24,7 +24,12 @@ namespace AZ : public AZ::EBusTraits { public: - virtual void ReportJobDependencies(JobDependencyList& jobDependencyList, const char* platformIdentifier) = 0; + //! Builders can implement this function to add job dependencies on other assets that may be used in the scene file conversion process. + virtual void ReportJobDependencies(JobDependencyList& jobDependencyList, const char* platformIdentifier) { AZ_UNUSED(jobDependencyList); AZ_UNUSED(platformIdentifier); } + + //! Builders can implement this function to append to the job analysis fingerprint. This can be used to trigger rebuilds when global configuration changes. + //! See also AssetBuilderDesc::m_analysisFingerprint. + virtual void AddFingerprintInfo(AZStd::set& fingerprintInfo) { AZ_UNUSED(fingerprintInfo); } }; using SceneBuilderDependencyBus = EBus; } // namespace SceneAPI diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp index f73b0d71eb..a885708a47 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp @@ -67,8 +67,8 @@ namespace AZ ImGuiPass::ImGuiPass(const RPI::PassDescriptor& descriptor) : Base(descriptor) - , AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityUI()) - , AzFramework::InputTextEventListener(AzFramework::InputTextEventListener::GetPriorityUI()) + , AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDebugUI() - 1) // Give ImGui manager priority over the pass + , AzFramework::InputTextEventListener(AzFramework::InputTextEventListener::GetPriorityDebugUI() - 1) // Give ImGui manager priority over the pass { const ImGuiPassData* imguiPassData = RPI::PassUtils::GetPassData(descriptor); @@ -157,11 +157,6 @@ namespace AZ return io.WantTextInput; } - AZ::s32 ImGuiPass::GetPriority() const - { - return AzFramework::InputChannelEventListener::GetPriorityUI(); - } - bool ImGuiPass::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) { if (!IsEnabled() || GetRenderPipeline()->GetScene() == nullptr) diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h index 76cf29a573..0bde3edb4f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.h @@ -84,7 +84,6 @@ namespace AZ // AzFramework::InputChannelEventListener overrides... bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - AZ::s32 GetPriority() const override; protected: explicit ImGuiPass(const RPI::PassDescriptor& descriptor); diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp index d173018ef7..e26a0fb274 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.cpp @@ -12,12 +12,26 @@ #include #include #include +#include #include +#include + namespace AZ { namespace Render { + void MaterialConverterSettings::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("Enable", &MaterialConverterSettings::m_enable) + ->Field("DefaultMaterial", &MaterialConverterSettings::m_defaultMaterial); + } + } + void MaterialConverterSystemComponent::Reflect(AZ::ReflectContext* context) { if (auto* serialize = azrtti_cast(context)) @@ -26,10 +40,22 @@ namespace AZ ->Version(3) ->Attribute(Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); } + + MaterialConverterSettings::Reflect(context); + } + + void MaterialConverterSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.emplace_back(AZ_CRC_CE("FingerprintModification")); } void MaterialConverterSystemComponent::Activate() { + if (auto* settingsRegistry = AZ::SettingsRegistry::Get()) + { + settingsRegistry->GetObject(m_settings, "/O3DE/SceneAPI/MaterialConverter"); + } + RPI::MaterialConverterBus::Handler::BusConnect(); } @@ -37,11 +63,21 @@ namespace AZ { RPI::MaterialConverterBus::Handler::BusDisconnect(); } + + bool MaterialConverterSystemComponent::IsEnabled() const + { + return m_settings.m_enable; + } bool MaterialConverterSystemComponent::ConvertMaterial( const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& sourceData) { using namespace AZ::RPI; + + if (!m_settings.m_enable) + { + return false; + } // The source data for generating material asset sourceData.m_materialType = GetMaterialTypePath(); @@ -140,9 +176,20 @@ namespace AZ return true; } - const char* MaterialConverterSystemComponent::GetMaterialTypePath() const + AZStd::string MaterialConverterSystemComponent::GetMaterialTypePath() const { return "Materials/Types/StandardPBR.materialtype"; } + + AZStd::string MaterialConverterSystemComponent::GetDefaultMaterialPath() const + { + if (m_settings.m_defaultMaterial.empty()) + { + AZ_Error("MaterialConverterSystemComponent", m_settings.m_enable, + "Material conversion is disabled but a default material not specified in registry /O3DE/SceneAPI/MaterialConverter/DefaultMaterial"); + } + + return m_settings.m_defaultMaterial; + } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.h index 38d4faedc8..7d95024759 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialConverterSystemComponent.h @@ -18,6 +18,16 @@ namespace AZ { namespace Render { + struct MaterialConverterSettings + { + AZ_TYPE_INFO(MaterialConverterSettings, "{8D91601D-570A-4557-99C8-631DB4928040}"); + + static void Reflect(AZ::ReflectContext* context); + + bool m_enable = true; + AZStd::string m_defaultMaterial; + }; + //! Atom's implementation of converting SceneAPI data into Atom's default material: StandardPBR class MaterialConverterSystemComponent final : public AZ::Component @@ -27,13 +37,20 @@ namespace AZ AZ_COMPONENT(MaterialConverterSystemComponent, "{C2338D45-6456-4521-B469-B000A13F2493}"); static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services); void Activate() override; void Deactivate() override; // MaterialConverterBus overrides ... + bool IsEnabled() const override; bool ConvertMaterial(const AZ::SceneAPI::DataTypes::IMaterialData& materialData, RPI::MaterialSourceData& out) override; - const char* GetMaterialTypePath() const override; + AZStd::string GetMaterialTypePath() const override; + AZStd::string GetDefaultMaterialPath() const override; + + private: + MaterialConverterSettings m_settings; }; } } diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h index 9372977d8e..92b56880b7 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h @@ -173,13 +173,14 @@ namespace AZ static void Reflect(AZ::ReflectContext* context); CpuProfilingStatisticsSerializerEntry() = default; - CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion); + CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId); Name m_groupName; Name m_regionName; uint16_t m_stackDepth; AZStd::sys_time_t m_startTick; AZStd::sys_time_t m_endTick; + size_t m_threadId; }; AZ_TYPE_INFO(CpuProfilingStatisticsSerializer, "{D5B02946-0D27-474F-9A44-364C2706DD41}"); diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index 6cfd68d3c6..8099fc3a32 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -417,14 +417,14 @@ namespace AZ // Create serializable entries for (const auto& timeRegionMap : continuousData) { - for (const auto& threadEntry : timeRegionMap) + for (const auto& [threadId, regionMap] : timeRegionMap) { - for (const auto& cachedRegionEntry : threadEntry.second) + for (const auto& [regionName, regionVec] : regionMap) { - m_cpuProfilingStatisticsSerializerEntries.insert( - m_cpuProfilingStatisticsSerializerEntries.end(), - cachedRegionEntry.second.begin(), - cachedRegionEntry.second.end()); + for (const auto& region : regionVec) + { + m_cpuProfilingStatisticsSerializerEntries.emplace_back(region, threadId); + } } } } @@ -445,13 +445,15 @@ namespace AZ // --- CpuProfilingStatisticsSerializerEntry --- - CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion) + CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry( + const RHI::CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId) { m_groupName = cachedTimeRegion.m_groupRegionName->m_groupName; m_regionName = cachedTimeRegion.m_groupRegionName->m_regionName; m_stackDepth = cachedTimeRegion.m_stackDepth; m_startTick = cachedTimeRegion.m_startTick; m_endTick = cachedTimeRegion.m_endTick; + m_threadId = AZStd::hash{}(threadId); } void CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::Reflect(AZ::ReflectContext* context) @@ -465,6 +467,7 @@ namespace AZ ->Field("stackDepth", &CpuProfilingStatisticsSerializerEntry::m_stackDepth) ->Field("startTick", &CpuProfilingStatisticsSerializerEntry::m_startTick) ->Field("endTick", &CpuProfilingStatisticsSerializerEntry::m_endTick) + ->Field("threadId", &CpuProfilingStatisticsSerializerEntry::m_threadId) ; } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialConverterBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialConverterBus.h index 120c1ee28b..8052fc4feb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialConverterBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialConverterBus.h @@ -29,10 +29,19 @@ namespace AZ : public AZ::EBusTraits { public: - //! Returns true if the converion was successful + + virtual bool IsEnabled() const = 0; + + //! Converts data from a IMaterialData object to an Atom MaterialSourceData. + //! Only works when IsEnabled() is true. + //! @return true if the MaterialSourceData output was populated with converted material data. virtual bool ConvertMaterial(const AZ::SceneAPI::DataTypes::IMaterialData& materialData, MaterialSourceData& out) = 0; - //! Returns the path to the .materialtype file that the materials are based on, such as StandardPBR.materialtype, etc. - virtual const char* GetMaterialTypePath() const = 0; + + //! Returns the path to the .materialtype file that the converted materials are based on, such as StandardPBR.materialtype, etc. + virtual AZStd::string GetMaterialTypePath() const = 0; + + //! Returns the path to a .material file to use as the default material when conversion is disabled. + virtual AZStd::string GetDefaultMaterialPath() const = 0; }; using MaterialConverterBus = AZ::EBus; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h index dd46aca6cd..30088d2d52 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelMaterialSlot.h @@ -25,6 +25,8 @@ namespace AZ static void Reflect(AZ::ReflectContext* context); + // Note that StableId is uint32_t for legacy reasons: we used to use AssetId::m_subId as the material slot ID. But actually the original MaterialUid + // is 64 bit so we might want to switch this to be uint64_t at some point. using StableId = uint32_t; static const StableId InvalidStableId; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp index 7187cb391a..4a4c2156ce 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -70,28 +71,74 @@ namespace AZ void MaterialAssetDependenciesComponent::ReportJobDependencies(SceneAPI::JobDependencyList& jobDependencyList, const char* platformIdentifier) { - AssetBuilderSDK::SourceFileDependency materialTypeSource; + bool conversionEnabled = false; + RPI::MaterialConverterBus::BroadcastResult(conversionEnabled, &RPI::MaterialConverterBus::Events::IsEnabled); + // Right now, scene file importing only supports a single material type, once that changes, this will have to be re-designed, see ATOM-3554 - RPI::MaterialConverterBus::BroadcastResult(materialTypeSource.m_sourceFileDependencyPath, &RPI::MaterialConverterBus::Events::GetMaterialTypePath); + AZStd::string materialTypePath; + RPI::MaterialConverterBus::BroadcastResult(materialTypePath, &RPI::MaterialConverterBus::Events::GetMaterialTypePath); - AssetBuilderSDK::JobDependency jobDependency; - jobDependency.m_jobKey = "Atom Material Builder"; - jobDependency.m_sourceFile = materialTypeSource; - jobDependency.m_platformIdentifier = platformIdentifier; - jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; - - if (!materialTypeSource.m_sourceFileDependencyPath.empty()) + if (conversionEnabled && !materialTypePath.empty()) { + AssetBuilderSDK::SourceFileDependency materialTypeSource; + materialTypeSource.m_sourceFileDependencyPath = materialTypePath; + + AssetBuilderSDK::JobDependency jobDependency; + jobDependency.m_jobKey = "Atom Material Builder"; + jobDependency.m_sourceFile = materialTypeSource; + jobDependency.m_platformIdentifier = platformIdentifier; + jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; + jobDependencyList.push_back(jobDependency); } } + + void MaterialAssetDependenciesComponent::AddFingerprintInfo(AZStd::set& fingerprintInfo) + { + // This will cause scene files to be reprocessed whenever the global MaterialConverter settings change. + + bool conversionEnabled = false; + RPI::MaterialConverterBus::BroadcastResult(conversionEnabled, &RPI::MaterialConverterBus::Events::IsEnabled); + fingerprintInfo.insert(AZStd::string::format("[MaterialConverter enabled=%d]", conversionEnabled)); + + if (!conversionEnabled) + { + AZStd::string defaultMaterialPath; + RPI::MaterialConverterBus::BroadcastResult(defaultMaterialPath, &RPI::MaterialConverterBus::Events::GetDefaultMaterialPath); + fingerprintInfo.insert(AZStd::string::format("[MaterialConverter defaultMaterial=%s]", defaultMaterialPath.c_str())); + } + } void MaterialAssetBuilderComponent::Reflect(ReflectContext* context) { if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(16); // Optional material conversion + ->Version(16); // Optional material conversion + } + } + + Data::Asset MaterialAssetBuilderComponent::GetDefaultMaterialAsset() const + { + AZStd::string defaultMaterialPath; + RPI::MaterialConverterBus::BroadcastResult(defaultMaterialPath, &RPI::MaterialConverterBus::Events::GetDefaultMaterialPath); + + if (defaultMaterialPath.empty()) + { + return {}; + } + else + { + auto defaultMaterialAssetId = RPI::AssetUtils::MakeAssetId(defaultMaterialPath, 0); + if (!defaultMaterialAssetId.IsSuccess()) + { + AZ_Error("MaterialAssetBuilderComponent", false, "Could not find asset '%s'", defaultMaterialPath.c_str()); + return {}; + } + else + { + return Data::AssetManager::Instance().CreateAsset(defaultMaterialAssetId.GetValue(), Data::AssetLoadBehaviorNamespace::PreLoad); + } } } @@ -119,8 +166,8 @@ namespace AZ BindToCall(&MaterialAssetBuilderComponent::BuildMaterials); } - - SceneAPI::Events::ProcessingResult MaterialAssetBuilderComponent::BuildMaterials(MaterialAssetBuilderContext& context) const + + SceneAPI::Events::ProcessingResult MaterialAssetBuilderComponent::ConvertMaterials(MaterialAssetBuilderContext& context) const { const auto& scene = context.m_scene; const Uuid sourceSceneUuid = scene.GetSourceGuid(); @@ -193,6 +240,64 @@ namespace AZ return SceneAPI::Events::ProcessingResult::Success; } + + SceneAPI::Events::ProcessingResult MaterialAssetBuilderComponent::AssignDefaultMaterials(MaterialAssetBuilderContext& context) const + { + Data::Asset defaultMaterialAsset = GetDefaultMaterialAsset(); + + if (!defaultMaterialAsset.GetId().IsValid()) + { + AZ_Warning("MaterialAssetBuilderComponent", false, "Material conversion is disabled but no default material was provided. The model will likely be invisible by default."); + // Return success because it's just a warning. + return SceneAPI::Events::ProcessingResult::Success; + } + + const auto& scene = context.m_scene; + const Uuid sourceSceneUuid = scene.GetSourceGuid(); + const auto& sceneGraph = scene.GetGraph(); + + auto names = sceneGraph.GetNameStorage(); + auto content = sceneGraph.GetContentStorage(); + auto pairView = SceneAPI::Containers::Views::MakePairView(names, content); + + auto view = SceneAPI::Containers::Views::MakeSceneGraphDownwardsView< + SceneAPI::Containers::Views::BreadthFirst>( + sceneGraph, sceneGraph.GetRoot(), pairView.cbegin(), true); + + for (const auto& viewIt : view) + { + if (viewIt.second == nullptr) + { + continue; + } + + if (azrtti_istypeof(viewIt.second.get())) + { + auto materialData = AZStd::static_pointer_cast(viewIt.second); + uint64_t materialUid = materialData->GetUniqueId(); + + context.m_outputMaterialsByUid[materialUid] = { defaultMaterialAsset, materialData->GetMaterialName() }; + } + } + + return SceneAPI::Events::ProcessingResult::Success; + } + + SceneAPI::Events::ProcessingResult MaterialAssetBuilderComponent::BuildMaterials(MaterialAssetBuilderContext& context) const + { + bool conversionEnabled = false; + RPI::MaterialConverterBus::BroadcastResult(conversionEnabled, &RPI::MaterialConverterBus::Events::IsEnabled); + + if (conversionEnabled) + { + return ConvertMaterials(context); + } + else + { + return AssignDefaultMaterials(context); + } + + } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.h index f02034c35d..f89ae1cde9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MaterialAssetBuilderComponent.h @@ -39,6 +39,13 @@ namespace AZ // Required for ExportingComponent static void Reflect(AZ::ReflectContext* context); + + private: + + SceneAPI::Events::ProcessingResult ConvertMaterials(MaterialAssetBuilderContext& context) const; + SceneAPI::Events::ProcessingResult AssignDefaultMaterials(MaterialAssetBuilderContext& context) const; + + Data::Asset GetDefaultMaterialAsset() const; }; /** @@ -65,6 +72,7 @@ namespace AZ // SceneAPI::SceneBuilderDependencyBus::Handler overrides... void ReportJobDependencies(SceneAPI::JobDependencyList& jobDependencyList, const char* platformIdentifier) override; + void AddFingerprintInfo(AZStd::set& fingerprintInfo) override; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp index ea39ea9031..f7e672ab32 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelExporterComponent.cpp @@ -78,9 +78,17 @@ namespace AZ //Export MaterialAssets for (auto& materialPair : materialsByUid) { + const Data::Asset& asset = materialPair.second.m_asset; + + // MaterialAssetBuilderContext could attach an independent material asset rather than + // generate one using the scene data, so we must skip the export step in that case. + if (asset.GetId().m_guid != exportEventContext.GetScene().GetSourceGuid()) + { + continue; + } + uint64_t materialUid = materialPair.first; const AZStd::string& sceneName = exportEventContext.GetScene().GetName(); - const Data::Asset& asset = materialPair.second.m_asset; // escape the material name acceptable for a filename AZStd::string materialName = materialPair.second.m_name; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index bb26e116af..b6db6b78ae 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -109,7 +109,6 @@ namespace AtomToolsFramework // AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Handler ... void BeginCursorCapture() override; void EndCursorCapture() override; - AzFramework::ScreenPoint ViewportCursorScreenPosition() override; bool IsMouseOver() const override; // AzFramework::WindowRequestBus::Handler ... diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index bf356d2b99..cbb30ba6da 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -403,11 +403,6 @@ namespace AtomToolsFramework return aznumeric_cast(devicePixelRatioF()); } - AzFramework::ScreenPoint RenderViewportWidget::ViewportCursorScreenPosition() - { - return AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(m_mousePosition.toPoint()); - } - bool RenderViewportWidget::IsMouseOver() const { return m_mouseOver; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h index bdaf38a64a..ea4dd20250 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.h @@ -43,7 +43,7 @@ namespace AZ }; // Update running statistics with new region data - void RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId); + void RecordRegion(const AZ::RHI::CachedTimeRegion& region, size_t threadId); void ResetPerFrameStatistics(); @@ -58,7 +58,7 @@ namespace AZ u64 m_invocationsLastFrame = 0; // NOTE: set over unordered_set so the threads can be shown in increasing order in tooltip. - AZStd::set m_executingThreads; + AZStd::set m_executingThreads; AZStd::sys_time_t m_lastFrameTotalTicks = 0; @@ -95,7 +95,7 @@ namespace AZ void Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& cpuTimingStatistics); private: - static constexpr float RowHeight = 50.0; + static constexpr float RowHeight = 35.0; static constexpr int DefaultFramesToCollect = 50; static constexpr float MediumFrameTimeLimit = 16.6; // 60 fps static constexpr float HighFrameTimeLimit = 33.3; // 30 fps @@ -134,7 +134,7 @@ namespace AZ void DrawThreadSeparator(u64 threadBoundary, u64 maxDepth); // Draw the "Thread XXXXX" label onto the viewport - void DrawThreadLabel(u64 baseRow, AZStd::thread_id threadId); + void DrawThreadLabel(u64 baseRow, size_t threadId); // Draw the vertical lines separating frames in the timeline void DrawFrameBoundaries(); @@ -169,7 +169,9 @@ namespace AZ AZStd::sys_time_t m_viewportEndTick; // Map to store each thread's TimeRegions, individual vectors are sorted by start tick - AZStd::unordered_map> m_savedData; + // note: we use size_t as a proxy for thread_id because native_thread_id_type differs differs from + // platform to platform, which causes problems when deserializing saved captures. + AZStd::unordered_map> m_savedData; // Region color cache AZStd::unordered_map m_regionColorMap; @@ -213,6 +215,11 @@ namespace AZ // Index into the file picker, used to determine which file to load when "Load File" is pressed. int m_currentFileIndex = 0; + + + // --- Loading capture state --- + AZStd::unordered_set m_deserializedStringPool; + AZStd::unordered_set m_deserializedGroupRegionNamePool; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index a225646761..638927d601 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -30,19 +31,6 @@ namespace AZ { namespace CpuProfilerImGuiHelper { - // NOTE: Fix build error in case AZStd::thread_id is not of an arithmetic type, and instead a pointer - template::value>::type* = nullptr> - AZStd::string TextThreadId(ThreadId threadId) - { - return AZStd::string::format("Thread: %p", threadId); - } - - template::value>::type* = nullptr> - AZStd::string TextThreadId(ThreadId threadId) - { - return AZStd::string::format("Thread: %zu", static_cast(threadId)); - } - inline float TicksToMs(AZStd::sys_time_t ticks) { // Note: converting to microseconds integer before converting to milliseconds float @@ -231,6 +219,7 @@ namespace AZ m_lastCapturedFilePath = resolvedPath; AZ::Render::ProfilingCaptureRequestBus::Broadcast( &AZ::Render::ProfilingCaptureRequestBus::Events::EndContinuousCpuProfilingCapture, frameDataFilePath); + m_paused = true; } else @@ -447,13 +436,65 @@ namespace AZ inline void ImGuiCpuProfiler::LoadFile() { const IO::Path& pathToLoad = m_cachedCapturePaths[m_currentFileIndex]; - auto res = CpuProfilerImGuiHelper::LoadSavedCpuProfilingStatistics(pathToLoad.String()); - if (!res.IsSuccess()) + auto loadResult = CpuProfilerImGuiHelper::LoadSavedCpuProfilingStatistics(pathToLoad.String()); + if (!loadResult.IsSuccess()) { - AZ_TracePrintf("ImGuiCpuProfiler", "%s", res.GetError().c_str()); + AZ_TracePrintf("ImGuiCpuProfiler", "%s", loadResult.GetError().c_str()); return; } - // TODO ATOM-16022 Parse this data and display it in the visualizer widget. + + AZStd::vector deserializedData = loadResult.TakeValue(); + + // Clear visualizer and statistics view state + m_savedRegionCount = deserializedData.size(); + m_savedData.clear(); + m_paused = true; + AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(false); + m_frameEndTicks.clear(); + + m_tableData.clear(); + m_groupRegionMap.clear(); + + for (const auto& entry : deserializedData) + { + const auto [groupNameItr, wasGroupNameInserted] = m_deserializedStringPool.emplace(entry.m_groupName.GetCStr()); + const auto [regionNameItr, wasRegionNameInserted] = m_deserializedStringPool.emplace(entry.m_regionName.GetCStr()); + const auto [groupRegionNameItr, wasGroupRegionNameInserted] = + m_deserializedGroupRegionNamePool.emplace(groupNameItr->c_str(), regionNameItr->c_str()); + + const RHI::CachedTimeRegion newRegion(&(*groupRegionNameItr), entry.m_stackDepth, entry.m_startTick, entry.m_endTick); + m_savedData[entry.m_threadId].push_back(newRegion); + + // Since we don't serialize the frame boundaries, we need to use the RPI's OnSystemTick event as a heuristic. + const static Name frameBoundaryName = Name("RPISystem: OnSystemTick"); + if (entry.m_regionName == frameBoundaryName) + { + m_frameEndTicks.push_back(entry.m_endTick); + } + + // Update running statistics + if (!m_groupRegionMap[*groupNameItr].contains(*regionNameItr)) + { + m_groupRegionMap[*groupNameItr][*regionNameItr].m_groupName = *groupNameItr; + m_groupRegionMap[*groupNameItr][*regionNameItr].m_regionName = *regionNameItr; + m_tableData.push_back(&m_groupRegionMap[*groupNameItr][*regionNameItr]); + } + m_groupRegionMap[*groupNameItr][*regionNameItr].RecordRegion(newRegion, entry.m_threadId); + } + + // Update viewport bounds with some added UX fudge factor + m_viewportStartTick = deserializedData.back().m_startTick - 1000; + m_viewportEndTick = deserializedData.back().m_endTick + 1000; + + // Invariant: each vector in m_savedData must be sorted so that we can efficiently cull region data. + for (auto& [threadId, singleThreadData] : m_savedData) + { + AZStd::sort(singleThreadData.begin(), singleThreadData.end(), + [](const TimeRegion& lhs, const TimeRegion& rhs) + { + return lhs.m_startTick < rhs.m_startTick; + }); + } } // -- CPU Visualizer -- @@ -465,7 +506,7 @@ namespace AZ if (ImGui::BeginChild("Options and Statistics", { 0, 0 }, true)) { ImGui::Columns(3, "Options", true); - ImGui::SliderInt("Saved Frames", &m_framesToCollect, 10, 10000, "%d", ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_Logarithmic); + ImGui::SliderInt("Saved Frames", &m_framesToCollect, 10, 20000, "%d", ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_Logarithmic); m_visualizerHighlightFilter.Draw("Find Region"); ImGui::NextColumn(); @@ -631,6 +672,7 @@ namespace AZ // Iterate through the entire TimeRegionMap and copy the data since it will get deleted on the next frame for (const auto& [threadId, singleThreadRegionMap] : timeRegionMap) { + const size_t threadIdHashed = AZStd::hash{}(threadId); // The profiler can sometime return threads without any profiling events when dropping threads, FIXME(ATOM-15949) if (singleThreadRegionMap.size() == 0) { @@ -656,7 +698,7 @@ namespace AZ m_tableData.push_back(&m_groupRegionMap[groupName][regionName]); } - m_groupRegionMap[groupName][regionName].RecordRegion(region, threadId); + m_groupRegionMap[groupName][regionName].RecordRegion(region, threadIdHashed); } } @@ -676,7 +718,7 @@ namespace AZ m_savedRegionCount += newVisualizerData.size(); // Move onto the end of the current thread's saved data, sorted order maintained - AZStd::vector& savedDataVec = m_savedData[threadId]; + AZStd::vector& savedDataVec = m_savedData[threadIdHashed]; savedDataVec.insert( savedDataVec.end(), AZStd::make_move_iterator(newVisualizerData.begin()), AZStd::make_move_iterator(newVisualizerData.end())); } @@ -696,6 +738,12 @@ namespace AZ { AZStd::size_t sizeBeforeRemove = savedRegions.size(); + // Early out to avoid the linear erase_if call + if (savedRegions.size() >= 1 && savedRegions.at(0).m_startTick > deleteBeforeTick) + { + continue; + } + // Use erase_if over plain upper_bound + erase to avoid repeated shifts. erase requires a shift of all elements to the right // for each element that is erased, while erase_if squashes all removes into a single shift which significantly improves perf. AZStd::erase_if( @@ -732,12 +780,19 @@ namespace AZ const float startPixel = ConvertTickToPixelSpace(block.m_startTick, m_viewportStartTick, m_viewportEndTick); const float endPixel = ConvertTickToPixelSpace(block.m_endTick, m_viewportStartTick, m_viewportEndTick); - const ImVec2 startPoint = { startPixel, wy + targetRow * RowHeight }; - const ImVec2 endPoint = { endPixel, wy + targetRow * RowHeight + 40 }; + if (endPixel - startPixel < 0.5f) + { + return; + } + + const ImVec2 startPoint = { startPixel, wy + targetRow * RowHeight + 1}; + const ImVec2 endPoint = { endPixel, wy + (targetRow + 1) * RowHeight }; const ImU32 blockColor = GetBlockColor(block); drawList->AddRectFilled(startPoint, endPoint, blockColor, 0); + drawList->AddLine(startPoint, { endPixel, startPoint.y }, IM_COL32_BLACK, 0.5f); + drawList->AddLine({ startPixel, endPoint.y }, endPoint, IM_COL32_BLACK, 0.5f); // Draw the region name if possible // If the block's current width is too small, we skip drawing the label. @@ -751,11 +806,13 @@ namespace AZ if (regionPixelWidth < textWidth) // Not enough space in the block to draw the whole name, draw clipped text. { - // clipRect appears to only clip when a character is fully outside of its bounds which can lead to overflow - // for now subtract the width of a character const ImVec4 clipRect = { startPoint.x, startPoint.y, endPoint.x - maxCharWidth, endPoint.y }; - const float fontSize = ImGui::GetFont()->FontSize; + // NOTE: RenderText calls do not automatically account for the global scale (which is modified at high DPI) + // so we must adjust for the scale manually. + const float scaleFactor = ImGui::GetIO().FontGlobalScale; + const float fontSize = ImGui::GetFont()->FontSize * scaleFactor; + ImGui::GetFont()->RenderText(drawList, fontSize, startPoint, IM_COL32_WHITE, clipRect, label.c_str(), 0); } else // We have enough space to draw the entire label, draw and center text. @@ -815,18 +872,18 @@ namespace AZ auto [wx, wy] = ImGui::GetWindowPos(); wy -= ImGui::GetScrollY(); const float windowWidth = ImGui::GetWindowWidth(); - const float boundaryY = wy + (baseRow + maxDepth + 1) * RowHeight - 5; + const float boundaryY = wy + (baseRow + maxDepth + 1) * RowHeight; - ImGui::GetWindowDrawList()->AddLine({ wx, boundaryY }, { wx + windowWidth, boundaryY }, red, 2.0f); + ImGui::GetWindowDrawList()->AddLine({ wx, boundaryY }, { wx + windowWidth, boundaryY }, red, 1.0f); } - inline void ImGuiCpuProfiler::DrawThreadLabel(u64 baseRow, AZStd::thread_id threadId) + inline void ImGuiCpuProfiler::DrawThreadLabel(u64 baseRow, size_t threadId) { auto [wx, wy] = ImGui::GetWindowPos(); wy -= ImGui::GetScrollY(); - const AZStd::string threadIdText = CpuProfilerImGuiHelper::TextThreadId(threadId.m_id); + const AZStd::string threadIdText = AZStd::string::format("Thread: %zu", threadId); - ImGui::GetWindowDrawList()->AddText({ wx + 10, wy + baseRow * RowHeight + 5 }, IM_COL32_WHITE, threadIdText.c_str()); + ImGui::GetWindowDrawList()->AddText({ wx + 10, wy + baseRow * RowHeight}, IM_COL32_WHITE, threadIdText.c_str()); } inline void ImGuiCpuProfiler::DrawFrameBoundaries() @@ -884,8 +941,10 @@ namespace AZ const float textBeginPixel = lastFrameBoundaryPixel + offset; const float textEndPixel = textBeginPixel + labelWidth; + const float verticalOffset = (ImGui::GetWindowHeight() - ImGui::GetFontSize()) / 2; + // Execution time label - drawList->AddText({ textBeginPixel, wy + ImGui::GetWindowHeight() / 4 }, IM_COL32_WHITE, label.c_str()); + drawList->AddText({ textBeginPixel, wy + verticalOffset }, IM_COL32_WHITE, label.c_str()); // Left side drawList->AddLine( @@ -1043,7 +1102,7 @@ namespace AZ // ---- TableRow impl ---- - inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region, AZStd::thread_id threadId) + inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region, size_t threadId) { const AZStd::sys_time_t deltaTime = region.m_endTick - region.m_startTick; @@ -1072,7 +1131,7 @@ namespace AZ auto threadString = AZStd::string::format("Executed in %zu threads\n", m_executingThreads.size()); for (const auto& threadId : m_executingThreads) { - threadString.append(CpuProfilerImGuiHelper::TextThreadId(threadId.m_id) + "\n"); + threadString.append(AZStd::string::format("Thread: %zu\n", threadId)); } return threadString; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 91ac73a209..6e1e710282 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -133,7 +134,7 @@ namespace AZ { InitializeMaterialInstance(asset); } - + void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { AZStd::unordered_set propertyOverrides; @@ -208,6 +209,7 @@ namespace AZ for (auto& materialPair : m_configuration.m_materials) { auto& materialAsset = materialPair.second.m_materialAsset; + if (materialAsset.GetId().IsValid() && !Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId())) { anyQueued = true; @@ -221,7 +223,7 @@ namespace AZ ReleaseMaterials(); } } - + void MaterialComponentController::InitializeMaterialInstance(const Data::Asset& asset) { bool allReady = true; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 8866493998..9e59bbef19 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -92,11 +92,11 @@ namespace AZ AZ_DISABLE_COPY(MaterialComponentController); - //! Data::AssetBus interface + //! Data::AssetBus overrides... void OnAssetReady(Data::Asset asset) override; void OnAssetReloaded(Data::Asset asset) override; - //! AZ::TickBus interface implementation + // AZ::TickBus overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; void LoadMaterials(); diff --git a/Gems/ImGui/Code/Source/ImGuiManager.h b/Gems/ImGui/Code/Source/ImGuiManager.h index 20695c0825..1b24aa9806 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.h +++ b/Gems/ImGui/Code/Source/ImGuiManager.h @@ -67,7 +67,7 @@ namespace ImGui // -- AzFramework::InputChannelEventListener and AzFramework::InputTextEventListener Interface ------------ bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; bool OnInputTextEventFiltered(const AZStd::string& textUTF8) override; - int GetPriority() const override { return AzFramework::InputChannelEventListener::GetPriorityDebug(); } + int GetPriority() const override { return AzFramework::InputChannelEventListener::GetPriorityDebugUI(); } // -- AzFramework::InputChannelEventListener and AzFramework::InputTextEventListener Interface ------------ // AzFramework::WindowNotificationBus::Handler overrides... diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index 80e8bee8e3..e2c3896356 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -226,13 +226,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) OUTPUT_SUBDIRECTORY Test.Assets/Gems/PhysX/Code/Tests ) -endif() - -ly_add_source_properties( - SOURCES - Editor/CollisionLayersWidget.cpp - Source/Collision.cpp - Source/Configuration/PhysXConfiguration.cpp - PROPERTY COMPILE_DEFINITIONS - VALUES TOUCHBENDING_LAYER_BIT=${LY_TOUCHBENDING_LAYER_BIT} -) +endif() \ No newline at end of file diff --git a/Gems/PhysX/Code/Editor/CollisionLayersWidget.cpp b/Gems/PhysX/Code/Editor/CollisionLayersWidget.cpp index 76a9c63ec0..49853312c6 100644 --- a/Gems/PhysX/Code/Editor/CollisionLayersWidget.cpp +++ b/Gems/PhysX/Code/Editor/CollisionLayersWidget.cpp @@ -22,9 +22,6 @@ namespace PhysX namespace Editor { const AZStd::string CollisionLayersWidget::s_defaultCollisionLayerName = "Default"; -#ifdef TOUCHBENDING_LAYER_BIT - const AZStd::string CollisionLayersWidget::s_touchBendCollisionLayerName = "TouchBend"; -#endif CollisionLayersWidget::CollisionLayersWidget(QWidget* parent) : QWidget(parent) @@ -150,12 +147,6 @@ namespace PhysX { lineEditCtrl->setEnabled(false); } -#ifdef TOUCHBENDING_LAYER_BIT - else if (lineEditCtrl->value() == s_touchBendCollisionLayerName) - { - lineEditCtrl->setEnabled(false); - } -#endif } } diff --git a/Gems/PhysX/Code/Editor/CollisionLayersWidget.h b/Gems/PhysX/Code/Editor/CollisionLayersWidget.h index ae21147cd2..2fb0af996b 100644 --- a/Gems/PhysX/Code/Editor/CollisionLayersWidget.h +++ b/Gems/PhysX/Code/Editor/CollisionLayersWidget.h @@ -35,9 +35,6 @@ namespace PhysX static const AZ::u32 s_maxCollisionLayerNameLength = 32; static const AZStd::string s_defaultCollisionLayerName; -#ifdef TOUCHBENDING_LAYER_BIT - static const AZStd::string s_touchBendCollisionLayerName; -#endif explicit CollisionLayersWidget(QWidget* parent = nullptr); diff --git a/Gems/PhysX/Code/Source/Collision.cpp b/Gems/PhysX/Code/Source/Collision.cpp index 0476dcfd09..361b1d13eb 100644 --- a/Gems/PhysX/Code/Source/Collision.cpp +++ b/Gems/PhysX/Code/Source/Collision.cpp @@ -38,21 +38,6 @@ namespace PhysX return physx::PxFilterFlag::eDEFAULT; } -//Enable/Disable this macro in the TouchBending Gem wscript -#ifdef TOUCHBENDING_LAYER_BIT - //If any of the actors is in the TouchBend layer then we are not interested - //in contact data, nor interested in eNOTIFY_* callbacks. - const AZ::u64 touchBendLayerMask = AzPhysics::CollisionLayer::TouchBend.GetMask(); - const AZ::u64 layer0 = Combine(filterData0.word0, filterData0.word1); - const AZ::u64 layer1 = Combine(filterData1.word0, filterData1.word1); - if (layer0 == touchBendLayerMask || layer1 == touchBendLayerMask) - { - pairFlags = physx::PxPairFlag::eSOLVE_CONTACT | - physx::PxPairFlag::eDETECT_DISCRETE_CONTACT; - return physx::PxFilterFlag::eDEFAULT; - } -#endif //TOUCHBENDING_LAYER_BIT - // generate contacts for all that were not filtered above pairFlags = physx::PxPairFlag::eCONTACT_DEFAULT | @@ -89,22 +74,6 @@ namespace PhysX return physx::PxFilterFlag::eDEFAULT; } -//Enable/Disable this macro in the TouchBending Gem wscript -#ifdef TOUCHBENDING_LAYER_BIT - //If any of the actors is in the TouchBend layer then we are not interested - //in contact data, nor interested in eNOTIFY_* callbacks. - const AZ::u64 layer0 = Combine(filterData0.word0, filterData0.word1); - const AZ::u64 layer1 = Combine(filterData1.word0, filterData1.word1); - const AZ::u64 touchBendLayerMask = AzPhysics::CollisionLayer::TouchBend.GetMask(); - if (layer0 == touchBendLayerMask || layer1 == touchBendLayerMask) - { - pairFlags = physx::PxPairFlag::eSOLVE_CONTACT | - physx::PxPairFlag::eDETECT_DISCRETE_CONTACT | - physx::PxPairFlag::eDETECT_CCD_CONTACT; - return physx::PxFilterFlag::eDEFAULT; - } -#endif - // generate contacts for all that were not filtered above pairFlags = physx::PxPairFlag::eCONTACT_DEFAULT | diff --git a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp index 4e1b66017e..7a441a1c55 100644 --- a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp @@ -23,11 +23,6 @@ namespace PhysX configuration.m_collisionGroups.CreateGroup("All", AzPhysics::CollisionGroup::All, AzPhysics::CollisionGroups::Id(), true); configuration.m_collisionGroups.CreateGroup("None", AzPhysics::CollisionGroup::None, AzPhysics::CollisionGroups::Id::Create(), true); -#ifdef TOUCHBENDING_LAYER_BIT - configuration.m_collisionLayers.SetName(AzPhysics::CollisionLayer::TouchBend, "TouchBend"); - configuration.m_collisionGroups.CreateGroup("All_NoTouchBend", AzPhysics::CollisionGroup::All_NoTouchBend, AzPhysics::CollisionGroups::Id::Create(), true); -#endif - return configuration; } diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 2445aba9bd..c337ab0a85 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -122,7 +122,10 @@ namespace PhysX if (m_shapeType != Physics::ShapeType::PhysicsAsset && m_lastShapeType == Physics::ShapeType::PhysicsAsset) { + //clean up any reference to a physics assets, and re-initialize to an empty Pipeline::MeshAsset asset. m_physicsAsset.m_pxAsset.Reset(); + m_physicsAsset.m_pxAsset = AZ::Data::Asset(AZ::Data::AssetLoadBehavior::QueueLoad); + m_physicsAsset.m_configuration = Physics::PhysicsAssetShapeConfiguration(); } m_lastShapeType = m_shapeType; diff --git a/Gems/PhysX/Code/Source/RigidBodyStatic.cpp b/Gems/PhysX/Code/Source/RigidBodyStatic.cpp index 325c42960a..2d4d64e518 100644 --- a/Gems/PhysX/Code/Source/RigidBodyStatic.cpp +++ b/Gems/PhysX/Code/Source/RigidBodyStatic.cpp @@ -20,6 +20,8 @@ namespace PhysX { + AZ_CLASS_ALLOCATOR_IMPL(PhysX::StaticRigidBody, AZ::SystemAllocator, 0); + StaticRigidBody::StaticRigidBody(const AzPhysics::StaticRigidBodyConfiguration& configuration) { CreatePhysXActor(configuration); @@ -40,7 +42,7 @@ namespace PhysX // Invalidate user data so it sets m_pxStaticRigidBody->userData to nullptr. // It's appropriate to do this as m_pxStaticRigidBody is a shared pointer and - // techniqucally it could survive m_actorUserData life's spam. + // technically it could survive m_actorUserData life's span. m_actorUserData.Invalidate(); } diff --git a/Gems/PhysX/Code/Source/RigidBodyStatic.h b/Gems/PhysX/Code/Source/RigidBodyStatic.h index 5301fdce08..3226cae836 100644 --- a/Gems/PhysX/Code/Source/RigidBodyStatic.h +++ b/Gems/PhysX/Code/Source/RigidBodyStatic.h @@ -26,8 +26,8 @@ namespace PhysX : public AzPhysics::StaticRigidBody { public: - AZ_CLASS_ALLOCATOR(StaticRigidBody, AZ::SystemAllocator, 0); - AZ_RTTI(StaticRigidBody, "{06E960EF-E1F3-466F-B34F-800E32775092}", AzPhysics::StaticRigidBody); + AZ_CLASS_ALLOCATOR_DECL; + AZ_RTTI(PhysX::StaticRigidBody, "{06E960EF-E1F3-466F-B34F-800E32775092}", AzPhysics::StaticRigidBody); StaticRigidBody() = default; StaticRigidBody(const AzPhysics::StaticRigidBodyConfiguration& configuration); diff --git a/Gems/PhysX/Code/Tests/PhysXCollisionFilteringTest.cpp b/Gems/PhysX/Code/Tests/PhysXCollisionFilteringTest.cpp index dec01392b8..421cf375d9 100644 --- a/Gems/PhysX/Code/Tests/PhysXCollisionFilteringTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXCollisionFilteringTest.cpp @@ -24,7 +24,6 @@ namespace PhysX { protected: const AZStd::string DefaultLayer = "Default"; - const AZStd::string TouchBendLayer = "TouchBend"; const AZStd::string LayerA = "LayerA"; const AZStd::string LayerB = "LayerB"; const AZStd::string GroupA = "GroupA"; @@ -42,7 +41,6 @@ namespace PhysX AZStd::vector TestCollisionLayers = { DefaultLayer, - TouchBendLayer, // This is needed here as placeholder as collision events are disabled on this layer. LayerA, LayerB }; diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp index 524b79b012..430733f3a1 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp @@ -73,6 +73,13 @@ namespace SceneBuilder required.emplace_back(AZ_CRC_CE("AssetImportRequestHandler")); } + void BuilderPluginComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + // Any components that can modify the analysis fingerprint via SceneBuilderDependencyRequests::AddFingerprintInfo must be activated first, + // so they contribute to the fingerprint calculated in BuilderPluginComponent::Activate(). + services.emplace_back(AZ_CRC_CE("FingerprintModification")); + } + void BuilderPluginComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h index b4eee64bc6..0bfe118a4c 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h @@ -29,6 +29,7 @@ namespace SceneBuilder void Deactivate() override; static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services); private: SceneBuilderWorker m_sceneBuilder; diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp index b4ae490e2c..c1a1252c6b 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderWorker.cpp @@ -67,6 +67,8 @@ namespace SceneBuilder context->EnumerateDerived(callback, azrtti_typeid(), azrtti_typeid()); context->EnumerateDerived(callback, azrtti_typeid(), azrtti_typeid()); } + + AZ::SceneAPI::SceneBuilderDependencyBus::Broadcast(&AZ::SceneAPI::SceneBuilderDependencyRequests::AddFingerprintInfo, fragments); for (const AZStd::string& element : fragments) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja index 5394ea2355..8bb72bb37f 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja @@ -197,7 +197,8 @@ void {{attribute_QualifiedName}}::Reflect(AZ::ReflectContext* context) {% if item.attrib['Description'] is defined %} {% set description = item.attrib['Description'] %} {% endif %} - // {{ item.attrib['Name'] }} + + // {{ item.attrib['Name'] }} {{preEdit}}->DataElement({{ uihandler }}, &{{ attribute_Name }}::{{ item.attrib['Name'] }}, "{{ item.attrib['Name'] }}", "{{ description }}"){{postEdit}} {% for EditAttribute in item.iter('EditAttribute') %} {{preEdit}}->Attribute({{ EditAttribute.attrib['Key'] }}, {{ EditAttribute.attrib['Value'] }}){{postEdit}} @@ -272,6 +273,9 @@ void Nodes::{{ nodeableNodeName }}::Reflect(AZ::ReflectContext* context) { {% if ExtendReflectionEdit is defined %}auto {{preEdit}} = {%endif%}editContext->Class<{{ nodeableNodeName }}>("{{ attribute_PreferredClassName }}", "{{ attribute_Description }}"){{postEdit}} {{preEdit}}->ClassElement(AZ::Edit::ClassElements::EditorData, ""){{postEdit}} +{% if attribute_Category is defined %} + {{preEdit}}->Attribute(AZ::Edit::Attributes::Category, "{{ attribute_Category }}"){{postEdit}} +{% endif %} {{preEdit}}->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly){{postEdit}} {{preEdit}}->Attribute(AZ::Edit::Attributes::AutoExpand, true){{postEdit}} ; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/CodeGen/NodeableCodegen.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/CodeGen/NodeableCodegen.h index c09386a5a9..3fdcbc0605 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/CodeGen/NodeableCodegen.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/CodeGen/NodeableCodegen.h @@ -11,345 +11,28 @@ #include #include + +/* + Any class that implements a nodeable AzAutoGen driver (i.e. *.ScriptCanvasNodeable.xml) + requires that the SCRIPTCANVAS_NODE macro be declared within its class declaration. + + Example: + + class CustomNode + : public ScriptCanvas::Nodeable + { + public: + SCRIPTCANVAS_NODE(CustomNode); + }; + + What will happen is that when AzAutoGen runs it will generate a preprocessor directive: + + SCRIPTCANVAS_NODE_CustomNode + + Which will define all of the node's boilerplate code and definitions. When CustomNode + is compiled, the preprocessor will replace the macro with the auto generated + code. +*/ + #define SCRIPTCANVAS_NODE(ClassName) SCRIPTCANVAS_NODE_##ClassName -/* ---------------------------------------------------------------------------------------------------------- -* -* BaseDefinition -* This tag must be included within the body of any custom nodeable class. It generates nodeable code only and it -* should be used as a base class only. -* -* Note: This tag does not generate a node class, so it will be hidden during edit time. -* -* Example: -* BaseDefinition(BaseHelloWorld, "Base Hello World", "My BaseHelloWorld.") -* -* ----------------------------------------------------------------------------------------------------------- */ -#define BaseDefinition(ClassName, Name, Description, ...) AZ_JOIN(AZ_GENERATED_, ClassName) - -/* ---------------------------------------------------------------------------------------------------------- -* -* NodeDefinition -* This tag must be included within the body of any custom nodeable class. It generates the necessary code to support nodes -* and customizes the serialization and reflection parameters(version, converter). -* -* Example: -* NodeDefinition(HelloWorld, "Hello World", "My HelloWorld Node.") -* NodeDefinition(HelloWorld, "Hello World", "My HelloWorld Node.", -* NodeTags::Icon("Icons/ScriptCanvas/HelloWorld.png") -* NodeTags::Version(3, VersionConverter)) -* -* ----------------------------------------------------------------------------------------------------------- */ -#define NodeDefinition(ClassName, Name, Description, ...) AZ_JOIN(AZ_GENERATED_, ClassName) - -/* ---------------------------------------------------------------------------------------------------------- -* InputMethod -* Using InputMethod on a method will create execution in&out slots that is invoked -* automatically. It will also allow the automatic generation of input or output data -* slots according to the method's signature. -* -* Example -* InputMethod("Do Something", "My DoSomething Function.") -* InputMethod("Do Something", "My DoSomething Function.") -* DataInput(int, "DoSomething:Arg", 0, "My DoSomething argument.") -* -* ----------------------------------------------------------------------------------------------------------- */ -#define InputMethod(Name, Description, ...) - -/* ---------------------------------------------------------------------------------------------------------- -* BranchMethod -* Using BranchMethod on a method will create execution input&output slots that is invoked -* automatically. It will also allow the automatic generation of input data -* slots according to the method's signature. BranchMethod should not be used on method -* having return type. -* -* Coupled with macro ExecutionOutput to generate branch out execution slots. -* -* Example -* BranchMethod("Branches", "My Branches Function.") -* ExecutionOutput("Branch1", "My Branch1 Function.", SlotTags::BranchOf("Branches")) -* ExecutionOutput("Branch2", "My Branch2 Function.", SlotTags::BranchOf("Branches")) -* -* ----------------------------------------------------------------------------------------------------------- */ -#define BranchMethod(Name, Description, ...) - -/* ---------------------------------------------------------------------------------------------------------- -* OnInputChangeMethod -* Using OnInputChangeMethod on a method will create one data input slot that is invoked -* automatically, and it should be used only with one input method. -* -* Example -* OnInputChangeMethod("MyInputChangeMethod", "My OnInputChange Function.") -* DataInput(int, "MyInputChangeMethod:Arg", 0, "My MyInputChangeMethod argument.", SlotTags::DisplayGroup("MyInputChangeMethod")) -* -* ----------------------------------------------------------------------------------------------------------- */ -#define OnInputChangeMethod(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* ExecutionInput -* This is a shorthand macro to easily create an execution input slot. -* -* Examples: -* ExecutionInput("Start Process", "Signals this node to begin processing.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define ExecutionInput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* ExecutionOutput -* This is a shorthand macro to easily create an execution output slot. -* -* Examples: -* ExecutionOutput("On Start Process", "Output of start process execution."); -* -* ---------------------------------------------------------------------------------------------------------- */ -#define ExecutionOutput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* ExecutionLatentOutput -* Similar to ExecutionOutput however it is used to make it explicit that the output slot will be latent, -* this means that the node maintains state and may not signal this slot immediately. -* -* Example: -* ExecutionLatentOutput("On Finished", "Will be signaled when the operation is complete."); -* -* ---------------------------------------------------------------------------------------------------------- */ -#define ExecutionLatentOutput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* Data -* Provides shorthand for exposing data to serialize context and edit context, -* mainly used with SlotTags::PropertyReference for property data. -* -* Example: -* int m_data = 1; -* PropertyData(int, "My Data", "My Serialized Data.", SlotTags::PropertyReference(m_data)); -* -* ---------------------------------------------------------------------------------------------------------- */ -#define PropertyData(Type, Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DataInput -* Provides shorthand for creating an input data slot. -* -* Coupled with macro InputMethod/BranchMethod/OnInputChangeMethod to give parameter editor definition -* -* Example: -* InputMethod("Do Something", "My DoSomething Function.") -* DataInput(int, "DoSomething:Arg", 0, "My DoSomething argument.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DataInput(Type, Name, DefaultVal, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DataOutput -* Provides shorthand for creating an output data slot. -* -* Coupled with macro InputMethod/BranchMethod/OnInputChangeMethod to give result editor definition -* -* Example: -* InputMethod("Do Something", "My DoSomething Function.") -* DataOutput(int, "DoSomething:Result", 0, "My DoSomething result.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DataOutput(Type, Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicValueDataInput -* Provides shorthand for creating an input dynamic value data slot. -* -* Examples: -* DynamicValueDataInput("ValueData", "A generic value data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicValueDataInput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicValueDataOutput -* Provides shorthand for creating an output dynamic value data slot. -* -* Examples: -* DynamicValueDataOutput("ValueData", "A generic value data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicValueDataOutput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicContainerDataInput -* Provides shorthand for creating an input dynamic container data slot. -* -* Coupled with macro ExecutionInput/ExecutionOutput/ExecutionLatentOutput to generate dynamic data input slot -* -* Examples: -* DynamicContainerDataInput("ContainerData", "A generic container data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicContainerDataInput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicContainerDataOutput -* Provides shorthand for creating an output dynamic container data slot. -* -* Coupled with macro ExecutionInput/ExecutionOutput/ExecutionLatentOutput to generate dynamic data output slot -* -* Examples: -* DynamicContainerDataOutput("ContainerData", "A generic container data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicContainerDataOutput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicAnyDataInput -* Provides shorthand for creating an input dynamic any data slot. -* -* Coupled with macro ExecutionInput/ExecutionOutput/ExecutionLatentOutput to generate dynamic data input slot -* -* Examples: -* DynamicAnyDataInput("AnyData", "A generic any data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicAnyDataInput(Name, Description, ...) - -/* -*---------------------------------------------------------------------------------------------------------- -* -* DynamicAnyDataOutput -* Provides shorthand for creating an output dynamic any data slot. -* -* Coupled with macro ExecutionInput/ExecutionOutput/ExecutionLatentOutput to generate dynamic data output slot -* -* Examples: -* DynamicAnyDataOutput("AnyData", "A generic any data.") -* -* ---------------------------------------------------------------------------------------------------------- */ -#define DynamicAnyDataOutput(Name, Description, ...) - -// Intellisense helpers, the following definitions exist to provide code completion details regarding what attributes are -// supported by the different tags. - -// Revisited common tags, we should be able to remove NodeableCodegen eventually -namespace NodeableCodegen -{ - namespace ScriptCanvasTags - { - using OverrideName = const char*; - using Uuid = const char*; - using Category = const char*; - using Icon = const char*; - using Deprecated = const char*; - - struct Version - { - using ConverterFunction = bool(class AZ::SerializeContext& context, class AZ::SerializeContext::DataElementNode& classElement); - Version(unsigned int /*version*/) {} - Version(unsigned int /*version*/, ConverterFunction /*converter*/) {} - }; - - template - struct EventHandler - { - EventHandler() = default; - }; - - namespace Edit - { - struct UIHandler - { - UIHandler([[maybe_unused]] const AZ::Crc32& uiHandler = AZ::Edit::UIHandlers::Default) {} - }; - } - - struct EditAttributes - { - template - EditAttributes(Args&& ... args) {} - }; - - struct BaseClass - { - BaseClass(AZStd::initializer_list) {} - }; - - //struct Contracts - //{ - // explicit Contracts(AZStd::initializer_list) {} - //}; - - //struct RestrictedTypeContractTag - //{ - // explicit RestrictedTypeContractTag(AZStd::initializer_list) {} - //}; - - struct SupportsMethodContractTag - { - explicit SupportsMethodContractTag(const char*) {} - }; - } -} - -namespace NodeTags -{ - using NodeableCodegen::ScriptCanvasTags::OverrideName; - using NodeableCodegen::ScriptCanvasTags::Uuid; - using NodeableCodegen::ScriptCanvasTags::Version; - using NodeableCodegen::ScriptCanvasTags::Icon; - using NodeableCodegen::ScriptCanvasTags::EditAttributes; - using NodeableCodegen::ScriptCanvasTags::Category; - using NodeableCodegen::ScriptCanvasTags::Deprecated; - - using GraphEntryPoint = bool; -} - -namespace SlotTags -{ - using NodeableCodegen::ScriptCanvasTags::OverrideName; - //using NodeableCodegen::ScriptCanvasTags::Contracts; - - // Data specific - using DisplayGroup = const char*; - - // PropertyData specific - using PropertyReference = const char*; - using PropertyInterface = const char*; - - // ExecutionSlot specific - using BranchOf = const char*; - - // EditContext specific - using NodeableCodegen::ScriptCanvasTags::EditAttributes; - using NodeableCodegen::ScriptCanvasTags::Edit::UIHandler; - using AzCommon::Attributes::ChangeNotify; - using AzCommon::Attributes::Visibility; - using AzCommon::Attributes::AutoExpand; - using AzCommon::Attributes::DescriptionTextOverride; - using AzCommon::Attributes::NameLabelOverride; - using AzCommon::Attributes::Min; - using AzCommon::Attributes::Max; - - // DynamicData specific - //using NodeableCodegen::ScriptCanvasTags::RestrictedTypeContractTag; - using NodeableCodegen::ScriptCanvasTags::SupportsMethodContractTag; - using DynamicGroup = const char*; -} diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp index 4eef54669a..35064bf4a4 100644 --- a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp +++ b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp @@ -10,7 +10,6 @@ #include #include #include -#include namespace SurfaceData { @@ -20,7 +19,6 @@ namespace SurfaceData SurfaceDataSystemComponent::CreateDescriptor(), SurfaceDataColliderComponent::CreateDescriptor(), SurfaceDataShapeComponent::CreateDescriptor(), - Terrain::TerrainSurfaceDataSystemComponent::CreateDescriptor(), }); } @@ -28,7 +26,6 @@ namespace SurfaceData { return AZ::ComponentTypeList{ azrtti_typeid(), - azrtti_typeid(), }; } } diff --git a/Gems/SurfaceData/Code/surfacedata_files.cmake b/Gems/SurfaceData/Code/surfacedata_files.cmake index 487dcb70e5..4b8ac914d7 100644 --- a/Gems/SurfaceData/Code/surfacedata_files.cmake +++ b/Gems/SurfaceData/Code/surfacedata_files.cmake @@ -19,8 +19,6 @@ set(FILES Include/SurfaceData/Utility/SurfaceDataUtility.h Source/SurfaceDataSystemComponent.cpp Source/SurfaceDataSystemComponent.h - Source/TerrainSurfaceDataSystemComponent.cpp - Source/TerrainSurfaceDataSystemComponent.h Source/SurfaceTag.cpp Source/Components/SurfaceDataColliderComponent.cpp Source/Components/SurfaceDataColliderComponent.h diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainHeight.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainHeight.svg new file mode 100644 index 0000000000..57835e9c20 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainHeight.svg @@ -0,0 +1,7 @@ + + + icon / Environmental / Terrain Height + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerRenderer.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerRenderer.svg new file mode 100644 index 0000000000..fb9590ae7b --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerRenderer.svg @@ -0,0 +1,7 @@ + + + icon / Environmental / Terrain Mesh + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerSpawner.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerSpawner.svg new file mode 100644 index 0000000000..df73d78276 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainLayerSpawner.svg @@ -0,0 +1,7 @@ + + + icon / Environmental / Generate Terrian + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorld.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorld.svg new file mode 100644 index 0000000000..c6388d6215 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorld.svg @@ -0,0 +1,8 @@ + + + icon / Environmental / Terrain Refactor + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldDebugger.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldDebugger.svg new file mode 100644 index 0000000000..bd1512afda --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldDebugger.svg @@ -0,0 +1,8 @@ + + + icon / Environmental / Terrain World Debugger + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldRenderer.svg b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldRenderer.svg new file mode 100644 index 0000000000..ab3716ad5d --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/TerrainWorldRenderer.svg @@ -0,0 +1,8 @@ + + + icon / Environmental / Terrain World Renderer + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainHeight.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainHeight.svg new file mode 100644 index 0000000000..b87a0b4d7e --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainHeight.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Terrain Height - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerRenderer.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerRenderer.svg new file mode 100644 index 0000000000..521d56784c --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerRenderer.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Terrain Mesh - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerSpawner.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerSpawner.svg new file mode 100644 index 0000000000..c078d32fe5 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainLayerSpawner.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Generate Terrian - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorld.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorld.svg new file mode 100644 index 0000000000..2aee65f2a8 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorld.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Terrain Refactor - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldDebugger.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldDebugger.svg new file mode 100644 index 0000000000..1b729ab73f --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldDebugger.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Terrain World Debugger - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg new file mode 100644 index 0000000000..4287508f10 --- /dev/null +++ b/Gems/Terrain/Assets/Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg @@ -0,0 +1,25 @@ + + + icon / Environmental / Terrain World Renderer - box + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Gems/Terrain/CMakeLists.txt b/Gems/Terrain/CMakeLists.txt new file mode 100644 index 0000000000..34bce0825f --- /dev/null +++ b/Gems/Terrain/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# 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 +# +# + +add_subdirectory(Code) diff --git a/Gems/Terrain/Code/CMakeLists.txt b/Gems/Terrain/Code/CMakeLists.txt new file mode 100644 index 0000000000..f40dd17ede --- /dev/null +++ b/Gems/Terrain/Code/CMakeLists.txt @@ -0,0 +1,139 @@ +# +# 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 +# +# + +ly_add_target( + NAME Terrain.Static STATIC + NAMESPACE Gem + FILES_CMAKE + terrain_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + Include + PRIVATE + Source + BUILD_DEPENDENCIES + PUBLIC + AZ::AzCore + AZ::AzFramework + Gem::Atom_RPI.Public + Gem::Atom_Utils.Static + Gem::GradientSignal + Gem::SurfaceData + Gem::LmbrCentral +) + +ly_add_target( + NAME Terrain ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} + NAMESPACE Gem + FILES_CMAKE + terrain_shared_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + Include + PRIVATE + Source + BUILD_DEPENDENCIES + PRIVATE + Gem::Terrain.Static + Gem::LmbrCentral + RUNTIME_DEPENDENCIES + Gem::LmbrCentral +) + +# the above module is for use in all client/server types +ly_create_alias(NAME Terrain.Servers NAMESPACE Gem TARGETS Gem::Terrain) +ly_create_alias(NAME Terrain.Clients NAMESPACE Gem TARGETS Gem::Terrain) + +# If we are on a host platform, we want to add the host tools targets like the Terrain.Editor target which +# will also depend on Terrain.Static +if(PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_target( + NAME Terrain.Editor MODULE + NAMESPACE Gem + AUTOMOC + OUTPUT_NAME Gem.Terrain.Editor + FILES_CMAKE + terrain_editor_shared_files.cmake + COMPILE_DEFINITIONS + PRIVATE + TERRAIN_EDITOR + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + AZ::AzToolsFramework + Gem::GradientSignal + Gem::LmbrCentral + Gem::Terrain.Static + ) + + # the above module is for use in dev tool situations + ly_create_alias(NAME Terrain.Builders NAMESPACE Gem TARGETS Gem::Terrain.Editor) + ly_create_alias(NAME Terrain.Tools NAMESPACE Gem TARGETS Gem::Terrain.Editor) +endif() + +################################################################################ +# Tests +################################################################################ +# See if globally, tests are supported +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + # We globally support tests, see if we support tests on this platform for Terrain.Static + if(PAL_TRAIT_TERRAIN_TEST_SUPPORTED) + # We support Terrain.Tests on this platform, add Terrain.Tests target which depends on Terrain.Static + ly_add_target( + NAME Terrain.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + terrain_files.cmake + terrain_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzFramework + Gem::Terrain.Static + ) + + # Add Terrain.Tests to googletest + ly_add_googletest( + NAME Gem::Terrain.Tests + ) + endif() + + # If we are a host platform we want to add tools test like editor tests here + if(PAL_TRAIT_BUILD_HOST_TOOLS) + # We are a host platform, see if Editor tests are supported on this platform + if(PAL_TRAIT_TERRAIN_EDITOR_TEST_SUPPORTED) + # We support Terrain.Editor.Tests on this platform, add Terrain.Editor.Tests target which depends on Terrain.Editor + ly_add_target( + NAME Terrain.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + terrain_editor_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + Gem::Terrain.Editor + ) + + # Add Terrain.Editor.Tests to googletest + ly_add_googletest( + NAME Gem::Terrain.Editor.Tests + ) + endif() + endif() +endif() diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp similarity index 96% rename from Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp rename to Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp index a60bbc4034..04c94b24d6 100644 --- a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include #include @@ -58,7 +58,7 @@ namespace Terrain editContext->Class("Terrain Surface Data System", "Manages surface data requests against legacy terrain") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Surface Data") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &TerrainSurfaceDataSystemComponent::m_configuration, "Configuration", "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) @@ -78,18 +78,18 @@ namespace Terrain void TerrainSurfaceDataSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e)); - services.push_back(AZ_CRC("TerrainSurfaceDataProviderService", 0xa1ac7717)); + services.push_back(AZ_CRC_CE("SurfaceDataProviderService")); + services.push_back(AZ_CRC_CE("TerrainSurfaceDataProviderService")); } void TerrainSurfaceDataSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("TerrainSurfaceDataProviderService", 0xa1ac7717)); + services.push_back(AZ_CRC_CE("TerrainSurfaceDataProviderService")); } void TerrainSurfaceDataSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("SurfaceDataSystemService", 0x1d44d25f)); + services.push_back(AZ_CRC_CE("SurfaceDataSystemService")); } void TerrainSurfaceDataSystemComponent::Activate() diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.h similarity index 100% rename from Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h rename to Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.h diff --git a/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.cpp new file mode 100644 index 0000000000..dea7babbbc --- /dev/null +++ b/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.cpp @@ -0,0 +1,68 @@ +/* + * 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 + +namespace Terrain +{ + void TerrainSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(0); + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("Terrain", "The Terrain System Component enables Terrain.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + } + } + } + + void TerrainSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("TerrainService")); + } + + void TerrainSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("TerrainService")); + } + + void TerrainSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("RPISystem")); + } + + void TerrainSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void TerrainSystemComponent::Init() + { + } + + void TerrainSystemComponent::Activate() + { + } + + void TerrainSystemComponent::Deactivate() + { + } +} diff --git a/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.h b/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.h new file mode 100644 index 0000000000..b294c0473a --- /dev/null +++ b/Gems/Terrain/Code/Source/Components/TerrainSystemComponent.h @@ -0,0 +1,40 @@ +/* + * 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 + +namespace Terrain +{ + class TerrainSystem; + + class TerrainSystemComponent + : public AZ::Component + { + public: + AZ_COMPONENT(TerrainSystemComponent, "{CD5A517E-3BD8-49AE-8F9B-33C6FC47EC67}"); + + static void Reflect(AZ::ReflectContext* context); + + 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); + + protected: + //////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Init() override; + void Activate() override; + void Deactivate() override; + //////////////////////////////////////////////////////////////////////// + + TerrainSystem* m_terrainSystem{ nullptr }; + }; +} diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.cpp b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.cpp new file mode 100644 index 0000000000..7fa35cc81c --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.cpp @@ -0,0 +1,32 @@ +/* + * 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 + +namespace Terrain +{ + void EditorTerrainSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class()->Version(1); + } + } + + void EditorTerrainSystemComponent::Activate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + } + + void EditorTerrainSystemComponent::Deactivate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + } + +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.h b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.h new file mode 100644 index 0000000000..274e561ace --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSystemComponent.h @@ -0,0 +1,43 @@ +/* + * 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 Terrain +{ + /// System component for Terrain editor + class EditorTerrainSystemComponent + : public AZ::Component + , private AzToolsFramework::EditorEvents::Bus::Handler + { + public: + AZ_COMPONENT(EditorTerrainSystemComponent, "{5E9f2200-9099-4325-BABD-6A533A1ABEA8}"); + static void Reflect(AZ::ReflectContext* context); + + EditorTerrainSystemComponent() = default; + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("TerrainEditorService")); + } + + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("TerrainService")); + } + + // AZ::Component + void Activate() override; + void Deactivate() override; + }; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/EditorTerrainModule.cpp b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp new file mode 100644 index 0000000000..bd4c94f4bf --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp @@ -0,0 +1,36 @@ +/* + * 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 + +namespace Terrain +{ + EditorTerrainModule::EditorTerrainModule() + { + m_descriptors.insert( + m_descriptors.end(), + { + Terrain::EditorTerrainSystemComponent::CreateDescriptor(), + }); + } + + AZ::ComponentTypeList EditorTerrainModule::GetRequiredSystemComponents() const + { + AZ::ComponentTypeList requiredComponents = TerrainModule::GetRequiredSystemComponents(); + requiredComponents.insert( + requiredComponents.end(), + { + azrtti_typeid(), + }); + + return requiredComponents; + } +} + +AZ_DECLARE_MODULE_CLASS(Gem_TerrainEditor, Terrain::EditorTerrainModule) diff --git a/Gems/Terrain/Code/Source/EditorTerrainModule.h b/Gems/Terrain/Code/Source/EditorTerrainModule.h new file mode 100644 index 0000000000..76c4706478 --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorTerrainModule.h @@ -0,0 +1,26 @@ +/* + * 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 + +namespace Terrain +{ + class EditorTerrainModule + : public TerrainModule + { + public: + AZ_RTTI(EditorTerrainModule, "{68693F28-7051-4C14-85EA-DE6FD8CFCBD6}", TerrainModule); + AZ_CLASS_ALLOCATOR(EditorTerrainModule, AZ::SystemAllocator, 0); + + EditorTerrainModule(); + + AZ::ComponentTypeList GetRequiredSystemComponents() const override; + }; +} diff --git a/Gems/Terrain/Code/Source/TerrainModule.cpp b/Gems/Terrain/Code/Source/TerrainModule.cpp new file mode 100644 index 0000000000..ec9325eb5c --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainModule.cpp @@ -0,0 +1,42 @@ +/* + * 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 + +namespace Terrain +{ + TerrainModule::TerrainModule() + : AZ::Module() + { + m_descriptors.insert(m_descriptors.end(), { + TerrainSystemComponent::CreateDescriptor(), + TerrainSurfaceDataSystemComponent::CreateDescriptor(), + }); + } + + AZ::ComponentTypeList TerrainModule::GetRequiredSystemComponents() const + { + return AZ::ComponentTypeList{ + azrtti_typeid(), + azrtti_typeid(), + }; + } +} + +#if !defined(TERRAIN_EDITOR) +// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM +// The first parameter should be GemName_GemIdLower +// The second should be the fully qualified name of the class above +AZ_DECLARE_MODULE_CLASS(Gem_Terrain, Terrain::TerrainModule) +#endif + diff --git a/Gems/Terrain/Code/Source/TerrainModule.h b/Gems/Terrain/Code/Source/TerrainModule.h new file mode 100644 index 0000000000..c665ee44eb --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainModule.h @@ -0,0 +1,26 @@ +/* + * 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 + +namespace Terrain +{ + class TerrainModule + : public AZ::Module + { + public: + AZ_RTTI(TerrainModule, "{B1CFB3A0-EA27-4AF0-A16D-E943C98FED88}", AZ::Module); + AZ_CLASS_ALLOCATOR(TerrainModule, AZ::SystemAllocator, 0); + + TerrainModule(); + + AZ::ComponentTypeList GetRequiredSystemComponents() const override; + }; +} diff --git a/Gems/Terrain/Code/Tests/TerrainEditorTest.cpp b/Gems/Terrain/Code/Tests/TerrainEditorTest.cpp new file mode 100644 index 0000000000..47492dfe40 --- /dev/null +++ b/Gems/Terrain/Code/Tests/TerrainEditorTest.cpp @@ -0,0 +1,31 @@ +/* + * 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 + +class TerrainEditorTest + : public ::testing::Test +{ +protected: + void SetUp() override + { + + } + + void TearDown() override + { + + } +}; + +TEST_F(TerrainEditorTest, SanityTest) +{ + ASSERT_TRUE(true); +} + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/Terrain/Code/Tests/TerrainTest.cpp b/Gems/Terrain/Code/Tests/TerrainTest.cpp new file mode 100644 index 0000000000..9b47c91a31 --- /dev/null +++ b/Gems/Terrain/Code/Tests/TerrainTest.cpp @@ -0,0 +1,31 @@ +/* + * 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 + +class TerrainTest + : public ::testing::Test +{ +protected: + void SetUp() override + { + + } + + void TearDown() override + { + + } +}; + +TEST_F(TerrainTest, SanityTest) +{ + ASSERT_TRUE(true); +} + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/Terrain/Code/terrain_editor_shared_files.cmake b/Gems/Terrain/Code/terrain_editor_shared_files.cmake new file mode 100644 index 0000000000..68ec9aeb54 --- /dev/null +++ b/Gems/Terrain/Code/terrain_editor_shared_files.cmake @@ -0,0 +1,16 @@ +# +# 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 +# +# + +set(FILES + Source/EditorComponents/EditorTerrainSystemComponent.cpp + Source/EditorComponents/EditorTerrainSystemComponent.h + Source/EditorTerrainModule.cpp + Source/EditorTerrainModule.h + Source/TerrainModule.cpp + Source/TerrainModule.h +) diff --git a/Gems/Terrain/Code/terrain_editor_tests_files.cmake b/Gems/Terrain/Code/terrain_editor_tests_files.cmake new file mode 100644 index 0000000000..d5d0ec5393 --- /dev/null +++ b/Gems/Terrain/Code/terrain_editor_tests_files.cmake @@ -0,0 +1,11 @@ +# +# 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 +# +# + +set(FILES + Tests/TerrainEditorTest.cpp +) diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake new file mode 100644 index 0000000000..c67d0c63b4 --- /dev/null +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -0,0 +1,14 @@ +# +# 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 +# +# + +set(FILES + Source/Components/TerrainSurfaceDataSystemComponent.cpp + Source/Components/TerrainSurfaceDataSystemComponent.h + Source/Components/TerrainSystemComponent.cpp + Source/Components/TerrainSystemComponent.h +) diff --git a/Gems/Terrain/Code/terrain_shared_files.cmake b/Gems/Terrain/Code/terrain_shared_files.cmake new file mode 100644 index 0000000000..211182b0fa --- /dev/null +++ b/Gems/Terrain/Code/terrain_shared_files.cmake @@ -0,0 +1,12 @@ +# +# 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 +# +# + +set(FILES + Source/TerrainModule.h + Source/TerrainModule.cpp +) diff --git a/Gems/Terrain/Code/terrain_tests_files.cmake b/Gems/Terrain/Code/terrain_tests_files.cmake new file mode 100644 index 0000000000..beed6bd83d --- /dev/null +++ b/Gems/Terrain/Code/terrain_tests_files.cmake @@ -0,0 +1,11 @@ +# +# 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 +# +# + +set(FILES + Tests/TerrainTest.cpp +) diff --git a/Gems/Terrain/gem.json b/Gems/Terrain/gem.json new file mode 100644 index 0000000000..ccf034d399 --- /dev/null +++ b/Gems/Terrain/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Terrain", + "display_name": "Terrain (WIP)", + "license": "Apache-2.0 Or MIT", + "origin": "Open 3D Engine - o3de.org", + "summary": "The Terrain Gem is a WIP (work-in-progress) Gem for providing terrain services including authoring workflows, rendering, and physics.", + "canonical_tags": [ "Gem" ], + "user_tags": [ "Environment", "Terrain" ], + "icon_path": "preview.png" +} diff --git a/Gems/Terrain/preview.png b/Gems/Terrain/preview.png new file mode 100644 index 0000000000..2f1ed47754 --- /dev/null +++ b/Gems/Terrain/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa +size 41127 diff --git a/Gems/Vegetation/Code/Source/VegetationSystemComponent.cpp b/Gems/Vegetation/Code/Source/VegetationSystemComponent.cpp index dd0e63c15b..345c27d27a 100644 --- a/Gems/Vegetation/Code/Source/VegetationSystemComponent.cpp +++ b/Gems/Vegetation/Code/Source/VegetationSystemComponent.cpp @@ -47,19 +47,24 @@ namespace Vegetation void VegetationSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("VegetationSystemService", 0xa2322728)); + services.push_back(AZ_CRC_CE("VegetationSystemService")); } void VegetationSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("VegetationSystemService", 0xa2322728)); + services.push_back(AZ_CRC_CE("VegetationSystemService")); } void VegetationSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services) { - services.push_back(AZ_CRC("VegetationAreaSystemService", 0x36da2b62)); - services.push_back(AZ_CRC("VegetationInstanceSystemService", 0x823a6007)); - services.push_back(AZ_CRC("SurfaceDataProviderService", 0xfe9fb95e)); + services.push_back(AZ_CRC_CE("VegetationAreaSystemService")); + services.push_back(AZ_CRC_CE("VegetationInstanceSystemService")); + services.push_back(AZ_CRC_CE("SurfaceDataSystemService")); + } + + void VegetationSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("SurfaceDataProviderService")); } void VegetationSystemComponent::Reflect(AZ::ReflectContext* context) diff --git a/Gems/Vegetation/Code/Source/VegetationSystemComponent.h b/Gems/Vegetation/Code/Source/VegetationSystemComponent.h index ff4ab17586..bbe92e2cf8 100644 --- a/Gems/Vegetation/Code/Source/VegetationSystemComponent.h +++ b/Gems/Vegetation/Code/Source/VegetationSystemComponent.h @@ -22,6 +22,7 @@ namespace Vegetation static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services); static void Reflect(AZ::ReflectContext* context); VegetationSystemComponent(); diff --git a/README.md b/README.md index a783139eef..1191a0f0ee 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ O3DE (Open 3D Engine) is an open-source, real-time, multi-platform 3D engine that enables developers and content creators to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations without any fees or commercial obligations. ## Contribute -For information about contributing to Open 3D Engine, visit https://o3de.org/docs/contributing/ +For information about contributing to Open 3D Engine, visit [https://o3de.org/docs/contributing/](https://o3de.org/docs/contributing/). ## Download and Install @@ -14,7 +14,7 @@ Verify you have Git LFS installed by running the following command to print the git lfs --version ``` -If Git LFS is not installed, download and run the installer from: https://git-lfs.github.com/. +If Git LFS is not installed, download and run the installer from: [https://git-lfs.github.com/](https://git-lfs.github.com/). ### Install Git LFS hooks ``` @@ -29,78 +29,100 @@ git clone https://github.com/o3de/o3de.git ``` ## Building the Engine -### Build Requirements and redistributables + +### Build requirements and redistributables + +For the latest details and system requirements, refer to [System Requirements](https://o3de.org/docs/welcome-guide/requirements/) in the documentation. + #### Windows -* Visual Studio 2019 16.9.2 minimum (All versions supported, including Community): [https://visualstudio.microsoft.com/downloads/](https://visualstudio.microsoft.com/downloads/) +* Visual Studio 2019 16.9.2 minimum (All editions supported, including Community): [https://visualstudio.microsoft.com/downloads/](https://visualstudio.microsoft.com/downloads/) + * Check [System Requirements](https://o3de.org/docs/welcome-guide/requirements/) for other supported versions. * Install the following workloads: * Game Development with C++ * MSVC v142 - VS 2019 C++ x64/x86 * C++ 2019 redistributable update -* CMake 3.20 minimum: [https://cmake.org/download/](https://cmake.org/download/) +* CMake 3.20.5 minimum: [https://cmake.org/download/](https://cmake.org/download/) #### Optional -* Wwise version 2021.1.1.7601 minimum: [https://www.audiokinetic.com/download/](https://www.audiokinetic.com/download/) - * Note: This requires registration and installation of a client application to download - * Note: It is generally okay to use a more recent version of Wwise, but some SDK updates will require code changes - * Make sure to select the `SDK(C++)` component during installation of Wwise - * CMake can find the Wwise install location in two ways: - * The `LY_WWISE_INSTALL_PATH` CMake cache variable -- this is checked first - * The `WWISEROOT` environment variable which is set when installing Wwise SDK +* Wwise audio SDK + * For the latest version requirements and setup instructions, refer to the [Wwise Audio Engine Gem](https://o3de.org/docs/user-guide/gems/reference/audio/wwise/audio-engine-wwise/) reference in the documentation. -### Quick Start Build Steps +### Quick start engine setup -1. Create a writable folder to cache 3rd Party dependencies. You can also use this to store other redistributable SDKs. +To set up a project-centric source engine, complete the following steps. For other build options, refer to [Setting up O3DE from GitHub](https://o3de.org/docs/welcome-guide/setup/setup-from-github/) in the documentation. + +1. Create a writable folder to cache downloadable third-party packages. You can also use this to store other redistributable SDKs. -1. Install the following redistributables to the following: - - Visual Studio and VC++ redistributable can be installed to any location - - CMake can be installed to any location, as long as it's available in the system path +1. Install the following redistributables: + - Visual Studio and VC++ redistributable can be installed to any location. + - CMake can be installed to any location, as long as it's available in the system path. -1. Configure the source into a solution using this command line, replacing and <3rdParty cache path> to a path you've created: +1. Configure the engine source into a solution using this command line, replacing ``, ``, and `<3rdParty package path>` with the paths you've created: ``` - cmake -B -S -G "Visual Studio 16" -DLY_3RDPARTY_PATH=<3rdParty cache path> -DLY_UNITY_BUILD=ON -DLY_PROJECTS=AutomatedTesting + cmake -B -S -G "Visual Studio 16" -DLY_3RDPARTY_PATH=<3rdParty package path> ``` - > Note: Do not use trailing slashes for the <3rdParty cache path> + + Example: + ``` + cmake -B C:\o3de\build\windows_vs2019 -S C:\o3de -G "Visual Studio 16" -DLY_3RDPARTY_PATH=C:\o3de-packages + ``` + + > Note: Do not use trailing slashes for the <3rdParty package path>. 1. Alternatively, you can do this through the CMake GUI: - 1. Start `cmake-gui.exe` - 1. Select the local path of the repo under "Where is the source code" - 1. Select a path where to build binaries under "Where to build the binaries" - 1. Click "Configure" - 1. Wait for the key values to populate. Fill in the fields that are relevant, including `LY_3RDPARTY_PATH` and `LY_PROJECTS` - 1. Click "Generate" + 1. Start `cmake-gui.exe`. + 1. Select the local path of the repo under "Where is the source code". + 1. Select a path where to build binaries under "Where to build the binaries". + 1. Click **Add Entry** and add a cache entry for the <3rdParty package path> folder you created, using the following values: + 1. **Name:** LY_3RDPARTY_PATH + 1. **Type:** STRING + 1. **Value:** `<3rdParty package path>` + 1. Click **Configure**. + 1. Wait for the key values to populate. Update or add any additional fields that are needed for your project. + 1. Click **Generate**. -1. The configuration of the solution is complete. To build the Editor and AssetProcessor to binaries, run this command inside your repo: - ``` - cmake --build --target AutomatedTesting.GameLauncher AssetProcessor Editor --config profile -- /m - ``` - -1. This will compile after some time and binaries will be available in the build path you've specified - -### Setting up new projects -1. While still within the repo folder, register the engine with this command: +1. Register the engine with this command: ``` scripts\o3de.bat register --this-engine ``` -1. Setup new projects using the `o3de create-project` command. + +1. The configuration of the solution is complete. You are now ready to create a project and build the engine. + +For more details on the steps above, refer to [Setting up O3DE from GitHub](https://o3de.org/docs/welcome-guide/setup/setup-from-github/) in the documentation. + +### Setting up new projects and building the engine + +1. From the O3DE repo folder, set up a new project using the `o3de create-project` command. ``` - \scripts\o3de.bat create-project --project-path + scripts\o3de.bat create-project --project-path ``` -1. Register the engine to the project - ``` - \scripts\o3de.bat register --project-path - ``` -1. Once you're ready to build the project, run the same set of commands to configure and build: + +1. Configure a solution for your project. ``` cmake -B -S -G "Visual Studio 16" -DLY_3RDPARTY_PATH=<3rdParty cache path> - - cmake --build --target .GameLauncher --config profile -- /m ``` - -For a tutorial on project configuration, see [Creating Projects Using the Command Line](https://docs.o3de.org/docs/welcome-guide/get-started/project-config/creating-projects-using-cli) in the documentation. + + Example: + ``` + cmake -B C:\my-project\build\windows_vs2019 -S C:\my-project -G "Visual Studio 16" -DLY_3RDPARTY_PATH=C:\o3de-packages + ``` + + > Note: Do not use trailing slashes for the <3rdParty cache path>. + +1. Build the project, Asset Processor, and Editor to binaries by running this command inside your project: + ``` + cmake --build --target .GameLauncher Editor --config profile -- /m + ``` + + > Note: Your project name used in the build target is the same as the directory name of your project. + +This will compile after some time and binaries will be available in the project build path you've specified, under `bin/profile`. + +For a complete tutorial on project configuration, see [Creating Projects Using the Command Line Interface](https://o3de.org/docs/welcome-guide/create/creating-projects-using-cli/) in the documentation. ## License -For terms please see the LICENSE*.TXT file at the root of this distribution. +For terms please see the LICENSE*.TXT files at the root of this distribution. diff --git a/Registry/sceneassetimporter.setreg b/Registry/sceneassetimporter.setreg index bd7c4d0705..6fef3a40dc 100644 --- a/Registry/sceneassetimporter.setreg +++ b/Registry/sceneassetimporter.setreg @@ -10,6 +10,11 @@ ".fbx", ".stl" ] + }, + "MaterialConverter": + { + "Enable": true, + "DefaultMaterial": "Materials/Presets/PBR/default_grid.material" } } } diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index ab7432e09e..a65e8b45e4 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -8,7 +8,7 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) -ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-multiplatform TARGETS RapidJSON PACKAGE_HASH 18b0aef4e6e849389916ff6de6682ab9c591ebe15af6ea6017014453c1119ea1) +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-r128-multiplatform TARGETS lz4 PACKAGE_HASH d7b1d5651191db2c339827ad24f669d9d37754143e9173abc986184532f57c9d) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 796e0beb32..7df364121b 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) -ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-multiplatform TARGETS RapidJSON PACKAGE_HASH 18b0aef4e6e849389916ff6de6682ab9c591ebe15af6ea6017014453c1119ea1) +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 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) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index ff222ee244..353956a495 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) -ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-multiplatform TARGETS RapidJSON PACKAGE_HASH 18b0aef4e6e849389916ff6de6682ab9c591ebe15af6ea6017014453c1119ea1) +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 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) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index e4fcc768c6..2aded62bcd 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) -ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-multiplatform TARGETS RapidJSON PACKAGE_HASH 18b0aef4e6e849389916ff6de6682ab9c591ebe15af6ea6017014453c1119ea1) +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 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) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index ac7a7427ca..c288460dd0 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -8,7 +8,7 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf) -ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-multiplatform TARGETS RapidJSON PACKAGE_HASH 18b0aef4e6e849389916ff6de6682ab9c591ebe15af6ea6017014453c1119ea1) +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-r128-multiplatform TARGETS lz4 PACKAGE_HASH d7b1d5651191db2c339827ad24f669d9d37754143e9173abc986184532f57c9d) diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index 08bb9f807e..b3e2093b65 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -6,4 +6,20 @@ # # -include(cmake/Platform/Common/Install_common.cmake) \ No newline at end of file +#! ly_install_code_function_override: Linux-specific copy function to handle RPATH fixes +set(ly_copy_template [[ +function(ly_copy source_file target_directory) + file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) + get_filename_component(target_filename_ext "${source_file}" LAST_EXT) + if("${source_file}" MATCHES "qt/plugins" AND "${target_filename_ext}" STREQUAL ".so") + get_filename_component(target_filename "${source_file}" NAME) + file(RPATH_CHANGE FILE "${target_directory}/${target_filename}" OLD_RPATH "\$ORIGIN/../../lib" NEW_RPATH "\$ORIGIN/..") + endif() +endfunction()]]) + +function(ly_install_code_function_override) + string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) + install(CODE "${ly_copy_function_linux}") +endfunction() + +include(cmake/Platform/Common/Install_common.cmake) diff --git a/engine.json b/engine.json index 29532347db..63bddc9548 100644 --- a/engine.json +++ b/engine.json @@ -76,6 +76,7 @@ "Gems/StartingPointInput", "Gems/StartingPointMovement", "Gems/SurfaceData", + "Gems/Terrain", "Gems/TestAssetBuilder", "Gems/TextureAtlas", "Gems/TickBusOrderViewer", diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 3d8c32f0f3..6231f9006d 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -338,6 +338,11 @@ def PreBuildCommonSteps(Map pipelineConfig, String snapshot, String repositoryNa else command += '.cmd' command += " -u ${pipelineConfig.BUILD_ENTRY_POINT} --platform ${platform} --type clean" palSh(command, "Running ${platform} clean") + + if(fileExists('.lfsconfig')) { + palSh("git lfs install", "LFS config exists. Installing LFS hooks to local repo") + palSh("git lfs pull", "Pulling new LFS objects") + } } }