diff --git a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py index d5a7acfe91..4aeff06f18 100644 --- a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py +++ b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py @@ -74,6 +74,7 @@ def update_manifest(scene): source_filename_only = os.path.basename(clean_filename) created_entities = [] + previous_entity_id = azlmbr.entity.InvalidEntityId # Loop every mesh node in the scene for activeMeshIndex in range(len(mesh_name_list)): @@ -102,14 +103,33 @@ def update_manifest(scene): # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel # The assetHint will be converted to an AssetId later during prefab loading json_update = json.dumps({ - "Controller": { "Configuration": { "ModelAsset": { - "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}} - }); + "Controller": { "Configuration": { "ModelAsset": { + "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}} + }); # Apply the JSON above to the component we created result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update) if not result: - raise RuntimeError("UpdateComponentForEntity failed") + raise RuntimeError("UpdateComponentForEntity failed for Mesh component") + + # Get the transform component + transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0") + + # Set this entity to be a child of the last entity we created + # This is just an example of how to do parenting and isn't necessarily useful to parent everything like this + if previous_entity_id is not None: + transform_json = json.dumps({ + "Parent Entity" : previous_entity_id.to_json() + }); + + # Apply the JSON update + result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json) + + if not result: + raise RuntimeError("UpdateComponentForEntity failed for Transform component") + + # Update the last entity id for next time + previous_entity_id = entity_id # Keep track of the entity we set up, we'll add them all to the prefab we're creating later created_entities.append(entity_id) @@ -147,6 +167,8 @@ def on_update_manifest(args): except RuntimeError as err: print (f'ERROR - {err}') log_exception_traceback() + except: + log_exception_traceback() global sceneJobHandler sceneJobHandler = None diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 447a4ebac9..c29a391be4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -71,5 +71,9 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module + @pytest.mark.test_case_id("C36525664") + class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py new file mode 100644 index 0000000000..d38e96739d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py @@ -0,0 +1,179 @@ +""" +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 +""" + +class Tests: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + postfx_gradient_weight_creation = ( + "PostFX Gradient Weight Modifier Entity successfully created", + "PostFX Gradient Weight Modifier Entity failed to be created") + postfx_gradient_weight_component = ( + "Entity has a PostFX Gradient Weight Modifier component", + "Entity failed to find PostFX Gradient Weight Modifier component") + postfx_gradient_weight_disabled = ( + "PostFX Gradient Weight Modifier component disabled", + "PostFX Gradient Weight Modifier component was not disabled.") + postfx_layer_component = ( + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") + postfx_gradient_weight_enabled = ( + "PostFX Gradient Weight Modifier component enabled", + "PostFX Gradient Weight Modifier component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): + """ + Summary: + Tests the PostFX Gradient Weight Modifier component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a PostFX Gradient Weight Modifier entity with no components. + 2) Add a PostFX Gradient Weight Modifier component to PostFX Gradient Weight Modifier entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify PostFX Gradient Weight Modifier component not enabled. + 6) Add PostFX Layer component since it is required by the PostFX Gradient Weight Modifier component. + 7) Verify PostFX Gradient Weight Modifier component is enabled. + 8) Enter/Exit game mode. + 9) Test IsHidden. + 10) Test IsVisible. + 11) Delete PostFX Gradient Weight Modifier entity. + 12) UNDO deletion. + 13) REDO deletion. + 14) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a PostFX Gradient Weight Modifier entity with no components. + postfx_gradient_weight_name = "PostFX Gradient Weight Modifier" + postfx_gradient_weight_entity = EditorEntity.create_editor_entity(postfx_gradient_weight_name) + Report.critical_result(Tests.postfx_gradient_weight_creation, postfx_gradient_weight_entity.exists()) + + # 2. Add a PostFX Gradient Weight Modifier component to PostFX Gradient Weight Modifier entity. + postfx_gradient_weight_component = postfx_gradient_weight_entity.add_component(postfx_gradient_weight_name) + Report.critical_result( + Tests.postfx_gradient_weight_component, + postfx_gradient_weight_entity.has_component(postfx_gradient_weight_name)) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not postfx_gradient_weight_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, postfx_gradient_weight_entity.exists()) + + # 5. Verify PostFX Gradient Weight Modifier component not enabled. + Report.result(Tests.postfx_gradient_weight_disabled, not postfx_gradient_weight_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the PostFX Gradient Weight Modifier component. + postfx_layer_name = "PostFX Layer" + postfx_gradient_weight_entity.add_component(postfx_layer_name) + Report.result(Tests.postfx_layer_component, postfx_gradient_weight_entity.has_component(postfx_layer_name)) + + # 7. Verify PostFX Gradient Weight Modifier component is enabled. + Report.result(Tests.postfx_gradient_weight_enabled, postfx_gradient_weight_component.is_enabled()) + + # 8. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 9. Test IsHidden. + postfx_gradient_weight_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, postfx_gradient_weight_entity.is_hidden() is True) + + # 10. Test IsVisible. + postfx_gradient_weight_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, postfx_gradient_weight_entity.is_visible() is True) + + # 11. Delete PostFX Gradient Weight Modifier entity. + postfx_gradient_weight_entity.delete() + Report.result(Tests.entity_deleted, not postfx_gradient_weight_entity.exists()) + + # 12. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, postfx_gradient_weight_entity.exists()) + + # 13. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not postfx_gradient_weight_entity.exists()) + + # 14. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity) diff --git a/Code/Editor/Core/QtEditorApplication_linux.cpp b/Code/Editor/Core/QtEditorApplication_linux.cpp index 2fd4ef629e..5491134170 100644 --- a/Code/Editor/Core/QtEditorApplication_linux.cpp +++ b/Code/Editor/Core/QtEditorApplication_linux.cpp @@ -19,10 +19,16 @@ namespace Editor if (GetIEditor()->IsInGameMode()) { #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB - AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message)); + // We need to handle RAW Input events in a separate loop. This is a workaround to enable XInput2 RAW Inputs using Editor mode. + // TODO To have this call here might be not be perfect. + AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::PollSpecialEvents); + + // Now handle the rest of the events. + AzFramework::XcbEventHandlerBus::Broadcast( + &AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message)); #endif return true; } return false; } -} +} // namespace Editor diff --git a/Code/Editor/EditorPreferencesDialog.cpp b/Code/Editor/EditorPreferencesDialog.cpp index c56df15908..a1859b0f14 100644 --- a/Code/Editor/EditorPreferencesDialog.cpp +++ b/Code/Editor/EditorPreferencesDialog.cpp @@ -264,6 +264,9 @@ void EditorPreferencesDialog::SetFilter(const QString& filter) else if (m_currentPageItem) { m_currentPageItem->UpdateEditorFilter(ui->propertyEditor, m_filter); + + // Refresh the Stylesheet - when using search functionality. + AzQtComponents::StyleManager::repolishStyleSheet(this); } } diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp index 7057cc5b7b..ee7e9a8e96 100644 --- a/Code/Editor/Objects/ObjectManager.cpp +++ b/Code/Editor/Objects/ObjectManager.cpp @@ -108,15 +108,11 @@ CObjectManager::CObjectManager() m_objectsByName.reserve(1024); LoadRegistry(); - - AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); } ////////////////////////////////////////////////////////////////////////// CObjectManager::~CObjectManager() { - AzToolsFramework::ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); - m_bExiting = true; SaveRegistry(); DeleteAllObjects(); @@ -2307,37 +2303,6 @@ void CObjectManager::SelectObjectInRect(CBaseObject* pObj, CViewport* view, HitC } } -void CObjectManager::OnEditorModeActivated( - [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) -{ - if (mode == AzToolsFramework::ViewportEditorMode::Component) - { - // hide current gizmo for entity (translate/rotate/scale) - IGizmoManager* gizmoManager = GetGizmoManager(); - const size_t gizmoCount = static_cast(gizmoManager->GetGizmoCount()); - for (size_t i = 0; i < gizmoCount; ++i) - { - gizmoManager->RemoveGizmo(gizmoManager->GetGizmoByIndex(static_cast(i))); - } - } -} - -void CObjectManager::OnEditorModeDeactivated( - [[maybe_unused]] const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) -{ - if (mode == AzToolsFramework::ViewportEditorMode::Component) - { - // show translate/rotate/scale gizmo again - if (IGizmoManager* gizmoManager = GetGizmoManager()) - { - if (CBaseObject* selectedObject = GetIEditor()->GetSelectedObject()) - { - gizmoManager->AddGizmo(new CAxisGizmo(selectedObject)); - } - } - } -} - ////////////////////////////////////////////////////////////////////////// namespace { diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h index 7fb2342e40..7389dfa6a1 100644 --- a/Code/Editor/Objects/ObjectManager.h +++ b/Code/Editor/Objects/ObjectManager.h @@ -20,7 +20,6 @@ #include "ObjectManagerEventBus.h" #include -#include #include #include #include @@ -59,7 +58,6 @@ public: */ class CObjectManager : public IObjectManager - , private AzToolsFramework::ViewportEditorModeNotificationsBus::Handler { public: //! Selection functor callback. @@ -330,12 +328,6 @@ private: void FindDisplayableObjects(DisplayContext& dc, bool bDisplay); - // ViewportEditorModeNotificationsBus overrides ... - void OnEditorModeActivated( - const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; - void OnEditorModeDeactivated( - const AzToolsFramework::ViewportEditorModesInterface& editorModeState, AzToolsFramework::ViewportEditorMode mode) override; - private: typedef std::map Objects; Objects m_objects; diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp index 9f207d9afd..79e1f79697 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.cpp +++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp @@ -225,8 +225,16 @@ namespace AZ ConsoleCommandContainer commandSubset; - for (ConsoleFunctorBase* curr = m_head; curr != nullptr; curr = curr->m_next) + for (const auto& functor : m_commands) { + if (functor.second.empty()) + { + continue; + } + + // Filter functors registered with the same name + const ConsoleFunctorBase* curr = functor.second.front(); + if ((curr->GetFlags() & ConsoleFunctorFlags::IsInvisible) == ConsoleFunctorFlags::IsInvisible) { // Filter functors marked as invisible @@ -236,7 +244,12 @@ namespace AZ if (StringFunc::StartsWith(curr->m_name, command, false)) { AZLOG_INFO("- %s : %s\n", curr->m_name, curr->m_desc); - commandSubset.push_back(curr->m_name); + + if (commandSubset.size() < MaxConsoleCommandPlusArgsLength) + { + commandSubset.push_back(curr->m_name); + } + if (matches) { matches->push_back(curr->m_name); @@ -271,7 +284,10 @@ namespace AZ { for (auto& curr : m_commands) { - visitor(curr.second.front()); + if (!curr.second.empty()) + { + visitor(curr.second.front()); + } } } @@ -336,6 +352,11 @@ namespace AZ { iter->second.erase(iter2); } + + if (iter->second.empty()) + { + m_commands.erase(iter); + } } functor->Unlink(m_head); functor->m_console = nullptr; diff --git a/Code/Framework/AzCore/AzCore/Debug/StackTracer.h b/Code/Framework/AzCore/AzCore/Debug/StackTracer.h index 430fd69168..2d09c16e99 100644 --- a/Code/Framework/AzCore/AzCore/Debug/StackTracer.h +++ b/Code/Framework/AzCore/AzCore/Debug/StackTracer.h @@ -40,6 +40,12 @@ namespace AZ static unsigned int Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned int suppressCount = 0, void* nativeThread = 0); }; + class StackConverter + { + public: + static unsigned int FromNative(StackFrame* frames, unsigned int maxNumOfFrames, void* nativeContext); + }; + class SymbolStorage { public: diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 3edcbaa273..cde8c36a4e 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -31,6 +31,8 @@ namespace AZ { namespace Debug { + struct StackFrame; + namespace Platform { #if defined(AZ_ENABLE_DEBUG_TOOLS) @@ -551,17 +553,19 @@ namespace AZ { StackFrame frames[25]; - // Without StackFrame explicit alignment frames array is aligned to 4 bytes - // which causes the stack tracing to fail. - //size_t bla = AZStd::alignment_of::value; - //printf("Alignment value %d address 0x%08x : 0x%08x\n",bla,frames); SymbolStorage::StackLine lines[AZ_ARRAY_SIZE(frames)]; + unsigned int numFrames = 0; if (!nativeContext) { - suppressCount += 1; /// If we don't provide a context we will capture in the RecordFunction, so skip us (Trace::PrinCallstack). + suppressCount += 1; /// If we don't provide a context we will capture in the RecordFunction, so skip us (Trace::PrintCallstack). + numFrames = StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), suppressCount); } - unsigned int numFrames = StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), suppressCount, nativeContext); + else + { + numFrames = StackConverter::FromNative(frames, AZ_ARRAY_SIZE(frames), nativeContext); + } + if (numFrames) { SymbolStorage::DecodeFrames(frames, numFrames, lines); diff --git a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp index 0c091a7242..a751eb505c 100644 --- a/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp +++ b/Code/Framework/AzCore/Platform/Common/Unimplemented/AzCore/Debug/StackTracer_Unimplemented.cpp @@ -17,6 +17,11 @@ namespace AZ return false; } + unsigned int StackConverter::FromNative(StackFrame*, unsigned int, void*) + { + return 0; + } + void SymbolStorage::LoadModuleData(const void*, unsigned int) {} diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp index f66a9d3b18..1948bbf2fe 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/StackTracer_UnixLike.cpp @@ -78,6 +78,12 @@ StackRecorder::Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned return count; } +unsigned int StackConverter::FromNative([[maybe_unused]] StackFrame* frames, [[maybe_unused]] unsigned int maxNumOfFrames, [[maybe_unused]] void* nativeContext) +{ + AZ_Assert(false, "StackConverter::FromNative() is not supported for UnixLike platform yet"); + return 0; +} + void SymbolStorage::DecodeFrames(const StackFrame* frames, unsigned int numFrames, StackLine* textLines) { diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index b2a1410bf5..90362a3ce8 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -1048,9 +1048,9 @@ cleanup: unsigned int StackRecorder::Record(StackFrame* frames, unsigned int maxNumOfFrames, unsigned int suppressCount, void* nativeThread) { -#if defined(AZ_ENABLE_DEBUG_TOOLS) unsigned int numFrames = 0; +#if defined(AZ_ENABLE_DEBUG_TOOLS) if (nativeThread == NULL) { ++suppressCount; // Skip current call @@ -1079,9 +1079,8 @@ cleanup: STACKFRAME64 sf; memset(&sf, 0, sizeof(STACKFRAME64)); - DWORD imageType; + DWORD imageType = IMAGE_FILE_MACHINE_AMD64; - imageType = IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset = context.Rip; sf.AddrPC.Mode = AddrModeFlat; sf.AddrFrame.Offset = context.Rsp; @@ -1090,8 +1089,7 @@ cleanup: sf.AddrStack.Mode = AddrModeFlat; EnterCriticalSection(&g_csDbgHelpDll); - s32 frame = -(s32)suppressCount; - for (; frame < (s32)maxNumOfFrames; ++frame) + for (s32 frame = -static_cast(suppressCount); frame < static_cast(maxNumOfFrames); ++frame) { if (!g_StackWalk64(imageType, g_currentProcess, hThread, &sf, &context, 0, g_SymFunctionTableAccess64, g_SymGetModuleBase64, 0)) { @@ -1111,15 +1109,68 @@ cleanup: } LeaveCriticalSection(&g_csDbgHelpDll); - } - return numFrames; + } #else - (void)frames; - (void)maxNumOfFrames; - (void)suppressCount; - (void)nativeThread; - return 0; + AZ_UNUSED(frames); + AZ_UNUSED(maxNumOfFrames); + AZ_UNUSED(suppressCount); + AZ_UNUSED(nativeThread); #endif // AZ_ENABLE_DEBUG_TOOLS + + return numFrames; + } + + unsigned int StackConverter::FromNative(StackFrame* frames, unsigned int maxNumOfFrames, void* nativeContext) + { + unsigned int numFrames = 0; + +#if defined(AZ_ENABLE_DEBUG_TOOLS) + if (!g_dbgHelpLoaded) + { + LoadDbgHelp(); + } + + HANDLE hThread; + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS); + + PCONTEXT nativeContextType = reinterpret_cast(nativeContext); + STACKFRAME64 sf; + memset(&sf, 0, sizeof(STACKFRAME64)); + + DWORD imageType = IMAGE_FILE_MACHINE_AMD64; + + sf.AddrPC.Offset = nativeContextType->Rip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrFrame.Offset = nativeContextType->Rsp; + sf.AddrFrame.Mode = AddrModeFlat; + sf.AddrStack.Offset = nativeContextType->Rsp; + sf.AddrStack.Mode = AddrModeFlat; + + EnterCriticalSection(&g_csDbgHelpDll); + for (unsigned int frame = 0; frame < maxNumOfFrames; ++frame) + { + if (!g_StackWalk64(imageType, g_currentProcess, hThread, &sf, nativeContext, 0, g_SymFunctionTableAccess64, g_SymGetModuleBase64, 0)) + { + break; + } + + if (sf.AddrPC.Offset == sf.AddrReturn.Offset) + { + // "StackWalk64-Endless-Callstack!" + break; + } + + frames[numFrames++].m_programCounter = sf.AddrPC.Offset; + } + + LeaveCriticalSection(&g_csDbgHelpDll); +#else + AZ_UNUSED(frames); + AZ_UNUSED(maxNumOfFrames); + AZ_UNUSED(nativeContext); +#endif + + return numFrames; } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp index b92dee44b6..c982868c4f 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Hashed.cpp @@ -1413,7 +1413,7 @@ namespace UnitTest >; TYPED_TEST_CASE(HashedSetDifferentAllocatorFixture, SetTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(HashedSetDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1435,7 +1435,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST template class HashedMapContainers @@ -1811,7 +1811,7 @@ namespace UnitTest >; TYPED_TEST_CASE(HashedMapDifferentAllocatorFixture, MapTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(HashedMapDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1833,7 +1833,7 @@ namespace UnitTest } } , ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST namespace HashedContainerTransparentTestInternal { diff --git a/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp b/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp index ca7d5cba42..26838eeb63 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Ordered.cpp @@ -1095,7 +1095,7 @@ namespace UnitTest >; TYPED_TEST_CASE(TreeSetDifferentAllocatorFixture, SetTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(TreeSetDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1117,7 +1117,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST TYPED_TEST(TreeSetDifferentAllocatorFixture, SwapMovesElementsWhenAllocatorsDiffer) { @@ -1516,7 +1516,7 @@ namespace UnitTest >; TYPED_TEST_CASE(TreeMapDifferentAllocatorFixture, MapTemplateConfigs); -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TYPED_TEST(TreeMapDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages) { using ContainerType = typename TypeParam::ContainerType; @@ -1538,7 +1538,7 @@ namespace UnitTest } }, ".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST TYPED_TEST(TreeMapDifferentAllocatorFixture, SwapMovesElementsWhenAllocatorsDiffer) { diff --git a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp index 407cd3c258..6b9202133c 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp @@ -1595,7 +1595,7 @@ namespace UnitTest } }; -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST TEST_F(ThreadEventsDeathTest, UsingClientBus_AvoidsDeadlock) { EXPECT_EXIT( @@ -1608,5 +1608,5 @@ namespace UnitTest , ::testing::ExitedWithCode(0),".*"); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST } diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index 3e6376323c..e33dbce9c1 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -736,7 +736,10 @@ namespace UnitTest auto& assetManager = AssetManager::Instance(); AssetBusCallbacks callbacks{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning callbacks.SetOnAssetReadyCallback([&, AssetNoRefB](const Asset&, AssetBusCallbacks&) + AZ_POP_DISABLE_WARNING { // This callback should run inside the "main thread" dispatch events loop auto loadAsset = assetManager.GetAsset(AZ::Uuid(AssetNoRefB), AssetLoadBehavior::Default); diff --git a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp index d91ec5ba58..e01129a7bc 100644 --- a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp +++ b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp @@ -288,6 +288,21 @@ namespace AZ AZStd::string completeCommand = console->AutoCompleteCommand("testVec3"); AZ_TEST_ASSERT(completeCommand == "testVec3"); } + + // Duplicate names + { + // Register two cvars with the same name + auto id = AZ::TypeId(); + auto flag = AZ::ConsoleFunctorFlags::Null; + auto signature = AZ::ConsoleFunctor::FunctorSignature(); + AZ::ConsoleFunctor cvarOne(*console, "testAutoCompleteDuplication", "", flag, id, signature); + AZ::ConsoleFunctor cvarTwo(*console, "testAutoCompleteDuplication", "", flag, id, signature); + + // Autocomplete given name expecting one match (not two) + AZStd::vector matches; + AZStd::string completeCommand = console->AutoCompleteCommand("testAutoCompleteD", &matches); + AZ_TEST_ASSERT(matches.size() == 1 && completeCommand == "testAutoCompleteDuplication"); + } } TEST_F(ConsoleTests, ConsoleFunctor_FreeFunctorExecutionTest) diff --git a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp index 242ac0e65d..d4b3351dbe 100644 --- a/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp +++ b/Code/Framework/AzCore/Tests/Debug/LocalFileEventLoggerTests.cpp @@ -109,7 +109,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &messages]() + AZ_POP_DISABLE_WARNING { while (!startLogging) { @@ -226,7 +229,10 @@ namespace AZ::Debug AZStd::thread threads[totalThreads]; for (size_t threadIndex = 0; threadIndex < totalThreads; ++threadIndex) { + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning threads[threadIndex] = AZStd::thread([&startLogging, &message, &totalRecordsWritten]() + AZ_POP_DISABLE_WARNING { AZ_UNUSED(message); diff --git a/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp b/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.cpp new file mode 100644 index 0000000000..cd9055085f --- /dev/null +++ b/Code/Framework/AzCore/Tests/Debug/UnhandledExceptions.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 + +namespace UnitTest +{ + class UnhandledExceptions + : public ScopedAllocatorSetupFixture + { + + public: + void causeAccessViolation() + { + int* someVariable = reinterpret_cast(0); + *someVariable = 0; + } + }; + +#if GTEST_HAS_DEATH_TEST + TEST_F(UnhandledExceptions, Handle) + { + EXPECT_DEATH(causeAccessViolation(), ""); + } +#endif +} diff --git a/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp b/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp index b4f129bb48..09255ce16f 100644 --- a/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp +++ b/Code/Framework/AzCore/Tests/Memory/LeakDetection.cpp @@ -144,14 +144,13 @@ namespace UnitTest } }; -#if GTEST_OS_SUPPORTS_DEATH_TEST - // SPEC-2669: Disabled since it is causing hangs on Linux +#if GTEST_HAS_DEATH_TEST TEST_F(AllocatorsTestFixtureLeakDetectionDeathTest_SKIPCODECOVERAGE, AllocatorLeak) { // testing that the TraceBusHook will fail on cause the test to die EXPECT_DEATH(TestAllocatorLeak(), ""); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Testing ScopedAllocatorSetupFixture. Testing that detects leaks diff --git a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp index 22fb6379d2..e312e2058d 100644 --- a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp @@ -597,7 +597,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer.get(), fileSize, path, 0, fileSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&fileSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -639,7 +642,10 @@ namespace AZ::IO path.InitFromAbsolutePath(m_dummyFilepath); request->CreateRead(nullptr, buffer, unalignedSize + 4, path, unalignedOffset, unalignedSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [unalignedOffset, unalignedSize, this](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -784,7 +790,10 @@ namespace AZ::IO requests[i] = m_context->GetNewInternalRequest(); requests[i]->CreateRead(nullptr, buffers[i].get(), chunkSize, path, i * chunkSize, chunkSize); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [chunkSize, i](const FileRequest& request) + AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); auto& readRequest = AZStd::get(request.GetCommand()); @@ -970,7 +979,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &numCallbacks, &waitForReads](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { IStreamer* streamer = Interface::Get(); if (streamer) @@ -1038,7 +1050,10 @@ namespace AZ::IO i * chunkSize )); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [numChunks, &waitForReads, &waitForSingleRead, &numReadCallbacks]([[maybe_unused]] FileRequestHandle request) + AZ_POP_DISABLE_WARNING { numReadCallbacks++; if (numReadCallbacks == 1) @@ -1059,7 +1074,10 @@ namespace AZ::IO for (size_t i = 0; i < numChunks; ++i) { cancels.push_back(m_streamer->Cancel(requests[numChunks - i - 1])); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [&numCancelCallbacks, &waitForCancels, numChunks](FileRequestHandle request) + AZ_POP_DISABLE_WARNING { auto result = Interface::Get()->GetRequestStatus(request); EXPECT_EQ(result, IStreamerTypes::RequestStatus::Completed); diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp index cc4d31eca9..9d4af1def5 100644 --- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp +++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonRegistrationContextTests.cpp @@ -327,7 +327,7 @@ namespace JsonSerializationTests SerializerWithOneType::Unreflect(m_jsonRegistrationContext.get()); } -#if GTEST_OS_SUPPORTS_DEATH_TEST +#if GTEST_HAS_DEATH_TEST using JsonSerializationDeathTests = JsonRegistrationContextTests; TEST_F(JsonSerializationDeathTests, DoubleUnregisterSerializer_Asserts) { @@ -338,5 +338,6 @@ namespace JsonSerializationTests }, ".*" ); } -#endif // GTEST_OS_SUPPORTS_DEATH_TEST +#endif // GTEST_HAS_DEATH_TEST + } //namespace JsonSerializationTests diff --git a/Code/Framework/AzCore/Tests/StringFunc.cpp b/Code/Framework/AzCore/Tests/StringFunc.cpp index 68821ba3f9..dc4bc40e5b 100644 --- a/Code/Framework/AzCore/Tests/StringFunc.cpp +++ b/Code/Framework/AzCore/Tests/StringFunc.cpp @@ -363,7 +363,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex{}; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { @@ -389,7 +392,10 @@ namespace AZ { constexpr AZStd::array visitTokens = { "Hello", "World", "", "More", "", "", "Tokens" }; size_t visitIndex = visitTokens.size() - 1; + AZ_PUSH_DISABLE_WARNING(5233, "-Wunknown-warning-option") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto visitor = [&visitIndex, &visitTokens](AZStd::string_view token) + AZ_POP_DISABLE_WARNING { if (visitIndex > visitTokens.size()) { diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index 6ba9944f7d..cc6000209f 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -72,6 +72,7 @@ set(FILES Debug/AssetTracking.cpp Debug/LocalFileEventLoggerTests.cpp Debug/Trace.cpp + Debug/UnhandledExceptions.cpp Name/NameJsonSerializerTests.cpp Name/NameTests.cpp RTTI/TypeSafeIntegralTests.cpp diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h index c6307755a7..251342093a 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h @@ -23,10 +23,12 @@ namespace AzFramework virtual ~XcbEventHandler() = default; virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0; + + // ATTN This is used as a workaround for RAW Input events when using the Editor. + virtual void PollSpecialEvents(){}; }; - class XcbEventHandlerBusTraits - : public AZ::EBusTraits + class XcbEventHandlerBusTraits : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp new file mode 100644 index 0000000000..56f21e6533 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.cpp @@ -0,0 +1,652 @@ +/* + * 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 + +namespace AzFramework +{ + xcb_window_t GetSystemCursorFocusWindow() + { + void* systemCursorFocusWindow = nullptr; + AzFramework::InputSystemCursorConstraintRequestBus::BroadcastResult( + systemCursorFocusWindow, &AzFramework::InputSystemCursorConstraintRequests::GetSystemCursorConstraintWindow); + + if (!systemCursorFocusWindow) + { + return XCB_NONE; + } + + // TODO Clang compile error because cast .... loses information. On GNU/Linux HWND is void* and on 64-bit + // machines its obviously 64 bit but we receive the window id from m_renderOverlay.winId() which is xcb_window_t 32-bit. + + return static_cast(reinterpret_cast(systemCursorFocusWindow)); + } + + xcb_connection_t* XcbInputDeviceMouse::s_xcbConnection = nullptr; + xcb_screen_t* XcbInputDeviceMouse::s_xcbScreen = nullptr; + bool XcbInputDeviceMouse::m_xfixesInitialized = false; + bool XcbInputDeviceMouse::m_xInputInitialized = false; + + XcbInputDeviceMouse::XcbInputDeviceMouse(InputDeviceMouse& inputDevice) + : InputDeviceMouse::Implementation(inputDevice) + , m_systemCursorState(SystemCursorState::Unknown) + , m_systemCursorPositionNormalized(0.5f, 0.5f) + , m_prevConstraintWindow(XCB_NONE) + , m_focusWindow(XCB_NONE) + , m_cursorShown(true) + { + XcbEventHandlerBus::Handler::BusConnect(); + + SetSystemCursorState(SystemCursorState::Unknown); + } + + XcbInputDeviceMouse::~XcbInputDeviceMouse() + { + XcbEventHandlerBus::Handler::BusDisconnect(); + + SetSystemCursorState(SystemCursorState::Unknown); + } + + InputDeviceMouse::Implementation* XcbInputDeviceMouse::Create(InputDeviceMouse& inputDevice) + { + auto* interface = AzFramework::XcbConnectionManagerInterface::Get(); + if (!interface) + { + AZ_Warning("XcbInput", false, "XCB interface not available"); + return nullptr; + } + + s_xcbConnection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection(); + if (!s_xcbConnection) + { + AZ_Warning("XcbInput", false, "XCB connection not available"); + return nullptr; + } + + const xcb_setup_t* xcbSetup = xcb_get_setup(s_xcbConnection); + s_xcbScreen = xcb_setup_roots_iterator(xcbSetup).data; + if (!s_xcbScreen) + { + AZ_Warning("XcbInput", false, "XCB screen not available"); + return nullptr; + } + + // Initialize XFixes extension which we use to create pointer barriers. + if (!InitializeXFixes()) + { + AZ_Warning("XcbInput", false, "XCB XFixes initialization failed"); + return nullptr; + } + + // Initialize XInput extension which is used to get RAW Input events. + if (!InitializeXInput()) + { + AZ_Warning("XcbInput", false, "XCB XInput initialization failed"); + return nullptr; + } + + return aznew XcbInputDeviceMouse(inputDevice); + } + + bool XcbInputDeviceMouse::IsConnected() const + { + return true; + } + + void XcbInputDeviceMouse::CreateBarriers(xcb_window_t window, bool create) + { + // Don't create any barriers if we are debugging. This will cause artifacts but better then + // a confined cursor during debugging. + if (AZ::Debug::Trace::IsDebuggerPresent()) + { + AZ_Warning("XcbInput", false, "Debugger running. Barriers will not be created."); + return; + } + + if (create) + { + // Destroy barriers if they are active already. + if (!m_activeBarriers.empty()) + { + for (const auto& barrier : m_activeBarriers) + { + xcb_xfixes_delete_pointer_barrier_checked(s_xcbConnection, barrier.id); + } + + m_activeBarriers.clear(); + } + + // Get window information. + const XcbStdFreePtr xcbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xcbGeometryReply) + { + return; + } + + const xcb_translate_coordinates_cookie_t translate_coord = + xcb_translate_coordinates(s_xcbConnection, window, s_xcbScreen->root, 0, 0); + + const XcbStdFreePtr xkbTranslateCoordReply{ xcb_translate_coordinates_reply( + s_xcbConnection, translate_coord, NULL) }; + + if (!xkbTranslateCoordReply) + { + return; + } + + const int16_t x0 = xkbTranslateCoordReply->dst_x < 0 ? 0 : xkbTranslateCoordReply->dst_x; + const int16_t y0 = xkbTranslateCoordReply->dst_y < 0 ? 0 : xkbTranslateCoordReply->dst_y; + const int16_t x1 = xkbTranslateCoordReply->dst_x + xcbGeometryReply->width; + const int16_t y1 = xkbTranslateCoordReply->dst_y + xcbGeometryReply->height; + + // ATTN For whatever reason, when making an exact rectangle the pointer will escape the top right corner in some cases. Adding + // an offset to the lines so that they cross each other prevents that. + const int16_t offset = 30; + + // Create the left barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_POSITIVE_X, x0, Clamp(y0 - offset), + x0, Clamp(y1 + offset) }); + + // Create the right barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_NEGATIVE_X, x1, Clamp(y0 - offset), + x1, Clamp(y1 + offset) }); + + // Create the top barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_POSITIVE_Y, Clamp(x0 - offset), y0, + Clamp(x1 + offset), y0 }); + + // Create the bottom barrier info. + m_activeBarriers.push_back({ xcb_generate_id(s_xcbConnection), XCB_XFIXES_BARRIER_DIRECTIONS_NEGATIVE_Y, Clamp(x0 - offset), y1, + Clamp(x1 + offset), y1 }); + + // Create the xfixes barriers. + for (const auto& barrier : m_activeBarriers) + { + xcb_void_cookie_t cookie = xcb_xfixes_create_pointer_barrier_checked( + s_xcbConnection, barrier.id, window, barrier.x0, barrier.y0, barrier.x1, barrier.y1, barrier.direction, 0, NULL); + const XcbStdFreePtr xkbError{ xcb_request_check(s_xcbConnection, cookie) }; + + AZ_Warning( + "XcbInput", !xkbError, "XFixes, failed to create barrier %d at (%d %d %d %d)", barrier.id, barrier.x0, barrier.y0, + barrier.x1, barrier.y1); + } + } + else + { + for (const auto& barrier : m_activeBarriers) + { + xcb_xfixes_delete_pointer_barrier_checked(s_xcbConnection, barrier.id); + } + + m_activeBarriers.clear(); + } + + xcb_flush(s_xcbConnection); + } + + bool XcbInputDeviceMouse::InitializeXFixes() + { + m_xfixesInitialized = false; + + // We don't have to free query_extension_reply according to xcb documentation. + const xcb_query_extension_reply_t* query_extension_reply = xcb_get_extension_data(s_xcbConnection, &xcb_xfixes_id); + if (!query_extension_reply || !query_extension_reply->present) + { + return m_xfixesInitialized; + } + + const xcb_xfixes_query_version_cookie_t query_cookie = xcb_xfixes_query_version(s_xcbConnection, 5, 0); + + xcb_generic_error_t* error = NULL; + const XcbStdFreePtr xkbQueryRequestReply{ xcb_xfixes_query_version_reply( + s_xcbConnection, query_cookie, &error) }; + + if (!xkbQueryRequestReply || error) + { + if (error) + { + AZ_Warning("XcbInput", false, "Retrieving XFixes version failed : Error code %d", error->error_code); + free(error); + } + return m_xfixesInitialized; + } + else if (xkbQueryRequestReply->major_version < 5) + { + AZ_Warning("XcbInput", false, "XFixes version fails the minimum version check (%d<5)", xkbQueryRequestReply->major_version); + return m_xfixesInitialized; + } + + m_xfixesInitialized = true; + + return m_xfixesInitialized; + } + + bool XcbInputDeviceMouse::InitializeXInput() + { + m_xInputInitialized = false; + + // We don't have to free query_extension_reply according to xcb documentation. + const xcb_query_extension_reply_t* query_extension_reply = xcb_get_extension_data(s_xcbConnection, &xcb_input_id); + if (!query_extension_reply || !query_extension_reply->present) + { + return m_xInputInitialized; + } + + const xcb_input_xi_query_version_cookie_t query_version_cookie = xcb_input_xi_query_version(s_xcbConnection, 2, 2); + + xcb_generic_error_t* error = NULL; + const XcbStdFreePtr xkbQueryRequestReply{ xcb_input_xi_query_version_reply( + s_xcbConnection, query_version_cookie, &error) }; + + if (!xkbQueryRequestReply || error) + { + if (error) + { + AZ_Warning("XcbInput", false, "Retrieving XInput version failed : Error code %d", error->error_code); + free(error); + } + return m_xInputInitialized; + } + else if (xkbQueryRequestReply->major_version < 2) + { + AZ_Warning("XcbInput", false, "XInput version fails the minimum version check (%d<5)", xkbQueryRequestReply->major_version); + return m_xInputInitialized; + } + + m_xInputInitialized = true; + + return m_xInputInitialized; + } + + void XcbInputDeviceMouse::SetEnableXInput(bool enable) + { + struct + { + xcb_input_event_mask_t head; + int mask; + } mask; + + mask.head.deviceid = XCB_INPUT_DEVICE_ALL; + mask.head.mask_len = 1; + + if (enable) + { + mask.mask = XCB_INPUT_XI_EVENT_MASK_RAW_MOTION | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS | + XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE | XCB_INPUT_XI_EVENT_MASK_MOTION | XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS | + XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE; + } + else + { + mask.mask = XCB_NONE; + } + + xcb_input_xi_select_events(s_xcbConnection, s_xcbScreen->root, 1, &mask.head); + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::SetSystemCursorState(SystemCursorState systemCursorState) + { + if (systemCursorState != m_systemCursorState) + { + m_systemCursorState = systemCursorState; + + m_focusWindow = GetSystemCursorFocusWindow(); + + HandleCursorState(m_focusWindow, systemCursorState); + } + } + + void XcbInputDeviceMouse::HandleCursorState(xcb_window_t window, SystemCursorState systemCursorState) + { + bool confined = false, cursorShown = true; + switch (systemCursorState) + { + case SystemCursorState::ConstrainedAndHidden: + { + //!< Constrained to the application's main window and hidden + confined = true; + cursorShown = false; + } + break; + case SystemCursorState::ConstrainedAndVisible: + { + //!< Constrained to the application's main window and visible + confined = true; + } + break; + case SystemCursorState::UnconstrainedAndHidden: + { + //!< Free to move outside the main window but hidden while inside + cursorShown = false; + } + break; + case SystemCursorState::UnconstrainedAndVisible: + { + //!< Free to move outside the application's main window and visible + } + case SystemCursorState::Unknown: + default: + break; + } + + // ATTN GetSystemCursorFocusWindow when getting out of the play in editor will return XCB_NONE + // We need however the window id to reset the cursor. + if (XCB_NONE == window && (confined || cursorShown)) + { + // Reuse the previous window to reset states. + window = m_prevConstraintWindow; + m_prevConstraintWindow = XCB_NONE; + } + else + { + // Remember the window we used to modify cursor and barrier states. + m_prevConstraintWindow = window; + } + + SetEnableXInput(!cursorShown); + + CreateBarriers(window, confined); + ShowCursor(window, cursorShown); + } + + SystemCursorState XcbInputDeviceMouse::GetSystemCursorState() const + { + return m_systemCursorState; + } + + void XcbInputDeviceMouse::SetSystemCursorPositionNormalizedInternal(xcb_window_t window, AZ::Vector2 positionNormalized) + { + // TODO Basically not done at all. Added only the basic functions needed. + const XcbStdFreePtr xkbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xkbGeometryReply) + { + return; + } + + const int16_t x = static_cast(positionNormalized.GetX() * xkbGeometryReply->width); + const int16_t y = static_cast(positionNormalized.GetY() * xkbGeometryReply->height); + + xcb_warp_pointer(s_xcbConnection, XCB_NONE, window, 0, 0, 0, 0, x, y); + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::SetSystemCursorPositionNormalized(AZ::Vector2 positionNormalized) + { + const xcb_window_t window = GetSystemCursorFocusWindow(); + if (XCB_NONE == window) + { + return; + } + + SetSystemCursorPositionNormalizedInternal(window, positionNormalized); + } + + AZ::Vector2 XcbInputDeviceMouse::GetSystemCursorPositionNormalizedInternal(xcb_window_t window) const + { + AZ::Vector2 position = AZ::Vector2::CreateZero(); + + const xcb_query_pointer_cookie_t pointer = xcb_query_pointer(s_xcbConnection, window); + + const XcbStdFreePtr xkbQueryPointerReply{ xcb_query_pointer_reply(s_xcbConnection, pointer, NULL) }; + + if (!xkbQueryPointerReply) + { + return position; + } + + const XcbStdFreePtr xkbGeometryReply{ xcb_get_geometry_reply( + s_xcbConnection, xcb_get_geometry(s_xcbConnection, window), NULL) }; + + if (!xkbGeometryReply) + { + return position; + } + + AZ_Assert(xkbGeometryReply->width != 0, "xkbGeometry response width must be non-zero. (%d)", xkbGeometryReply->width); + const float normalizedCursorPostionX = static_cast(xkbQueryPointerReply->win_x) / xkbGeometryReply->width; + + AZ_Assert(xkbGeometryReply->height != 0, "xkbGeometry response height must be non-zero. (%d)", xkbGeometryReply->height); + const float normalizedCursorPostionY = static_cast(xkbQueryPointerReply->win_y) / xkbGeometryReply->height; + + position = AZ::Vector2(normalizedCursorPostionX, normalizedCursorPostionY); + + return position; + } + + AZ::Vector2 XcbInputDeviceMouse::GetSystemCursorPositionNormalized() const + { + const xcb_window_t window = GetSystemCursorFocusWindow(); + if (XCB_NONE == window) + { + return AZ::Vector2::CreateZero(); + } + + return GetSystemCursorPositionNormalizedInternal(window); + } + + void XcbInputDeviceMouse::TickInputDevice() + { + ProcessRawEventQueues(); + } + + void XcbInputDeviceMouse::ShowCursor(xcb_window_t window, bool show) + { + xcb_void_cookie_t cookie; + if (show) + { + cookie = xcb_xfixes_show_cursor_checked(s_xcbConnection, window); + } + else + { + cookie = xcb_xfixes_hide_cursor_checked(s_xcbConnection, window); + } + + const XcbStdFreePtr xkbError{ xcb_request_check(s_xcbConnection, cookie) }; + + if (xkbError) + { + AZ_Warning("XcbInput", false, "ShowCursor failed: %d", xkbError->error_code); + + return; + } + + // ATTN In the following part we will when cursor gets hidden store the position of the cursor in screen space + // not window space. We use that to re-position when showing the cursor again. Is this the correct + // behavior? + + const bool cursorWasHidden = !m_cursorShown; + m_cursorShown = show; + if (!m_cursorShown) + { + m_cursorHiddenPosition = GetSystemCursorPositionNormalizedInternal(s_xcbScreen->root); + + SetSystemCursorPositionNormalized(AZ::Vector2(0.5f, 0.5f)); + } + else if (cursorWasHidden) + { + SetSystemCursorPositionNormalizedInternal(s_xcbScreen->root, m_cursorHiddenPosition); + } + + xcb_flush(s_xcbConnection); + } + + void XcbInputDeviceMouse::HandleButtonPressEvents(uint32_t detail, bool pressed) + { + bool isWheel; + float wheelDirection; + const auto* button = InputChannelFromMouseEvent(detail, isWheel, wheelDirection); + if (button) + { + QueueRawButtonEvent(*button, pressed); + } + if (isWheel) + { + float axisValue = MAX_XI_WHEEL_SENSITIVITY * wheelDirection; + QueueRawMovementEvent(InputDeviceMouse::Movement::Z, axisValue); + } + } + + void XcbInputDeviceMouse::HandlePointerMotionEvents(const xcb_generic_event_t* event) + { + const xcb_input_motion_event_t* mouseMotionEvent = reinterpret_cast(event); + + m_systemCursorPosition[0] = mouseMotionEvent->event_x; + m_systemCursorPosition[1] = mouseMotionEvent->event_y; + } + + void XcbInputDeviceMouse::HandleRawInputEvents(const xcb_ge_generic_event_t* event) + { + const xcb_ge_generic_event_t* genericEvent = reinterpret_cast(event); + switch (genericEvent->event_type) + { + case XCB_INPUT_RAW_BUTTON_PRESS: + { + const xcb_input_raw_button_press_event_t* mouseButtonEvent = + reinterpret_cast(event); + HandleButtonPressEvents(mouseButtonEvent->detail, true); + } + break; + case XCB_INPUT_RAW_BUTTON_RELEASE: + { + const xcb_input_raw_button_release_event_t* mouseButtonEvent = + reinterpret_cast(event); + HandleButtonPressEvents(mouseButtonEvent->detail, false); + } + break; + case XCB_INPUT_RAW_MOTION: + { + const xcb_input_raw_motion_event_t* mouseMotionEvent = reinterpret_cast(event); + + int axisLen = xcb_input_raw_button_press_axisvalues_length(mouseMotionEvent); + const xcb_input_fp3232_t* axisvalues = xcb_input_raw_button_press_axisvalues_raw(mouseMotionEvent); + for (int i = 0; i < axisLen; ++i) + { + const float axisValue = fp3232ToFloat(axisvalues[i]); + + switch (i) + { + case 0: + QueueRawMovementEvent(InputDeviceMouse::Movement::X, axisValue); + break; + case 1: + QueueRawMovementEvent(InputDeviceMouse::Movement::Y, axisValue); + break; + } + } + } + break; + } + } + + void XcbInputDeviceMouse::PollSpecialEvents() + { + while (xcb_generic_event_t* genericEvent = xcb_poll_for_queued_event(s_xcbConnection)) + { + // TODO Is the following correct? If we are showing the cursor, don't poll RAW Input events. + switch (genericEvent->response_type & ~0x80) + { + case XCB_GE_GENERIC: + { + const xcb_ge_generic_event_t* geGenericEvent = reinterpret_cast(genericEvent); + + // Only handle raw inputs if we have focus. + // Handle Raw Input events first. + if ((geGenericEvent->event_type == XCB_INPUT_RAW_BUTTON_PRESS) || + (geGenericEvent->event_type == XCB_INPUT_RAW_BUTTON_RELEASE) || + (geGenericEvent->event_type == XCB_INPUT_RAW_MOTION)) + { + HandleRawInputEvents(geGenericEvent); + + free(genericEvent); + } + } + break; + } + } + } + + void XcbInputDeviceMouse::HandleXcbEvent(xcb_generic_event_t* event) + { + switch (event->response_type & ~0x80) + { + // QT5 is using by default XInput which means we do need to check for XCB_GE_GENERIC event to parse all mouse related events. + case XCB_GE_GENERIC: + { + const xcb_ge_generic_event_t* genericEvent = reinterpret_cast(event); + + // Handling RAW Inputs here works in GameMode but not in Editor mode because QT is + // not handling RAW input events and passing to. + if (!m_cursorShown) + { + // Handle Raw Input events first. + if ((genericEvent->event_type == XCB_INPUT_RAW_BUTTON_PRESS) || + (genericEvent->event_type == XCB_INPUT_RAW_BUTTON_RELEASE) || (genericEvent->event_type == XCB_INPUT_RAW_MOTION)) + { + HandleRawInputEvents(genericEvent); + } + } + else + { + switch (genericEvent->event_type) + { + case XCB_INPUT_BUTTON_PRESS: + { + const xcb_input_button_press_event_t* mouseButtonEvent = + reinterpret_cast(genericEvent); + HandleButtonPressEvents(mouseButtonEvent->detail, true); + } + break; + case XCB_INPUT_BUTTON_RELEASE: + { + const xcb_input_button_release_event_t* mouseButtonEvent = + reinterpret_cast(genericEvent); + HandleButtonPressEvents(mouseButtonEvent->detail, false); + } + break; + case XCB_INPUT_MOTION: + { + HandlePointerMotionEvents(event); + } + break; + } + } + } + break; + case XCB_FOCUS_IN: + { + const xcb_focus_in_event_t* focusInEvent = reinterpret_cast(event); + if (m_focusWindow != focusInEvent->event) + { + m_focusWindow = focusInEvent->event; + HandleCursorState(m_focusWindow, m_systemCursorState); + } + } + break; + case XCB_FOCUS_OUT: + { + const xcb_focus_out_event_t* focusOutEvent = reinterpret_cast(event); + HandleCursorState(focusOutEvent->event, SystemCursorState::UnconstrainedAndVisible); + + ProcessRawEventQueues(); + ResetInputChannelStates(); + + m_focusWindow = XCB_NONE; + } + break; + } + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h new file mode 100644 index 0000000000..106d204ca9 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +#include +#include + +// The maximum number of raw input axis this mouse device supports. +constexpr uint32_t MAX_XI_RAW_AXIS = 2; + +// The sensitivity of the wheel. +constexpr float MAX_XI_WHEEL_SENSITIVITY = 140.0f; + +namespace AzFramework +{ + class XcbInputDeviceMouse + : public InputDeviceMouse::Implementation + , public XcbEventHandlerBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(XcbInputDeviceMouse, AZ::SystemAllocator, 0); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Constructor + //! \param[in] inputDevice Reference to the input device being implemented + XcbInputDeviceMouse(InputDeviceMouse& inputDevice); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Destructor + virtual ~XcbInputDeviceMouse(); + + static XcbInputDeviceMouse::Implementation* Create(InputDeviceMouse& inputDevice); + + protected: + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::IsConnected + bool IsConnected() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::SetSystemCursorState + void SetSystemCursorState(SystemCursorState systemCursorState) override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::GetSystemCursorState + SystemCursorState GetSystemCursorState() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::SetSystemCursorPositionNormalized + void SetSystemCursorPositionNormalized(AZ::Vector2 positionNormalized) override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::GetSystemCursorPositionNormalized + AZ::Vector2 GetSystemCursorPositionNormalized() const override; + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::InputDeviceMouse::Implementation::TickInputDevice + void TickInputDevice() override; + + //! This method is called by the Editor to accommodate some events with the Editor. Never called in Game mode. + void PollSpecialEvents() override; + + //! Handle X11 events. + void HandleXcbEvent(xcb_generic_event_t* event) override; + + //! Initialize XFixes extension. Used for barriers. + static bool InitializeXFixes(); + + //! Initialize XInput extension. Used for raw input during confinement and showing/hiding the cursor. + static bool InitializeXInput(); + + //! Enables/Disables XInput Raw Input events. + void SetEnableXInput(bool enable); + + //! Create barriers. + void CreateBarriers(xcb_window_t window, bool create); + + //! Helper function. + void SystemCursorStateToLogic(SystemCursorState systemCursorState, bool& confined, bool& cursorShown); + + //! Shows/Hides the cursor. + void ShowCursor(xcb_window_t window, bool show); + + //! Get the normalized cursor position. The coordinates returned are relative to the specified window. + AZ::Vector2 GetSystemCursorPositionNormalizedInternal(xcb_window_t window) const; + + //! Set the normalized cursor position. The normalized position will be relative to the specified window. + void SetSystemCursorPositionNormalizedInternal(xcb_window_t window, AZ::Vector2 positionNormalized); + + //! Handle button press/release events. + void HandleButtonPressEvents(uint32_t detail, bool pressed); + + //! Handle motion notify events. + void HandlePointerMotionEvents(const xcb_generic_event_t* event); + + //! Will set cursor states and confinement modes. + void HandleCursorState(xcb_window_t window, SystemCursorState systemCursorState); + + //! Will handle all raw input events. + void HandleRawInputEvents(const xcb_ge_generic_event_t* event); + + //! Convert XInput fp1616 to float. + inline float fp1616ToFloat(xcb_input_fp1616_t value) const + { + return static_cast((value >> 16) + (value & 0xffff) / 0xffff); + } + + //! Convert XInput fp3232 to float. + inline float fp3232ToFloat(xcb_input_fp3232_t value) const + { + return static_cast(value.integral) + static_cast(value.frac / (float)(1ull << 32)); + } + + const InputChannelId* InputChannelFromMouseEvent(xcb_button_t button, bool& isWheel, float& direction) const + { + isWheel = false; + direction = 1.0f; + switch (button) + { + case XCB_BUTTON_INDEX_1: + return &InputDeviceMouse::Button::Left; + case XCB_BUTTON_INDEX_2: + return &InputDeviceMouse::Button::Right; + case XCB_BUTTON_INDEX_3: + return &InputDeviceMouse::Button::Middle; + case XCB_BUTTON_INDEX_4: + isWheel = true; + direction = 1.0f; + break; + case XCB_BUTTON_INDEX_5: + isWheel = true; + direction = -1.0f; + break; + default: + break; + } + + return nullptr; + } + + // Barriers work only with positive values. We clamp here to zero. + inline int16_t Clamp(int16_t value) const + { + return value < 0 ? 0 : value; + } + + private: + //! The current system cursor state + SystemCursorState m_systemCursorState; + + //! The cursor position before it got hidden. + AZ::Vector2 m_cursorHiddenPosition; + + AZ::Vector2 m_systemCursorPositionNormalized; + uint32_t m_systemCursorPosition[MAX_XI_RAW_AXIS]; + + static xcb_connection_t* s_xcbConnection; + static xcb_screen_t* s_xcbScreen; + + //! Will be true if the xfixes extension could be initialized. + static bool m_xfixesInitialized; + + //! Will be true if the xinput2 extension could be initialized. + static bool m_xInputInitialized; + + //! The window that had focus + xcb_window_t m_prevConstraintWindow; + + //! The current window that has focus + xcb_window_t m_focusWindow; + + //! Will be true if the cursor is shown else false. + bool m_cursorShown; + + struct XFixesBarrierProperty + { + xcb_xfixes_barrier_t id; + uint32_t direction; + int16_t x0, y0, x1, y1; + }; + + //! Array that holds barrier information used to confine the cursor. + std::vector m_activeBarriers; + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp index 43f7e7140f..af5b3af3d8 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp @@ -8,25 +8,31 @@ #include #include -#include #include #include +#include #include namespace AzFramework { [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow"; - static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages - static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified - static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event + static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages + static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified + static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event + +#define _NET_WM_STATE_REMOVE 0l +#define _NET_WM_STATE_ADD 1l +#define _NET_WM_STATE_TOGGLE 2l //////////////////////////////////////////////////////////////////////////////////////////////// - XcbNativeWindow::XcbNativeWindow() + XcbNativeWindow::XcbNativeWindow() : NativeWindow::Implementation() + , m_xcbConnection(nullptr) + , m_xcbRootScreen(nullptr) + , m_xcbWindow(XCB_NONE) { - if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get(); - xcbConnectionManager != nullptr) + if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get(); xcbConnectionManager != nullptr) { m_xcbConnection = xcbConnectionManager->GetXcbConnection(); } @@ -34,89 +40,184 @@ namespace AzFramework } //////////////////////////////////////////////////////////////////////////////////////////////// - XcbNativeWindow::~XcbNativeWindow() = default; + XcbNativeWindow::~XcbNativeWindow() + { + if (XCB_NONE != m_xcbWindow) + { + xcb_destroy_window(m_xcbConnection, m_xcbWindow); + } + } //////////////////////////////////////////////////////////////////////////////////////////////// - void XcbNativeWindow::InitWindow(const AZStd::string& title, - const WindowGeometry& geometry, - const WindowStyleMasks& styleMasks) + void XcbNativeWindow::InitWindow(const AZStd::string& title, const WindowGeometry& geometry, const WindowStyleMasks& styleMasks) { - // Get the parent window + // Get the parent window const xcb_setup_t* xcbSetup = xcb_get_setup(m_xcbConnection); - xcb_screen_t* xcbRootScreen = xcb_setup_roots_iterator(xcbSetup).data; - xcb_window_t xcbParentWindow = xcbRootScreen->root; + m_xcbRootScreen = xcb_setup_roots_iterator(xcbSetup).data; + xcb_window_t xcbParentWindow = m_xcbRootScreen->root; // Create an XCB window from the connection m_xcbWindow = xcb_generate_id(m_xcbConnection); uint16_t borderWidth = 0; const uint32_t mask = styleMasks.m_platformAgnosticStyleMask; - if ((mask & WindowStyleMasks::WINDOW_STYLE_BORDERED) || - (mask & WindowStyleMasks::WINDOW_STYLE_RESIZEABLE)) + if ((mask & WindowStyleMasks::WINDOW_STYLE_BORDERED) || (mask & WindowStyleMasks::WINDOW_STYLE_RESIZEABLE)) { borderWidth = s_DefaultXcbWindowBorderWidth; } uint32_t eventMask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - - const uint32_t interestedEvents = - XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_BUTTON_PRESS - | XCB_EVENT_MASK_BUTTON_RELEASE - | XCB_EVENT_MASK_KEY_PRESS - | XCB_EVENT_MASK_KEY_RELEASE - | XCB_EVENT_MASK_POINTER_MOTION - ; - uint32_t valueList[] = { xcbRootScreen->black_pixel, - interestedEvents }; + + const uint32_t interestedEvents = XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE; + uint32_t valueList[] = { m_xcbRootScreen->black_pixel, interestedEvents }; xcb_void_cookie_t xcbCheckResult; - xcbCheckResult = xcb_create_window_checked(m_xcbConnection, - XCB_COPY_FROM_PARENT, - m_xcbWindow, - xcbParentWindow, - aznumeric_cast(geometry.m_posX), - aznumeric_cast(geometry.m_posY), - aznumeric_cast(geometry.m_width), - aznumeric_cast(geometry.m_height), - borderWidth, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - xcbRootScreen->root_visual, - eventMask, - valueList); + xcbCheckResult = xcb_create_window_checked( + m_xcbConnection, XCB_COPY_FROM_PARENT, m_xcbWindow, xcbParentWindow, aznumeric_cast(geometry.m_posX), + aznumeric_cast(geometry.m_posY), aznumeric_cast(geometry.m_width), aznumeric_cast(geometry.m_height), + borderWidth, XCB_WINDOW_CLASS_INPUT_OUTPUT, m_xcbRootScreen->root_visual, eventMask, valueList); AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to create xcb window."); SetWindowTitle(title); - // Setup the window close event - const static char* wmProtocolString = "WM_PROTOCOLS"; - - xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString); - xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr); - AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString); - m_xcbAtomProtocols = replyProtocol->atom; - - const static char* wmDeleteWindowString = "WM_DELETE_WINDOW"; - xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString); - xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr); - AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString); - m_xcbAtomDeleteWindow = replyDeleteWindow->atom; - - xcbCheckResult = xcb_change_property_checked(m_xcbConnection, - XCB_PROP_MODE_REPLACE, - m_xcbWindow, - m_xcbAtomProtocols, - XCB_ATOM_ATOM, - s_XcbFormatDataSize, - 1, - &m_xcbAtomDeleteWindow); - - AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to change the xcb atom property for WM_CLOSE event"); - + m_posX = geometry.m_posX; + m_posY = geometry.m_posY; m_width = geometry.m_width; m_height = geometry.m_height; + + InitializeAtoms(); + + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_REQUEST_FRAME_EXTENTS; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = 0l; + event.data.data32[1] = 0l; + event.data.data32[2] = 0l; + event.data.data32[3] = 0l; + event.data.data32[4] = 0l; + xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set _NET_REQUEST_FRAME_EXTENTS"); + + // The WM will be able to kill the application if it gets unresponsive. + int32_t pid = getpid(); + xcb_change_property(m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid); + + xcb_flush(m_xcbConnection); + } + + xcb_atom_t XcbNativeWindow::GetAtom(const char* atomName) + { + xcb_intern_atom_cookie_t intern_atom_cookie = xcb_intern_atom(m_xcbConnection, 0, strlen(atomName), atomName); + XcbStdFreePtr xkbinternAtom{ xcb_intern_atom_reply(m_xcbConnection, intern_atom_cookie, NULL) }; + + if (!xkbinternAtom) + { + AZ_Error(XcbErrorWindow, xkbinternAtom != nullptr, "Unable to query xcb '%s' atom", atomName); + return XCB_NONE; + } + + return xkbinternAtom->atom; + } + + int XcbNativeWindow::SetAtom(xcb_window_t window, xcb_atom_t atom, xcb_atom_t type, size_t len, void* data) + { + xcb_void_cookie_t cookie = xcb_change_property_checked(m_xcbConnection, XCB_PROP_MODE_REPLACE, window, atom, type, 32, len, data); + XcbStdFreePtr xkbError{ xcb_request_check(m_xcbConnection, cookie) }; + + if (!xkbError) + { + return 0; + } + + return xkbError->error_code; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + + void XcbNativeWindow::InitializeAtoms() + { + AZStd::vector Atoms; + + _NET_ACTIVE_WINDOW = GetAtom("_NET_ACTIVE_WINDOW"); + _NET_WM_BYPASS_COMPOSITOR = GetAtom("_NET_WM_BYPASS_COMPOSITOR"); + + // --------------------------------------------------------------------- + // Handle all WM Protocols atoms. + // + + WM_PROTOCOLS = GetAtom("WM_PROTOCOLS"); + + // This atom is used to close a window. Emitted when user clicks the close button. + WM_DELETE_WINDOW = GetAtom("WM_DELETE_WINDOW"); + + Atoms.push_back(WM_DELETE_WINDOW); + + xcb_change_property( + m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, WM_PROTOCOLS, XCB_ATOM_ATOM, 32, Atoms.size(), Atoms.data()); + + xcb_flush(m_xcbConnection); + + // --------------------------------------------------------------------- + // Handle all WM State atoms. + // + + _NET_WM_STATE = GetAtom("_NET_WM_STATE"); + _NET_WM_STATE_FULLSCREEN = GetAtom("_NET_WM_STATE_FULLSCREEN"); + _NET_WM_STATE_MAXIMIZED_VERT = GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"); + _NET_WM_STATE_MAXIMIZED_HORZ = GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"); + _NET_MOVERESIZE_WINDOW = GetAtom("_NET_MOVERESIZE_WINDOW"); + _NET_REQUEST_FRAME_EXTENTS = GetAtom("_NET_REQUEST_FRAME_EXTENTS"); + _NET_FRAME_EXTENTS = GetAtom("_NET_FRAME_EXTENTS"); + _NET_WM_PID = GetAtom("_NET_WM_PID"); + } + + void XcbNativeWindow::GetWMStates() + { + xcb_get_property_cookie_t cookie = xcb_get_property(m_xcbConnection, 0, m_xcbWindow, _NET_WM_STATE, XCB_ATOM_ATOM, 0, 1024); + + xcb_generic_error_t* error = nullptr; + XcbStdFreePtr xkbGetPropertyReply{ xcb_get_property_reply(m_xcbConnection, cookie, &error) }; + + if (!xkbGetPropertyReply || error || !((xkbGetPropertyReply->format == 32) && (xkbGetPropertyReply->type == XCB_ATOM_ATOM))) + { + AZ_Warning("ApplicationLinux", false, "Acquiring _NET_WM_STATE information from the WM failed."); + + if (error) + { + AZ_TracePrintf("Error", "Error code %d", error->error_code); + free(error); + } + return; + } + + m_fullscreenState = false; + m_horizontalyMaximized = false; + m_verticallyMaximized = false; + + const xcb_atom_t* states = static_cast(xcb_get_property_value(xkbGetPropertyReply.get())); + for (int i = 0; i < xkbGetPropertyReply->length; i++) + { + if (states[i] == _NET_WM_STATE_FULLSCREEN) + { + m_fullscreenState = true; + } + else if (states[i] == _NET_WM_STATE_MAXIMIZED_HORZ) + { + m_horizontalyMaximized = true; + } + else if (states[i] == _NET_WM_STATE_MAXIMIZED_VERT) + { + m_verticallyMaximized = true; + } + } } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -146,7 +247,7 @@ namespace AzFramework xcb_flush(m_xcbConnection); } XcbEventHandlerBus::Handler::BusDisconnect(); - } + } //////////////////////////////////////////////////////////////////////////////////////////////// NativeWindowHandle XcbNativeWindow::GetWindowHandle() const @@ -158,14 +259,9 @@ namespace AzFramework void XcbNativeWindow::SetWindowTitle(const AZStd::string& title) { xcb_void_cookie_t xcbCheckResult; - xcbCheckResult = xcb_change_property(m_xcbConnection, - XCB_PROP_MODE_REPLACE, - m_xcbWindow, - XCB_ATOM_WM_NAME, - XCB_ATOM_STRING, - 8, - static_cast(title.size()), - title.c_str()); + xcbCheckResult = xcb_change_property( + m_xcbConnection, XCB_PROP_MODE_REPLACE, m_xcbWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, static_cast(title.size()), + title.c_str()); AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set window title."); } @@ -175,7 +271,7 @@ namespace AzFramework const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height }; xcb_configure_window(m_xcbConnection, m_xcbWindow, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); - + m_width = clientAreaSize.m_width; m_height = clientAreaSize.m_height; } @@ -185,16 +281,77 @@ namespace AzFramework { // [GFX TODO][GHI - 2678] // Using 60 for now until proper support is added + return 60; } + bool XcbNativeWindow::GetFullScreenState() const + { + return m_fullscreenState; + } + + void XcbNativeWindow::SetFullScreenState(bool fullScreenState) + { + // TODO This is a pretty basic full-screen implementation using WM's _NET_WM_STATE_FULLSCREEN state. + // Do we have to provide also the old way? + + GetWMStates(); + + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_WM_STATE; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = fullScreenState ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + event.data.data32[1] = _NET_WM_STATE_FULLSCREEN; + event.data.data32[2] = 0; + event.data.data32[3] = 1; + event.data.data32[4] = 0; + xcb_void_cookie_t xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert(ValidateXcbResult(xcbCheckResult), "Failed to set _NET_WM_STATE_FULLSCREEN"); + + // Also try to disable/enable the compositor if possible. Might help in some cases. + const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = m_fullscreenState ? 1 : 0; + SetAtom(m_xcbWindow, _NET_WM_BYPASS_COMPOSITOR, XCB_ATOM_CARDINAL, 32, (char*)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON); + + if (!fullScreenState) + { + if (m_horizontalyMaximized || m_verticallyMaximized) + { + printf("Remove maximized state.\n"); + xcb_client_message_event_t event; + event.response_type = XCB_CLIENT_MESSAGE; + event.type = _NET_WM_STATE; + event.window = m_xcbWindow; + event.format = 32; + event.sequence = 0; + event.data.data32[0] = _NET_WM_STATE_MAXIMIZED_VERT; + event.data.data32[1] = _NET_WM_STATE_MAXIMIZED_HORZ; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + xcb_void_cookie_t xcbCheckResult = xcb_send_event( + m_xcbConnection, 1, m_xcbRootScreen->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)&event); + AZ_Assert( + ValidateXcbResult(xcbCheckResult), "Failed to remove _NET_WM_STATE_MAXIMIZED_VERT | _NET_WM_STATE_MAXIMIZED_HORZ"); + } + } + + xcb_flush(m_xcbConnection); + m_fullscreenState = fullScreenState; + } + //////////////////////////////////////////////////////////////////////////////////////////////// bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie) { bool result = true; if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie)) { - AZ_TracePrintf("Error","Error code %d", error->error_code); + AZ_TracePrintf("Error", "Error code %d", error->error_code); result = false; } return result; @@ -205,20 +362,20 @@ namespace AzFramework { switch (event->response_type & s_XcbResponseTypeMask) { - case XCB_CONFIGURE_NOTIFY: + case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t* cne = reinterpret_cast(event); - WindowSizeChanged(aznumeric_cast(cne->width), - aznumeric_cast(cne->height)); - + if ((cne->width != m_width) || (cne->height != m_height)) + { + WindowSizeChanged(aznumeric_cast(cne->width), aznumeric_cast(cne->height)); + } break; } - case XCB_CLIENT_MESSAGE: + case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t* cme = reinterpret_cast(event); - if ((cme->type == m_xcbAtomProtocols) && - (cme->format == s_XcbFormatDataSize) && - (cme->data.data32[0] == m_xcbAtomDeleteWindow)) + + if ((cme->type == WM_PROTOCOLS) && (cme->format == s_XcbFormatDataSize) && (cme->data.data32[0] == WM_DELETE_WINDOW)) { Deactivate(); @@ -239,7 +396,8 @@ namespace AzFramework if (m_activated) { - WindowNotificationBus::Event(reinterpret_cast(m_xcbWindow), &WindowNotificationBus::Events::OnWindowResized, width, height); + WindowNotificationBus::Event( + reinterpret_cast(m_xcbWindow), &WindowNotificationBus::Events::OnWindowResized, width, height); } } } diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h index 36737e24e8..38462dcb08 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h @@ -27,15 +27,16 @@ namespace AzFramework //////////////////////////////////////////////////////////////////////////////////////////// // NativeWindow::Implementation - void InitWindow(const AZStd::string& title, - const WindowGeometry& geometry, - const WindowStyleMasks& styleMasks) override; + void InitWindow(const AZStd::string& title, const WindowGeometry& geometry, const WindowStyleMasks& styleMasks) override; void Activate() override; void Deactivate() override; NativeWindowHandle GetWindowHandle() const override; void SetWindowTitle(const AZStd::string& title) override; void ResizeClientArea(WindowSize clientAreaSize) override; - uint32_t GetDisplayRefreshRate() const override; + uint32_t GetDisplayRefreshRate() const override; + + bool GetFullScreenState() const override; + void SetFullScreenState(bool fullScreenState) override; //////////////////////////////////////////////////////////////////////////////////////////// // XcbEventHandlerBus::Handler @@ -44,10 +45,46 @@ namespace AzFramework private: bool ValidateXcbResult(xcb_void_cookie_t cookie); void WindowSizeChanged(const uint32_t width, const uint32_t height); + int SetAtom(xcb_window_t window, xcb_atom_t atom, xcb_atom_t type, size_t len, void* data); - xcb_connection_t* m_xcbConnection = nullptr; - xcb_window_t m_xcbWindow = 0; - xcb_atom_t m_xcbAtomProtocols; - xcb_atom_t m_xcbAtomDeleteWindow; + // Initialize one atom. + xcb_atom_t GetAtom(const char* atomName); + + // Initialize all used atoms. + void InitializeAtoms(); + void GetWMStates(); + + xcb_connection_t* m_xcbConnection = nullptr; + xcb_screen_t* m_xcbRootScreen = nullptr; + xcb_window_t m_xcbWindow = 0; + int32_t m_posX; + int32_t m_posY; + bool m_fullscreenState = false; + bool m_horizontalyMaximized = false; + bool m_verticallyMaximized = false; + + // Use exact atom names for easy readability and usage. + xcb_atom_t WM_PROTOCOLS; + xcb_atom_t WM_DELETE_WINDOW; + // This atom is used to activate a window. + xcb_atom_t _NET_ACTIVE_WINDOW; + // This atom is use to bypass a compositor. Used during fullscreen mode. + xcb_atom_t _NET_WM_BYPASS_COMPOSITOR; + // This atom is used to change the state of a window using the WM. + xcb_atom_t _NET_WM_STATE; + // This atom is used to enable/disable fullscreen mode of a window. + xcb_atom_t _NET_WM_STATE_FULLSCREEN; + // This atom is used to extend the window to max vertically. + xcb_atom_t _NET_WM_STATE_MAXIMIZED_VERT; + // This atom is used to extend the window to max horizontally. + xcb_atom_t _NET_WM_STATE_MAXIMIZED_HORZ; + // This atom is used to position and resize a window. + xcb_atom_t _NET_MOVERESIZE_WINDOW; + // This atom is used to request the extent of the window. + xcb_atom_t _NET_REQUEST_FRAME_EXTENTS; + // This atom is used to identify the reply event for _NET_REQUEST_FRAME_EXTENTS + xcb_atom_t _NET_FRAME_EXTENTS; + // This atom is used to allow WM to kill app if not responsive anymore + xcb_atom_t _NET_WM_PID; }; } // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake index 68de710fa1..48afccc0d0 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake @@ -12,6 +12,8 @@ set(FILES AzFramework/XcbConnectionManager.h AzFramework/XcbInputDeviceKeyboard.cpp AzFramework/XcbInputDeviceKeyboard.h + AzFramework/XcbInputDeviceMouse.cpp + AzFramework/XcbInputDeviceMouse.h AzFramework/XcbInterface.h AzFramework/XcbNativeWindow.cpp AzFramework/XcbNativeWindow.h diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp new file mode 100644 index 0000000000..e2c3c2d575 --- /dev/null +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp @@ -0,0 +1,27 @@ +/* + * 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 + * + */ + +#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB +#include +#endif + +namespace AzFramework +{ + InputDeviceMouse::Implementation* InputDeviceMouse::Implementation::Create(InputDeviceMouse& inputDevice) + { +#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + return XcbInputDeviceMouse::Create(inputDevice); +#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND +#error "Linux Window Manager Wayland not supported." + return nullptr; +#else +#error "Linux Window Manager not recognized." + return nullptr; +#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake index b08c3b310d..66211c6085 100644 --- a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake +++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake @@ -22,8 +22,10 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") PRIVATE 3rdParty::X11::xcb 3rdParty::X11::xcb_xkb + 3rdParty::X11::xcb_xfixes 3rdParty::X11::xkbcommon 3rdParty::X11::xkbcommon_X11 + xcb-xinput ) elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland") diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake index 4f06aa5c57..206563fdda 100644 --- a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake @@ -22,8 +22,8 @@ set(FILES AzFramework/Windowing/NativeWindow_Linux.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp + AzFramework/Input/Devices/Mouse/InputDeviceMouse_Linux.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp - ../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp AzFramework/Input/User/LocalUserId_Platform.h ../Common/Default/AzFramework/Input/User/LocalUserId_Default.h diff --git a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 407ab1d21f..2dc32d14d5 100644 --- a/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/AzFramework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -569,11 +569,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; @@ -591,11 +592,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; @@ -720,11 +722,12 @@ namespace UnitTest FillSpawnable(NumEntities); CreateEntityReferences(refScheme); + AZ_PUSH_DISABLE_WARNING(5233, "-Wunused-lambda-capture") // Older versions of MSVC toolchain require to pass constexpr in the + // capture. Newer versions issue unused warning auto callback = [this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + AZ_POP_DISABLE_WARNING { - AZ_UNUSED(refScheme); - AZ_UNUSED(NumEntities); ValidateEntityReferences(refScheme, NumEntities, entities); }; diff --git a/Code/Framework/AzTest/AzTest/AzTest.cpp b/Code/Framework/AzTest/AzTest/AzTest.cpp index 3b809d2c96..85e7f7e6b3 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.cpp +++ b/Code/Framework/AzTest/AzTest/AzTest.cpp @@ -90,19 +90,16 @@ namespace AZ } } - //! Filter out integration tests from the test run - void excludeIntegTests() - { - AddExcludeFilter("INTEG_*"); - AddExcludeFilter("Integ_*"); - } - void ApplyGlobalParameters(int* argc, char** argv) { - // this is a hook that can be used to apply any other global non-google parameters - // that we use. + // this is a hook that can be used to apply any other global parameters that we use. AZ_UNUSED(argc); AZ_UNUSED(argv); + + // Disable gtest catching unhandled exceptions, instead, AzTestRunner will do it through: + // AZ::Debug::Trace::HandleExceptions(true). This gives us a stack trace when the exception + // is thrown (googletest does not). + testing::FLAGS_gtest_catch_exceptions = false; } //! Print out parameters that are not used by the framework @@ -160,7 +157,6 @@ namespace AZ } ::testing::InitGoogleMock(&argc, argv); - AZ::Test::excludeIntegTests(); AZ::Test::ApplyGlobalParameters(&argc, argv); AZ::Test::printUnusedParametersWarning(argc, argv); AZ::Test::addTestEnvironments(m_envs); @@ -281,7 +277,6 @@ namespace AZ } } - AZ::Test::excludeIntegTests(); AZ::Test::printUnusedParametersWarning(argc, argv); return RUN_ALL_TESTS(); diff --git a/Code/Framework/AzTest/AzTest/AzTest.h b/Code/Framework/AzTest/AzTest/AzTest.h index 352db1a0b5..4b038cabd4 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.h +++ b/Code/Framework/AzTest/AzTest/AzTest.h @@ -104,7 +104,6 @@ namespace AZ void addTestEnvironment(ITestEnvironment* env); void addTestEnvironments(std::vector envs); - void excludeIntegTests(); //! A hook that can be used to read any other misc parameters and remove them before google sees them. //! Note that this modifies argc and argv to delete the parameters it consumes. @@ -266,7 +265,6 @@ namespace AZ ::testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); \ listeners.Append(new AZ::Test::OutputEventListener); \ } \ - AZ::Test::excludeIntegTests(); \ AZ::Test::ApplyGlobalParameters(&argc, argv); \ AZ::Test::printUnusedParametersWarning(argc, argv); \ AZ::Test::addTestEnvironments({TEST_ENV}); \ diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h index 4fb4191d45..966b9f8478 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h @@ -43,8 +43,7 @@ namespace AzToolsFramework }; //! Provides a bus to notify when the different editor modes are entered/exit. - class ViewportEditorModeNotifications - : public AZ::EBusTraits + class ViewportEditorModeNotifications : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// @@ -58,14 +57,17 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); //! Notifies subscribers of the a given viewport to the activation of the specified editor mode. - virtual void OnEditorModeActivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeActivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } //! Notifies subscribers of the a given viewport to the deactivation of the specified editor mode. - virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) + virtual void OnEditorModeDeactivated( + [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, [[maybe_unused]] ViewportEditorMode mode) { } }; + using ViewportEditorModeNotificationsBus = AZ::EBus; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp index 1768cb5920..07e025fc60 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/ComponentModeCollection.cpp @@ -137,6 +137,7 @@ namespace AzToolsFramework if (componentTypeIt == m_activeComponentTypes.end()) { m_activeComponentTypes.push_back(componentType); + m_viewportUiHandlers.emplace_back(componentType); } // see if we already have a ComponentModeBuilder for the specific component on this entity @@ -225,6 +226,7 @@ namespace AzToolsFramework if (!m_entitiesAndComponentModes.empty()) { RefreshActions(); + PopulateViewportUi(); } // if entering ComponentMode not as an undo/redo step (an action was @@ -285,6 +287,10 @@ namespace AzToolsFramework componentModeCommand.release(); } + // remove the component mode viewport border + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder); + // notify listeners the editor has left ComponentMode - listeners may // wish to modify state to indicate this (e.g. appearance, functionality etc.) m_viewportEditorModeTracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Component); @@ -301,6 +307,7 @@ namespace AzToolsFramework } m_entitiesAndComponentModeBuilders.clear(); m_activeComponentTypes.clear(); + m_viewportUiHandlers.clear(); m_componentMode = false; m_selectedComponentModeIndex = 0; @@ -385,6 +392,24 @@ namespace AzToolsFramework return m_activeComponentTypes.size() > 1; } + static ComponentModeViewportUi* FindViewportUiHandlerForType( + AZStd::vector& viewportUiHandlers, const AZ::Uuid& componentType) + { + auto handler = AZStd::find_if( + viewportUiHandlers.begin(), viewportUiHandlers.end(), + [componentType](const ComponentModeViewportUi& handler) + { + return handler.GetComponentType() == componentType; + }); + + if (handler == viewportUiHandlers.end()) + { + return nullptr; + } + + return handler; + } + bool ComponentModeCollection::ActiveComponentModeChanged(const AZ::Uuid& previousComponentType) { if (m_activeComponentTypes[m_selectedComponentModeIndex] != previousComponentType) @@ -410,6 +435,20 @@ namespace AzToolsFramework // replace the current component mode by invoking the builder // for the new 'active' component mode componentMode.m_componentMode = componentModeBuilder->m_componentModeBuilder(); + + // populate the viewport UI with the new component mode + PopulateViewportUi(); + + // set the appropriate viewportUiHandler to active + if (auto viewportUiHandler = + FindViewportUiHandlerForType(m_viewportUiHandlers, m_activeComponentTypes[m_selectedComponentModeIndex])) + { + viewportUiHandler->SetComponentModeViewportUiActive(true); + } + + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, + componentMode.m_componentMode->GetComponentModeName().c_str()); } RefreshActions(); @@ -519,5 +558,18 @@ namespace AzToolsFramework } } + void ComponentModeCollection::PopulateViewportUi() + { + // update viewport UI for new component type + if (m_selectedComponentModeIndex < m_activeComponentTypes.size()) + { + // iterate over all entities and their active Component Mode, populate viewport UI for the new mode + for (auto& entityAndComponentMode : m_entitiesAndComponentModes) + { + // build viewport UI based on current state + entityAndComponentMode.m_componentMode->PopulateViewportUi(); + } + } + } } // namespace ComponentModeFramework } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp index 9e043a5c86..f449478306 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ComponentMode/EditorBaseComponentMode.cpp @@ -55,7 +55,7 @@ namespace AzToolsFramework GetEntityComponentIdPair(), elementIdsToDisplay); // create the component mode border with the specific name for this component mode ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateComponentModeBorder, + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, GetComponentModeName()); // set the EntityComponentId for this ComponentMode to active in the ComponentModeViewportUi system ComponentModeViewportUiRequestBus::Event( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp index f592c471d0..44ff603c0c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp @@ -71,12 +71,7 @@ namespace AzToolsFramework return; } - AZ::EntityId previousFocusEntityId = m_focusRoot; - m_focusRoot = entityId; - FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot); - - if (auto tracker = AZ::Interface::Get(); - tracker != nullptr) + if (auto tracker = AZ::Interface::Get()) { if (!m_focusRoot.IsValid() && entityId.IsValid()) { @@ -87,6 +82,10 @@ namespace AzToolsFramework tracker->DeactivateMode({ GetEntityContextId() }, ViewportEditorMode::Focus); } } + + AZ::EntityId previousFocusEntityId = m_focusRoot; + m_focusRoot = entityId; + FocusModeNotificationBus::Broadcast(&FocusModeNotifications::OnEditorFocusChanged, previousFocusEntityId, m_focusRoot); } void FocusModeSystemComponent::ClearFocusRoot([[maybe_unused]] AzFramework::EntityContextId entityContextId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 081655a166..ee34b628bb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1052,10 +1052,10 @@ namespace AzToolsFramework DuplicateNestedEntitiesInInstance(commonOwningInstance->get(), entities, instanceDomAfter, duplicatedEntityAndInstanceIds, duplicateEntityAliasMap); - PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication", false); command->SetParent(undoBatch.GetUndoBatch()); command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); - command->RedoBatched(); + command->Redo(); DuplicateNestedInstancesInInstance(commonOwningInstance->get(), instances, instanceDomAfter, duplicatedEntityAndInstanceIds, newInstanceAliasToOldInstanceMap); @@ -1323,7 +1323,7 @@ namespace AzToolsFramework Prefab::PrefabDom instanceDomAfter; m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance); - PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment", false); command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId); command->SetParent(undoBatch.GetUndoBatch()); { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp index d34e2cfc92..9d0d0547ae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemScriptingHandler.cpp @@ -6,11 +6,14 @@ * */ +#include #include #include #include #include #include +#include +#include namespace AzToolsFramework::Prefab { @@ -61,9 +64,30 @@ namespace AzToolsFramework::Prefab entities.push_back(entity); } } - - auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath))); + bool result = false; + [[maybe_unused]] AZ::EntityId commonRoot; + EntityList topLevelEntities; + AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(result, &AzToolsFramework::ToolsApplicationRequestBus::Events::FindCommonRootInactive, + entities, commonRoot, &topLevelEntities); + + auto containerEntity = AZStd::make_unique(); + containerEntity->CreateComponent(); + + for (AZ::Entity* entity : topLevelEntities) + { + AzToolsFramework::Components::TransformComponent* transformComponent = + entity->FindComponent(); + + if (transformComponent) + { + transformComponent->SetParent(containerEntity->GetId()); + } + } + + auto prefab = m_prefabSystemComponentInterface->CreatePrefab( + entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)), AZStd::move(containerEntity)); + if (!prefab) { AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp index b298304e3b..6c96209d56 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.cpp @@ -17,17 +17,16 @@ namespace AzToolsFramework { PrefabUndoBase::PrefabUndoBase(const AZStd::string& undoOperationName) : UndoSystem::URSequencePoint(undoOperationName) - , m_changed(true) - , m_templateId(InvalidTemplateId) { m_instanceToTemplateInterface = AZ::Interface::Get(); AZ_Assert(m_instanceToTemplateInterface, "Failed to grab instance to template interface"); } //PrefabInstanceUndo - PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName) + PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation) : PrefabUndoBase(undoOperationName) { + m_useImmediatePropagation = useImmediatePropagation; } void PrefabUndoInstance::Capture( @@ -43,17 +42,12 @@ namespace AzToolsFramework void PrefabUndoInstance::Undo() { - m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, true); + m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId, m_useImmediatePropagation); } void PrefabUndoInstance::Redo() { - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, true); - } - - void PrefabUndoInstance::RedoBatched() - { - m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId); + m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId, m_useImmediatePropagation); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h index 8669024df7..0946a36951 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndo.h @@ -29,14 +29,15 @@ namespace AzToolsFramework bool Changed() const override { return m_changed; } protected: - TemplateId m_templateId; + TemplateId m_templateId = InvalidTemplateId; PrefabDom m_redoPatch; PrefabDom m_undoPatch; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; - bool m_changed; + bool m_changed = true; + bool m_useImmediatePropagation = true; }; //! handles the addition and removal of entities from instances @@ -44,7 +45,7 @@ namespace AzToolsFramework : public PrefabUndoBase { public: - explicit PrefabUndoInstance(const AZStd::string& undoOperationName); + explicit PrefabUndoInstance(const AZStd::string& undoOperationName, const bool useImmediatePropagation = true); void Capture( const PrefabDom& initialState, @@ -53,7 +54,6 @@ namespace AzToolsFramework void Undo() override; void Redo() override; - void RedoBatched(); }; //! handles entity updates, such as when the values on an entity change diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp index 9803b55324..31a0c60bcb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoHelpers.cpp @@ -23,10 +23,10 @@ namespace AzToolsFramework PrefabDom instanceDomAfterUpdate; PrefabDomUtils::StoreInstanceInPrefabDom(instance, instanceDomAfterUpdate); - PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage); + PrefabUndoInstance* state = aznew Prefab::PrefabUndoInstance(undoMessage, false); state->Capture(instanceDomBeforeUpdate, instanceDomAfterUpdate, instance.GetTemplateId()); state->SetParent(undoBatch); - state->RedoBatched(); + state->Redo(); } LinkId CreateLink( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index bb718d0dc9..94795c44a9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -9,6 +9,7 @@ #include "EditorHelpers.h" #include +#include #include #include #include @@ -114,6 +115,33 @@ namespace AzToolsFramework } } + CursorEntityIdQuery::CursorEntityIdQuery(AZ::EntityId entityId, AZ::EntityId rootEntityId) + : m_entityId(entityId) + , m_containerAncestorEntityId(rootEntityId) + { + } + + AZ::EntityId CursorEntityIdQuery::EntityIdUnderCursor() const + { + return m_entityId; + } + + AZ::EntityId CursorEntityIdQuery::ContainerAncestorEntityId() const + { + return m_containerAncestorEntityId; + } + + bool CursorEntityIdQuery::HasContainerAncestorEntityId() const + { + if (m_entityId.IsValid()) + { + return m_entityId != m_containerAncestorEntityId; + } + + return false; + } + + EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache) : m_entityDataCache(entityDataCache) { @@ -123,9 +151,14 @@ namespace AzToolsFramework "EditorHelpers - " "Focus Mode Interface could not be found. " "Check that it is being correctly initialized."); + + AZStd::vector> invalidClicks; + invalidClicks.push_back(AZStd::make_unique("Not in focus")); + invalidClicks.push_back(AZStd::make_unique()); + m_invalidClicks = AZStd::make_unique(AZStd::move(invalidClicks)); } - AZ::EntityId EditorHelpers::HandleMouseInteraction( + CursorEntityIdQuery EditorHelpers::FindEntityIdUnderCursor( const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { AZ_PROFILE_FUNCTION(AzToolsFramework); @@ -186,20 +219,34 @@ namespace AzToolsFramework } } - // Verify if the entity Id corresponds to an entity that is focused; if not, halt selection. - if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor)) + // verify if the entity Id corresponds to an entity that is focused; if not, halt selection. + if (entityIdUnderCursor.IsValid() && !IsSelectableAccordingToFocusMode(entityIdUnderCursor)) { - return AZ::EntityId(); + if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() && + mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down || + mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::DoubleClick) + { + m_invalidClicks->AddInvalidClick(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); + } + + return CursorEntityIdQuery(AZ::EntityId(), AZ::EntityId()); } - // Container Entity support - if the entity that is being selected is part of a closed container, + // container entity support - if the entity that is being selected is part of a closed container, // change the selection to the container instead. if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) { - return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor); + const auto highestSelectableEntity = containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor); + return CursorEntityIdQuery(entityIdUnderCursor, highestSelectableEntity); } - return entityIdUnderCursor; + return CursorEntityIdQuery(entityIdUnderCursor, AZ::EntityId()); + } + + void EditorHelpers::Display2d( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + m_invalidClicks->Display2d(viewportInfo, debugDisplay); } void EditorHelpers::DisplayHelpers( @@ -263,19 +310,19 @@ namespace AzToolsFramework } } - bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableInViewport(const AZ::EntityId entityId) const { return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId); } - bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableAccordingToFocusMode(const AZ::EntityId entityId) const { return m_focusModeInterface->IsInFocusSubTree(entityId); } - bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) + bool EditorHelpers::IsSelectableAccordingToContainerEntities(const AZ::EntityId entityId) const { - if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get()) + if (const auto* containerEntityInterface = AZ::Interface::Get()) { return !containerEntityInterface->IsUnderClosedContainerEntity(entityId); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h index 909a231635..458f15c1f2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include namespace AzFramework { @@ -29,6 +32,28 @@ namespace AzToolsFramework struct MouseInteractionEvent; } + //!< Represents the result of a query to find the id of the entity under the cursor (if any). + class CursorEntityIdQuery + { + public: + CursorEntityIdQuery(AZ::EntityId entityId, AZ::EntityId rootEntityId); + + //! Returns the entity id under the cursor (if any). + //! @note In the case of no entity id under the cursor, an invalid entity id is returned. + AZ::EntityId EntityIdUnderCursor() const; + + //! Returns the topmost container entity id in the hierarchy if the entity id under the cursor is inside a container entity, otherwise returns the entity id. + //! @note In the case of no entity id under the cursor, an invalid entity id is returned. + AZ::EntityId ContainerAncestorEntityId() const; + + //! Returns true if the query has a container ancestor entity id, otherwise false. + bool HasContainerAncestorEntityId() const; + + private: + AZ::EntityId m_entityId; //& showIconCheck); + //! Handle 2d drawing for EditorHelper functionality. + void Display2d( + const AzFramework::ViewportInfo& viewportInfo, + AzFramework::DebugDisplayRequests& debugDisplay); + //! Returns whether the entityId can be selected in the viewport according //! to the current Editor Focus Mode and Container Entity setup. - bool IsSelectableInViewport(AZ::EntityId entityId); + bool IsSelectableInViewport(AZ::EntityId entityId) const; private: //! Returns whether the entityId can be selected in the viewport according //! to the current Editor Focus Mode setup. - bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId); + bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId) const; //! Returns whether the entityId can be selected in the viewport according - //! to the current Container Entityu setup. - bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId); + //! to the current Container Entity setup. + bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId) const; + + AZStd::unique_ptr m_invalidClicks; //!< Display for invalid click behavior. const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. - const FocusModeInterface* m_focusModeInterface = nullptr; + const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 6e7777b31c..059b265f51 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -80,7 +80,7 @@ namespace AzToolsFramework const AzFramework::CameraState cameraState = GetCameraState(viewportId); - m_cachedEntityIdUnderCursor = m_editorHelpers->HandleMouseInteraction(cameraState, mouseInteraction); + m_cachedEntityIdUnderCursor = m_editorHelpers->FindEntityIdUnderCursor(cameraState, mouseInteraction).ContainerAncestorEntityId(); // when left clicking, if we successfully clicked an entity, assign that // to the entity field selected in the entity inspector (RPE) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index d5a0595049..39c882b766 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1799,7 +1800,8 @@ namespace AzToolsFramework const AzFramework::ViewportId viewportId = mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId; const AzFramework::CameraState cameraState = GetCameraState(viewportId); - m_cachedEntityIdUnderCursor = m_editorHelpers->HandleMouseInteraction(cameraState, mouseInteraction); + const auto cursorEntityIdQuery = m_editorHelpers->FindEntityIdUnderCursor(cameraState, mouseInteraction); + m_cachedEntityIdUnderCursor = cursorEntityIdQuery.ContainerAncestorEntityId(); const auto selectClickEvent = ClickDetectorEventFromViewportInteraction(mouseInteraction); m_cursorState.SetCurrentPosition(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); @@ -1825,8 +1827,6 @@ namespace AzToolsFramework } } - const AZ::EntityId entityIdUnderCursor = m_cachedEntityIdUnderCursor; - EditorContextMenuUpdate(m_contextMenu, mouseInteraction); m_boxSelect.HandleMouseInteraction(mouseInteraction); @@ -1842,6 +1842,21 @@ namespace AzToolsFramework return true; } + const AZ::EntityId entityIdUnderCursor = m_cachedEntityIdUnderCursor; + + if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::DoubleClick && + mouseInteraction.m_mouseInteraction.m_mouseButtons.Left()) + { + if (cursorEntityIdQuery.HasContainerAncestorEntityId()) + { + if (auto prefabFocusInterface = AZ::Interface::Get()) + { + prefabFocusInterface->FocusOnPrefabInstanceOwningEntityId(cursorEntityIdQuery.ContainerAncestorEntityId()); + return false; + } + } + } + bool stickySelect = false; ViewportInteraction::ViewportSettingsRequestBus::EventResult( stickySelect, viewportId, &ViewportInteraction::ViewportSettingsRequestBus::Events::StickySelectEnabled); @@ -3560,6 +3575,8 @@ namespace AzToolsFramework DrawAxisGizmo(viewportInfo, debugDisplay); m_boxSelect.Display2d(viewportInfo, debugDisplay); + + m_editorHelpers->Display2d(viewportInfo, debugDisplay); } void EditorTransformComponentSelection::RefreshSelectedEntityIds() @@ -3663,26 +3680,63 @@ namespace AzToolsFramework void EditorTransformComponentSelection::OnEditorModeActivated( [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) { - if (mode == ViewportEditorMode::Component) + switch (mode) { - SetAllViewportUiVisible(false); + case ViewportEditorMode::Component: + { + SetAllViewportUiVisible(false); - EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); - ToolsApplicationNotificationBus::Handler::BusDisconnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterDisconnect(); + ToolsApplicationNotificationBus::Handler::BusDisconnect(); + } + break; + case ViewportEditorMode::Focus: + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode"); + } + break; + case ViewportEditorMode::Default: + case ViewportEditorMode::Pick: + // noop + break; } } void EditorTransformComponentSelection::OnEditorModeDeactivated( - [[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) + const ViewportEditorModesInterface& editorModeState, const ViewportEditorMode mode) { - if (mode == ViewportEditorMode::Component) + switch (mode) { - SetAllViewportUiVisible(true); + case ViewportEditorMode::Component: + { + SetAllViewportUiVisible(true); - ToolsApplicationNotificationBus::Handler::BusConnect(); - EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); - EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); + ToolsApplicationNotificationBus::Handler::BusConnect(); + EditorEntityVisibilityNotificationBus::Router::BusRouterConnect(); + EditorEntityLockComponentNotificationBus::Router::BusRouterConnect(); + + // note: when leaving component mode, we check if we're still in focus mode (i.e. component mode was + // started from within focus mode), if we are, ensure we create/update the viewport border (as leaving + // component mode will attempt to remove it) + if (editorModeState.IsModeActive(ViewportEditorMode::Focus)) + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateViewportBorder, "Focus Mode"); + } + } + break; + case ViewportEditorMode::Focus: + { + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveViewportBorder); + } + break; + case ViewportEditorMode::Default: + case ViewportEditorMode::Pick: + // noop + break; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp new file mode 100644 index 0000000000..dfff4da08f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.cpp @@ -0,0 +1,142 @@ +/* + * 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 + +AZ_CVAR(float, ed_invalidClickRadius, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum invalid click radius to expand to"); +AZ_CVAR(float, ed_invalidClickDuration, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Duration to display the invalid click feedback"); +AZ_CVAR(float, ed_invalidClickMessageSize, 0.8f, nullptr, AZ::ConsoleFunctorFlags::Null, "Size of text for invalid message"); +AZ_CVAR( + float, + ed_invalidClickMessageVerticalOffset, + 30.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Vertical offset from cursor of invalid click message"); + +namespace AzToolsFramework +{ + void ExpandingFadingCircles::Begin(const AzFramework::ScreenPoint& screenPoint) + { + FadingCircle fadingCircle; + fadingCircle.m_position = screenPoint; + fadingCircle.m_opacity = 1.0f; + fadingCircle.m_radius = 0.0f; + m_fadingCircles.push_back(fadingCircle); + } + + void ExpandingFadingCircles::Update(const float deltaTime) + { + for (auto& fadingCircle : m_fadingCircles) + { + fadingCircle.m_opacity = AZStd::max(fadingCircle.m_opacity - (deltaTime / ed_invalidClickDuration), 0.0f); + fadingCircle.m_radius += deltaTime * ed_invalidClickRadius; + } + + m_fadingCircles.erase( + AZStd::remove_if( + m_fadingCircles.begin(), m_fadingCircles.end(), + [](const FadingCircle& fadingCircle) + { + return fadingCircle.m_opacity <= 0.0f; + }), + m_fadingCircles.end()); + } + + bool ExpandingFadingCircles::Updating() + { + return !m_fadingCircles.empty(); + } + + void ExpandingFadingCircles::Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + const AZ::Vector2 viewportSize = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId).m_viewportSize; + + for (const auto& fadingCircle : m_fadingCircles) + { + const auto position = AzFramework::Vector2FromScreenPoint(fadingCircle.m_position) / viewportSize; + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, fadingCircle.m_opacity)); + debugDisplay.DrawWireCircle2d(position, fadingCircle.m_radius * 0.005f, 0.0f); + } + } + + void FadingText::Begin(const AzFramework::ScreenPoint& screenPoint) + { + m_opacity = 1.0f; + m_invalidClickPosition = screenPoint; + } + + void FadingText::Update(const float deltaTime) + { + m_opacity -= deltaTime / ed_invalidClickDuration; + } + + bool FadingText::Updating() + { + return m_opacity >= 0.0f; + } + + void FadingText::Display( + [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + if (constexpr float MinOpacity = 0.05f; m_opacity >= MinOpacity) + { + debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, m_opacity)); + debugDisplay.Draw2dTextLabel( + aznumeric_cast(m_invalidClickPosition.m_x), + aznumeric_cast(m_invalidClickPosition.m_y) - ed_invalidClickMessageVerticalOffset, ed_invalidClickMessageSize, + m_message.c_str(), true); + } + } + + void InvalidClicks::AddInvalidClick(const AzFramework::ScreenPoint& screenPoint) + { + AZ::TickBus::Handler::BusConnect(); + + for (auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Begin(screenPoint); + } + } + + void InvalidClicks::OnTick(const float deltaTime, [[maybe_unused]] const AZ::ScriptTimePoint time) + { + for (auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Update(deltaTime); + } + + const auto updating = AZStd::any_of( + m_invalidClickBehaviors.begin(), m_invalidClickBehaviors.end(), + [](const auto& invalidClickBehavior) + { + return invalidClickBehavior->Updating(); + }); + + if (!updating && AZ::TickBus::Handler::BusIsConnected()) + { + AZ::TickBus::Handler::BusDisconnect(); + } + } + + void InvalidClicks::Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + { + debugDisplay.DepthTestOff(); + + for (const auto& invalidClickBehavior : m_invalidClickBehaviors) + { + invalidClickBehavior->Display(viewportInfo, debugDisplay); + } + + debugDisplay.DepthTestOn(); + } +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h new file mode 100644 index 0000000000..55a6d614ea --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h @@ -0,0 +1,108 @@ +/* + * 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 AzFramework +{ + class DebugDisplayRequests; + struct ViewportInfo; +} // namespace AzFramework + +namespace AzToolsFramework +{ + namespace ViewportInteraction + { + struct MouseInteractionEvent; + } + + //! An interface to provide invalid click feedback in the editor viewport. + class InvalidClick + { + public: + virtual ~InvalidClick() = default; + + //! Begin the feedback. + //! @param screenPoint The position of the click in screen coordinates. + virtual void Begin(const AzFramework::ScreenPoint& screenPoint) = 0; + //! Update the invalid click feedback + virtual void Update(float deltaTime) = 0; + //! Report if the click feedback is running or not (returning false will signal the TickBus can be disconnected from). + virtual bool Updating() = 0; + //! Display the click feedback in the viewport. + virtual void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) = 0; + }; + + //! Display expanding fading circles for every click of the mouse that is invalid. + class ExpandingFadingCircles : public InvalidClick + { + public: + void Begin(const AzFramework::ScreenPoint& screenPoint) override; + void Update(float deltaTime) override; + bool Updating() override; + void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + private: + //! Stores a circle representation with a lifetime to grow and fade out over time. + struct FadingCircle + { + AzFramework::ScreenPoint m_position; + float m_radius; + float m_opacity; + }; + + using FadingCircles = AZStd::vector; + FadingCircles m_fadingCircles; //!< Collection of fading circles to draw for clicks that have no effect. + }; + + //! Display fading text where an invalid click happened. + //! @note There is only one fading text, each click will update its position. + class FadingText : public InvalidClick + { + public: + explicit FadingText(AZStd::string message) + : m_message(AZStd::move(message)) + { + } + + void Begin(const AzFramework::ScreenPoint& screenPoint) override; + void Update(float deltaTime) override; + bool Updating() override; + void Display(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + + private: + AZStd::string m_message; //!< Message to display for fading text. + float m_opacity = 1.0f; //!< The opacity of the invalid click message. + AzFramework::ScreenPoint m_invalidClickPosition; //!< The position to display the invalid click message. + }; + + //! Interface to begin invalid click feedback (will run all added InvalidClick behaviors). + class InvalidClicks : private AZ::TickBus::Handler + { + public: + explicit InvalidClicks(AZStd::vector> invalidClickBehaviors) + : m_invalidClickBehaviors(AZStd::move(invalidClickBehaviors)) + { + } + + //! Add an invalid click and activate one or more of the added invalid click behaviors. + void AddInvalidClick(const AzFramework::ScreenPoint& screenPoint); + + //! Handle 2d drawing for EditorHelper functionality. + void Display2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay); + + private: + //! AZ::TickBus overrides ... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + AZStd::vector> m_invalidClickBehaviors; //!< Invalid click behaviors to run. + }; +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index e27627eab6..a289d914d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -290,9 +290,9 @@ namespace AzToolsFramework::ViewportUi::Internal return false; } - void ViewportUiDisplay::CreateComponentModeBorder(const AZStd::string& borderTitle) + void ViewportUiDisplay::CreateViewportBorder(const AZStd::string& borderTitle) { - AZStd::string styleSheet = AZStd::string::format( + const AZStd::string styleSheet = AZStd::string::format( "border: %dpx solid %s; border-top: %dpx solid %s;", HighlightBorderSize, HighlightBorderColor, TopHighlightBorderSize, HighlightBorderColor); m_uiOverlay.setStyleSheet(styleSheet.c_str()); @@ -303,7 +303,7 @@ namespace AzToolsFramework::ViewportUi::Internal m_componentModeBorderText.setText(borderTitle.c_str()); } - void ViewportUiDisplay::RemoveComponentModeBorder() + void ViewportUiDisplay::RemoveViewportBorder() { m_componentModeBorderText.setVisible(false); m_uiOverlay.setStyleSheet("border: none;"); @@ -420,6 +420,7 @@ namespace AzToolsFramework::ViewportUi::Internal m_uiMainWindow.setVisible(true); m_uiOverlay.setVisible(true); } + m_uiMainWindow.setMask(region); } @@ -437,6 +438,7 @@ namespace AzToolsFramework::ViewportUi::Internal { return element->second; } + return ViewportUiElementInfo{ nullptr, InvalidViewportUiElementId, false }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h index aafaf61ff3..5020241815 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h @@ -89,8 +89,8 @@ namespace AzToolsFramework::ViewportUi::Internal AZStd::shared_ptr GetViewportUiElement(ViewportUiElementId elementId); bool IsViewportUiElementVisible(ViewportUiElementId elementId); - void CreateComponentModeBorder(const AZStd::string& borderTitle); - void RemoveComponentModeBorder(); + void CreateViewportBorder(const AZStd::string& borderTitle); + void RemoveViewportBorder(); private: void PrepareWidgetForViewportUi(QPointer widget); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp index 255d11f561..1f14b12b7d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp @@ -240,14 +240,14 @@ namespace AzToolsFramework::ViewportUi } } - void ViewportUiManager::CreateComponentModeBorder(const AZStd::string& borderTitle) + void ViewportUiManager::CreateViewportBorder(const AZStd::string& borderTitle) { - m_viewportUi->CreateComponentModeBorder(borderTitle); + m_viewportUi->CreateViewportBorder(borderTitle); } - void ViewportUiManager::RemoveComponentModeBorder() + void ViewportUiManager::RemoveViewportBorder() { - m_viewportUi->RemoveComponentModeBorder(); + m_viewportUi->RemoveViewportBorder(); } void ViewportUiManager::PressButton(ClusterId clusterId, ButtonId buttonId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h index 9ec6648451..ce7e5aafe9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h @@ -50,8 +50,8 @@ namespace AzToolsFramework::ViewportUi void RegisterTextFieldCallback(TextFieldId textFieldId, AZ::Event::Handler& handler) override; void RemoveTextField(TextFieldId textFieldId) override; void SetTextFieldVisible(TextFieldId textFieldId, bool visible) override; - void CreateComponentModeBorder(const AZStd::string& borderTitle) override; - void RemoveComponentModeBorder() override; + void CreateViewportBorder(const AZStd::string& borderTitle) override; + void RemoveViewportBorder() override; void PressButton(ClusterId clusterId, ButtonId buttonId) override; void PressButton(SwitcherId switcherId, ButtonId buttonId) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h index 108d23950a..3c6f7094cb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h @@ -78,7 +78,7 @@ namespace AzToolsFramework::ViewportUi virtual void RegisterSwitcherEventHandler(SwitcherId switcherId, AZ::Event::Handler& handler) = 0; //! Removes a cluster from the Viewport UI system. virtual void RemoveCluster(ClusterId clusterId) = 0; - //! + //! Removes a switcher from the Viewport UI system. virtual void RemoveSwitcher(SwitcherId switcherId) = 0; //! Sets the visibility of the cluster. virtual void SetClusterVisible(ClusterId clusterId, bool visible) = 0; @@ -96,12 +96,12 @@ namespace AzToolsFramework::ViewportUi //! Sets the visibility of the text field. virtual void SetTextFieldVisible(TextFieldId textFieldId, bool visible) = 0; //! Create the highlight border for Component Mode. - virtual void CreateComponentModeBorder(const AZStd::string& borderTitle) = 0; + virtual void CreateViewportBorder(const AZStd::string& borderTitle) = 0; //! Remove the highlight border for Component Mode. - virtual void RemoveComponentModeBorder() = 0; - //! Invoke a button press in a cluster. + virtual void RemoveViewportBorder() = 0; + //! Invoke a button press on a cluster. virtual void PressButton(ClusterId clusterId, ButtonId buttonId) = 0; - //! + //! Invoke a button press on a switcher. virtual void PressButton(SwitcherId switcherId, ButtonId buttonId) = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 8dec7ab611..5db65f89f4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -553,6 +553,8 @@ set(FILES ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp ViewportSelection/EditorVisibleEntityDataCache.h ViewportSelection/EditorVisibleEntityDataCache.cpp + ViewportSelection/InvalidClicks.h + ViewportSelection/InvalidClicks.cpp ViewportSelection/ViewportEditorModeTracker.cpp ViewportSelection/ViewportEditorModeTracker.h ToolsFileUtils/ToolsFileUtils.h diff --git a/Code/Framework/GridMate/Tests/Carrier.cpp b/Code/Framework/GridMate/Tests/Carrier.cpp index 5b18a80221..29550d8b68 100644 --- a/Code/Framework/GridMate/Tests/Carrier.cpp +++ b/Code/Framework/GridMate/Tests/Carrier.cpp @@ -333,7 +333,7 @@ namespace UnitTest }; template - class Integ_CarrierAsyncHandshakeTestTemplate + class CarrierAsyncHandshakeTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -761,7 +761,7 @@ namespace UnitTest }; template - class Integ_CarrierDisconnectDetectionTestTemplate + class CarrierDisconnectDetectionTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -846,7 +846,7 @@ namespace UnitTest * Sends reliable messages across different channels to each other */ template - class Integ_CarrierMultiChannelTestTemplate + class CarrierMultiChannelTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -950,7 +950,7 @@ namespace UnitTest * Stress tests multiple simultaneous Carriers */ template - class Integ_CarrierMultiStressTestTemplate + class CarrierMultiStressTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -977,7 +977,7 @@ namespace UnitTest public: void run() { - AZ_TracePrintf("GridMate", "Integ_CarrierMultiStressTest\n\n"); + AZ_TracePrintf("GridMate", "CarrierMultiStressTest\n\n"); // initialize transport const int k_numChannels = 1; @@ -1108,7 +1108,7 @@ namespace UnitTest /*** Congestion control back pressure test */ template - class Integ_CarrierBackpressureTestTemplate + class CarrierBackpressureTestTemplate : public GridMateMPTestFixture , protected SocketProvider , public CarrierEventBus::Handler @@ -1380,7 +1380,7 @@ namespace UnitTest }; template - class Integ_CarrierACKTestTemplate + class CarrierACKTestTemplate : public GridMateMPTestFixture , protected SocketProvider { @@ -1544,13 +1544,13 @@ namespace UnitTest //Create specific tests using CarrierBasicTest = CarrierBasicTestTemplate<>; using CarrierTest = CarrierTestTemplate<>; - using Integ_CarrierDisconnectDetectionTest = Integ_CarrierDisconnectDetectionTestTemplate<>; - using Integ_CarrierAsyncHandshakeTest = Integ_CarrierAsyncHandshakeTestTemplate<>; - using Integ_CarrierStressTest = CarrierStressTestTemplate<>; - using Integ_CarrierMultiChannelTest = Integ_CarrierMultiChannelTestTemplate<>; - using Integ_CarrierMultiStressTest = Integ_CarrierMultiStressTestTemplate<>; - using Integ_CarrierBackpressureTest = Integ_CarrierBackpressureTestTemplate<>; - using Integ_CarrierACKTest = Integ_CarrierACKTestTemplate<>; + using DISABLED_CarrierDisconnectDetectionTest = CarrierDisconnectDetectionTestTemplate<>; + using DISABLED_CarrierAsyncHandshakeTest = CarrierAsyncHandshakeTestTemplate<>; + using DISABLED_CarrierStressTest = CarrierStressTestTemplate<>; + using DISABLED_CarrierMultiChannelTest = CarrierMultiChannelTestTemplate<>; + using DISABLED_CarrierMultiStressTest = CarrierMultiStressTestTemplate<>; + using DISABLED_CarrierBackpressureTest = CarrierBackpressureTestTemplate<>; + using DISABLED_CarrierACKTest = CarrierACKTestTemplate<>; #if AZ_TRAIT_GRIDMATE_TEST_WITH_SECURE_SOCKET_DRIVER @@ -1658,20 +1658,20 @@ namespace UnitTest using SecureProviderBadHost = SecureDriverProvider>; using SecureProviderBadBoth = SecureDriverProvider, SecureSocketHandshakeDrop>; - using Integ_CarrierSecureSocketHandshakeTestClient = CarrierBasicTestTemplate; - using Integ_CarrierSecureSocketHandshakeTestHost = CarrierBasicTestTemplate; - using Integ_CarrierSecureSocketHandshakeTestBoth = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestClient = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestHost = CarrierBasicTestTemplate; + using DISABLED_CarrierSecureSocketHandshakeTestBoth = CarrierBasicTestTemplate; //Create secure socket variants of tests using CarrierBasicTestSecure = CarrierBasicTestTemplate>; using CarrierTestSecure = CarrierTestTemplate>; - using Integ_CarrierDisconnectDetectionTestSecure = Integ_CarrierDisconnectDetectionTestTemplate>; - using Integ_CarrierAsyncHandshakeTestSecure = Integ_CarrierAsyncHandshakeTestTemplate>; - using Integ_CarrierStressTestSecure = CarrierStressTestTemplate>; - using Integ_CarrierMultiChannelTestSecure = Integ_CarrierMultiChannelTestTemplate>; - using Integ_CarrierMultiStressTestSecure = Integ_CarrierMultiStressTestTemplate>; - using Integ_CarrierBackpressureTestSecure = Integ_CarrierBackpressureTestTemplate>; - using Integ_CarrierACKTestSecure = Integ_CarrierACKTestTemplate>; + using DISABLED_CarrierDisconnectDetectionTestSecure = CarrierDisconnectDetectionTestTemplate>; + using DISABLED_CarrierAsyncHandshakeTestSecure = CarrierAsyncHandshakeTestTemplate>; + using DISABLED_CarrierStressTestSecure = CarrierStressTestTemplate>; + using DISABLED_CarrierMultiChannelTestSecure = CarrierMultiChannelTestTemplate>; + using DISABLED_CarrierMultiStressTestSecure = CarrierMultiStressTestTemplate>; + using DISABLED_CarrierBackpressureTestSecure = CarrierBackpressureTestTemplate>; + using DISABLED_CarrierACKTestSecure = CarrierACKTestTemplate>; #endif } @@ -1720,30 +1720,30 @@ GM_TEST_SUITE(CarrierSuite) GM_TEST(CarrierBasicTest) GM_TEST(CarrierTest) #endif //AZ_TRAIT_GRIDMATE_UNIT_TEST_DISABLE_CARRIER_SESSION_TESTS -GM_TEST(Integ_CarrierAsyncHandshakeTest) +GM_TEST(DISABLED_CarrierAsyncHandshakeTest) #if !defined(AZ_DEBUG_BUILD) // this test is a little slow for debug -GM_TEST(Integ_CarrierStressTest) -GM_TEST(Integ_CarrierMultiStressTest) +GM_TEST(DISABLED_CarrierStressTest) +GM_TEST(DISABLED_CarrierMultiStressTest) #endif -GM_TEST(Integ_CarrierMultiChannelTest) -GM_TEST(Integ_CarrierBackpressureTest) -GM_TEST(Integ_CarrierACKTest) +GM_TEST(DISABLED_CarrierMultiChannelTest) +GM_TEST(DISABLED_CarrierBackpressureTest) +GM_TEST(DISABLED_CarrierACKTest) #if AZ_TRAIT_GRIDMATE_TEST_WITH_SECURE_SOCKET_DRIVER -GM_TEST(CarrierBasicTestSecure) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestClient) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestHost) -GM_TEST(Integ_CarrierSecureSocketHandshakeTestBoth) +GM_TEST(DISABLED_CarrierBasicTestSecure) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestClient) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestHost) +GM_TEST(DISABLED_CarrierSecureSocketHandshakeTestBoth) GM_TEST(CarrierTestSecure) -GM_TEST(Integ_CarrierAsyncHandshakeTestSecure) +GM_TEST(DISABLED_CarrierAsyncHandshakeTestSecure) #if !defined(AZ_DEBUG_BUILD) // this test is a little slow for debug -GM_TEST(Integ_CarrierStressTestSecure) -GM_TEST(Integ_CarrierMultiStressTestSecure) +GM_TEST(DISABLED_CarrierStressTestSecure) +GM_TEST(DISABLED_CarrierMultiStressTestSecure) #endif -GM_TEST(Integ_CarrierMultiChannelTestSecure) -GM_TEST(Integ_CarrierBackpressureTestSecure) -GM_TEST(Integ_CarrierACKTestSecure) +GM_TEST(DISABLED_CarrierMultiChannelTestSecure) +GM_TEST(DISABLED_CarrierBackpressureTestSecure) +GM_TEST(DISABLED_CarrierACKTestSecure) #endif diff --git a/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp index 8ec3ad540f..dd0d6f1b2b 100644 --- a/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/CarrierStreamSocketDriverTests.cpp @@ -172,7 +172,7 @@ public: namespace UnitTest { - class Integ_CarrierStreamBasicTest + class DISABLED_CarrierStreamBasicTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -330,7 +330,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamAsyncHandshakeTest + class DISABLED_CarrierStreamAsyncHandshakeTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -462,7 +462,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamStressTest + class CarrierStreamStressTest : public GridMateMPTestFixture , protected SocketDriverSupplier , public ::testing::Test @@ -470,7 +470,7 @@ namespace UnitTest public: }; - TEST_F(Integ_CarrierStreamStressTest, Stress_Test) + TEST_F(CarrierStreamStressTest, DISABLED_Stress_Test) { CarrierStreamCallbacksHandler clientCB, serverCB; UnitTest::TestCarrierDesc serverCarrierDesc, clientCarrierDesc; @@ -581,7 +581,7 @@ namespace UnitTest ////////////////////////////////////////////////////////////////////////// } - class Integ_CarrierStreamTest + class DISABLED_CarrierStreamTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -783,7 +783,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamDisconnectDetectionTest + class DISABLED_CarrierStreamDisconnectDetectionTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -873,7 +873,7 @@ namespace UnitTest } }; - class Integ_CarrierStreamMultiChannelTest + class DISABLED_CarrierStreamMultiChannelTest : public GridMateMPTestFixture , protected SocketDriverSupplier { @@ -999,8 +999,8 @@ namespace UnitTest } GM_TEST_SUITE(CarrierStreamSuite) - GM_TEST(Integ_CarrierStreamBasicTest) - GM_TEST(Integ_CarrierStreamTest) - GM_TEST(Integ_CarrierStreamAsyncHandshakeTest) - GM_TEST(Integ_CarrierStreamMultiChannelTest) + GM_TEST(DISABLED_CarrierStreamBasicTest) + GM_TEST(DISABLED_CarrierStreamTest) + GM_TEST(DISABLED_CarrierStreamAsyncHandshakeTest) + GM_TEST(DISABLED_CarrierStreamMultiChannelTest) GM_TEST_SUITE_END() diff --git a/Code/Framework/GridMate/Tests/Replica.cpp b/Code/Framework/GridMate/Tests/Replica.cpp index 83a3a1f5a1..5fef135347 100644 --- a/Code/Framework/GridMate/Tests/Replica.cpp +++ b/Code/Framework/GridMate/Tests/Replica.cpp @@ -6,7 +6,6 @@ * */ #include "Tests.h" -#include "TestProfiler.h" #include @@ -1888,12 +1887,12 @@ protected: }; //----------------------------------------------------------------------------- -class Integ_ReplicaGMTest +class ReplicaGMTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test {}; -TEST_F(Integ_ReplicaGMTest, ReplicaTest) +TEST_F(ReplicaGMTest, DISABLED_ReplicaTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -2157,7 +2156,7 @@ TEST_F(Integ_ReplicaGMTest, ReplicaTest) } } -class Integ_ForcedReplicaMigrationTest +class ForcedReplicaMigrationTest : public UnitTest::GridMateMPTestFixture , public ReplicaMgrCallbackBus::Handler , public MigratableReplica::MigratableReplicaDebugMsgs::EBus::Handler @@ -2186,8 +2185,8 @@ class Integ_ForcedReplicaMigrationTest } public: - Integ_ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } - ~Integ_ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } + ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } + ~ForcedReplicaMigrationTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } enum @@ -2205,11 +2204,11 @@ public: AZStd::unordered_map m_replicaOwnership; }; -const int Integ_ForcedReplicaMigrationTest::k_frameTimePerNodeMs; -const int Integ_ForcedReplicaMigrationTest::k_numFramesToRun; -const int Integ_ForcedReplicaMigrationTest::k_hostSendRateMs; +const int ForcedReplicaMigrationTest::k_frameTimePerNodeMs; +const int ForcedReplicaMigrationTest::k_numFramesToRun; +const int ForcedReplicaMigrationTest::k_hostSendRateMs; -TEST_F(Integ_ForcedReplicaMigrationTest, ForcedReplicaMigrationTest) +TEST_F(ForcedReplicaMigrationTest, DISABLED_ForcedReplicaMigrationTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -2360,7 +2359,7 @@ TEST_F(Integ_ForcedReplicaMigrationTest, ForcedReplicaMigrationTest) MigratableReplica::MigratableReplicaDebugMsgs::EBus::Handler::BusDisconnect(); } -class Integ_ReplicaMigrationRequestTest +class ReplicaMigrationRequestTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -2516,7 +2515,7 @@ public: static const int k_hostSendTimeMs = k_frameTimePerNodeMs * TotalNodes * 4; // limiting host send rate to be x4 times slower than tick }; -TEST_F(Integ_ReplicaMigrationRequestTest, ReplicaMigrationRequestTest) +TEST_F(ReplicaMigrationRequestTest, DISABLED_ReplicaMigrationRequestTest) { /* Topology: @@ -2837,11 +2836,11 @@ TEST_F(Integ_ReplicaMigrationRequestTest, ReplicaMigrationRequestTest) } } -const int Integ_ReplicaMigrationRequestTest::k_frameTimePerNodeMs; -const int Integ_ReplicaMigrationRequestTest::k_hostSendTimeMs; +const int ReplicaMigrationRequestTest::k_frameTimePerNodeMs; +const int ReplicaMigrationRequestTest::k_hostSendTimeMs; -class Integ_PeerRejoinTest +class PeerRejoinTest : public UnitTest::GridMateMPTestFixture , public ReplicaMgrCallbackBus::Handler , public ::testing::Test @@ -2860,11 +2859,11 @@ class Integ_PeerRejoinTest } public: - Integ_PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } - ~Integ_PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } + PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusConnect(m_gridMate); } + ~PeerRejoinTest() { ReplicaMgrCallbackBus::Handler::BusDisconnect(); } }; -TEST_F(Integ_PeerRejoinTest, PeerRejoinTest) +TEST_F(PeerRejoinTest, DISABLED_PeerRejoinTest) { ReplicaChunkDescriptorTable::Get().RegisterChunkType(); ReplicaChunkDescriptorTable::Get().RegisterChunkType(); @@ -3011,7 +3010,7 @@ TEST_F(Integ_PeerRejoinTest, PeerRejoinTest) } } -class Integ_ReplicationSecurityOptionsTest +class ReplicationSecurityOptionsTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -3156,7 +3155,7 @@ public: using TestChunkPtr = AZStd::intrusive_ptr ; }; -TEST_F(Integ_ReplicationSecurityOptionsTest, ReplicationSecurityOptionsTest) +TEST_F(ReplicationSecurityOptionsTest, DISABLED_ReplicationSecurityOptionsTest) { AZ_TracePrintf("GridMate", "\n"); @@ -3356,7 +3355,7 @@ TEST_F(Integ_ReplicationSecurityOptionsTest, ReplicationSecurityOptionsTest) Replica update time (msec): avg=4.94, min=1, max=9 (peers=40, replicas=16000, freq=10%, samples=4000) Replica update time (msec): avg=8.05, min=6, max=15 (peers=40, replicas=16000, freq=100%, samples=4000) */ -class Integ_ReplicaStressTest +class DISABLED_ReplicaStressTest : public UnitTest::GridMateMPTestFixture { public: @@ -3388,7 +3387,7 @@ public: static const int BASE_PORT = 44270; // TODO: Reduce the size or disable the test for platforms which can't allocate 2 GiB - Integ_ReplicaStressTest() + DISABLED_ReplicaStressTest() : UnitTest::GridMateMPTestFixture(2000u * 1024u * 1024u) {} @@ -3516,33 +3515,33 @@ public: virtual void RunStressTests(MPSession* sessions, vector >& replicas) { // testing 3 cases & waiting for system to settle in between - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); Wait(sessions, replicas, 50, FRAME_TIME); - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.0); // no replicas are dirty - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 1, FRAME_TIME, 1.0); // single burst dirty replicas Wait(sessions, replicas, 2, FRAME_TIME); - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.1); // 10% of replicas are marked dirty every frame - TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 1.0); // every replica is marked dirty every frame - TestProfiler::PrintProfilingTotal("GridMate"); - TestProfiler::PrintProfilingSelf("GridMate"); + //TestProfiler::PrintProfilingTotal("GridMate"); + //TestProfiler::PrintProfilingSelf("GridMate"); - TestProfiler::StopProfiling(); + //TestProfiler::StopProfiling(); } virtual void MarkChanging(vector >& replicas, double freq) @@ -3623,8 +3622,8 @@ public: Replica update time (msec): avg=2.01, min=1, max=5 (peers=40, replicas=16000, freq=10%, samples=4000) Replica update time (msec): avg=4.61, min=3, max=10 (peers=40, replicas=16000, freq=50%, samples=4000) */ -class Integ_ReplicaStableStressTest - : public Integ_ReplicaStressTest +class DISABLED_ReplicaStableStressTest + : public DISABLED_ReplicaStressTest { public: @@ -3636,21 +3635,21 @@ public: void RunStressTests(MPSession* sessions, vector >& replicas) override { - Integ_ReplicaStressTest::MarkChanging(replicas, 0.1); // picks 10% of replicas + DISABLED_ReplicaStressTest::MarkChanging(replicas, 0.1); // picks 10% of replicas Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.1); - TestProfiler::PrintProfilingTotal("GridMate"); - TestProfiler::PrintProfilingSelf("GridMate"); + /*TestProfiler::PrintProfilingTotal("GridMate"); + TestProfiler::PrintProfilingSelf("GridMate");*/ - Integ_ReplicaStressTest::MarkChanging(replicas, 0.5); // picks 50% of replicas + DISABLED_ReplicaStressTest::MarkChanging(replicas, 0.5); // picks 50% of replicas Wait(sessions, replicas, 20, FRAME_TIME); - TestProfiler::StartProfiling(); + //TestProfiler::StartProfiling(); TestReplicas(sessions, replicas, 100, FRAME_TIME, 0.5); - TestProfiler::PrintProfilingTotal("GridMate"); + /*TestProfiler::PrintProfilingTotal("GridMate"); TestProfiler::PrintProfilingSelf("GridMate"); - TestProfiler::StopProfiling(); + TestProfiler::StopProfiling();*/ } }; @@ -3666,7 +3665,7 @@ public: * expected |none |brst | capped |under cap |brst | capped | * */ -class Integ_ReplicaBandiwdthTest +class DISABLED_ReplicaBandiwdthTest : public UnitTest::GridMateMPTestFixture { public: @@ -3944,9 +3943,9 @@ GM_TEST_SUITE(ReplicaSuite) GM_TEST(InterpolatorTest) #if !defined(AZ_DEBUG_BUILD) // these tests are a little slow for debug -GM_TEST(Integ_ReplicaBandiwdthTest) -GM_TEST(Integ_ReplicaStressTest) -GM_TEST(Integ_ReplicaStableStressTest) +GM_TEST(DISABLED_ReplicaBandiwdthTest) +GM_TEST(DISABLED_ReplicaStressTest) +GM_TEST(DISABLED_ReplicaStableStressTest) #endif GM_TEST_SUITE_END() diff --git a/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp b/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp index f6f88d2dff..86f9f4605b 100644 --- a/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp +++ b/Code/Framework/GridMate/Tests/ReplicaBehavior.cpp @@ -457,13 +457,13 @@ namespace ReplicaBehavior { Completed, }; - class Integ_SimpleBehaviorTest + class SimpleBehaviorTest : public UnitTest::GridMateMPTestFixture { public: //GM_CLASS_ALLOCATOR(SimpleBehaviorTest); - Integ_SimpleBehaviorTest() + SimpleBehaviorTest() : m_sessionCount(0) { } virtual int GetNumSessions() { return 0; } @@ -654,11 +654,11 @@ namespace ReplicaBehavior { * * This is a simple sanity check to ensure the logic sends the update when it's necessary. */ - class Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData - : public Integ_SimpleBehaviorTest + class Replica_DontSendDataSets_WithNoDiffFromCtorData + : public SimpleBehaviorTest { public: - Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData() + Replica_DontSendDataSets_WithNoDiffFromCtorData() : m_replicaIdDefault(InvalidReplicaId), m_replicaIdModified(InvalidReplicaId) { } @@ -774,9 +774,9 @@ namespace ReplicaBehavior { FilteredHook m_driller; }; - TEST(Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData, Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData) + TEST(Replica_DontSendDataSets_WithNoDiffFromCtorData, DISABLED_Replica_DontSendDataSets_WithNoDiffFromCtorData) { - Integ_Replica_DontSendDataSets_WithNoDiffFromCtorData tester; + Replica_DontSendDataSets_WithNoDiffFromCtorData tester; tester.run(); } @@ -784,11 +784,11 @@ namespace ReplicaBehavior { * This test checks the actual size of the replica as marshalled in the binary payload. * The assessment of the payload size is done using driller EBus. */ - class Integ_ReplicaDefaultDataSetDriller - : public Integ_SimpleBehaviorTest + class ReplicaDefaultDataSetDriller + : public SimpleBehaviorTest { public: - Integ_ReplicaDefaultDataSetDriller() + ReplicaDefaultDataSetDriller() : m_replicaId(InvalidReplicaId) { } @@ -815,7 +815,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_ReplicaDefaultDataSetDriller() override + ~ReplicaDefaultDataSetDriller() override { m_driller.BusDisconnect(); } @@ -880,11 +880,11 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - const int Integ_ReplicaDefaultDataSetDriller::NonDefaultValue; + const int ReplicaDefaultDataSetDriller::NonDefaultValue; - TEST(Integ_ReplicaDefaultDataSetDriller, Integ_ReplicaDefaultDataSetDriller) + TEST(ReplicaDefaultDataSetDriller, DISABLED_ReplicaDefaultDataSetDriller) { - Integ_ReplicaDefaultDataSetDriller tester; + ReplicaDefaultDataSetDriller tester; tester.run(); } @@ -892,11 +892,11 @@ namespace ReplicaBehavior { * This test checks the actual size of the replica as marshalled in the binary payload. * The assessment of the payload size is done using driller EBus. */ - class Integ_Replica_ComparePackingBoolsVsU8 - : public Integ_SimpleBehaviorTest + class Replica_ComparePackingBoolsVsU8 + : public SimpleBehaviorTest { public: - Integ_Replica_ComparePackingBoolsVsU8() + Replica_ComparePackingBoolsVsU8() : m_replicaBoolsId(InvalidReplicaId) , m_replicaU8Id(InvalidReplicaId) { @@ -928,7 +928,7 @@ namespace ReplicaBehavior { m_replicaU8Id = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica2); } - ~Integ_Replica_ComparePackingBoolsVsU8() override + ~Replica_ComparePackingBoolsVsU8() override { m_driller.BusDisconnect(); } @@ -1020,17 +1020,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaU8Id; }; - TEST(Integ_Replica_ComparePackingBoolsVsU8, Integ_Replica_ComparePackingBoolsVsU8) + TEST(Replica_ComparePackingBoolsVsU8, DISABLED_Replica_ComparePackingBoolsVsU8) { - Integ_Replica_ComparePackingBoolsVsU8 tester; + Replica_ComparePackingBoolsVsU8 tester; tester.run(); } - class Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary - : public Integ_SimpleBehaviorTest + class CheckDataSetStreamIsntWrittenMoreThanNecessary + : public SimpleBehaviorTest { public: - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary() + CheckDataSetStreamIsntWrittenMoreThanNecessary() : m_replicaId(InvalidReplicaId) { } @@ -1057,7 +1057,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary() override + ~CheckDataSetStreamIsntWrittenMoreThanNecessary() override { m_driller.BusDisconnect(); } @@ -1117,17 +1117,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary, Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary) + TEST(CheckDataSetStreamIsntWrittenMoreThanNecessary, DISABLED_CheckDataSetStreamIsntWrittenMoreThanNecessary) { - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessary tester; + CheckDataSetStreamIsntWrittenMoreThanNecessary tester; tester.run(); } - class Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty - : public Integ_SimpleBehaviorTest + class CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty + : public SimpleBehaviorTest { public: - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() + CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() : m_replicaId(InvalidReplicaId) { } @@ -1154,7 +1154,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() override + ~CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty() override { m_driller.BusDisconnect(); } @@ -1213,17 +1213,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty, Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty) + TEST(CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty, DISABLED_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty) { - Integ_CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty tester; + CheckDataSetStreamIsntWrittenMoreThanNecessaryOnceDirty tester; tester.run(); } - class Integ_CheckReplicaIsntSentWithNoChanges - : public Integ_SimpleBehaviorTest + class CheckReplicaIsntSentWithNoChanges + : public SimpleBehaviorTest { public: - Integ_CheckReplicaIsntSentWithNoChanges() + CheckReplicaIsntSentWithNoChanges() : m_replicaId(InvalidReplicaId) { } @@ -1248,7 +1248,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckReplicaIsntSentWithNoChanges() override + ~CheckReplicaIsntSentWithNoChanges() override { m_driller.BusDisconnect(); } @@ -1323,17 +1323,17 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckReplicaIsntSentWithNoChanges, Integ_CheckReplicaIsntSentWithNoChanges) + TEST(CheckReplicaIsntSentWithNoChanges, DISABLED_CheckReplicaIsntSentWithNoChanges) { - Integ_CheckReplicaIsntSentWithNoChanges tester; + CheckReplicaIsntSentWithNoChanges tester; tester.run(); } - class Integ_CheckEntityScriptReplicaIsntSentWithNoChanges - : public Integ_SimpleBehaviorTest + class CheckEntityScriptReplicaIsntSentWithNoChanges + : public SimpleBehaviorTest { public: - Integ_CheckEntityScriptReplicaIsntSentWithNoChanges() + CheckEntityScriptReplicaIsntSentWithNoChanges() : m_replicaId(InvalidReplicaId) { } @@ -1359,7 +1359,7 @@ namespace ReplicaBehavior { m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_CheckEntityScriptReplicaIsntSentWithNoChanges() override + ~CheckEntityScriptReplicaIsntSentWithNoChanges() override { m_driller.BusDisconnect(); } @@ -1410,9 +1410,9 @@ namespace ReplicaBehavior { ReplicaId m_replicaId; }; - TEST(Integ_CheckEntityScriptReplicaIsntSentWithNoChanges, Integ_CheckEntityScriptReplicaIsntSentWithNoChanges) + TEST(CheckEntityScriptReplicaIsntSentWithNoChanges, DISABLED_CheckEntityScriptReplicaIsntSentWithNoChanges) { - Integ_CheckEntityScriptReplicaIsntSentWithNoChanges tester; + CheckEntityScriptReplicaIsntSentWithNoChanges tester; tester.run(); } diff --git a/Code/Framework/GridMate/Tests/ReplicaMedium.cpp b/Code/Framework/GridMate/Tests/ReplicaMedium.cpp index 61fe9d65b2..2e8d2a3a73 100644 --- a/Code/Framework/GridMate/Tests/ReplicaMedium.cpp +++ b/Code/Framework/GridMate/Tests/ReplicaMedium.cpp @@ -596,12 +596,12 @@ public: //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -class MPSession +class MPSessionMedium : public CarrierEventBus::Handler { public: - ~MPSession() override + ~MPSessionMedium() override { CarrierEventBus::Handler::BusDisconnect(); } @@ -708,14 +708,14 @@ enum class TestStatus Completed, }; -class Integ_SimpleTest +class SimpleTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { public: - //GM_CLASS_ALLOCATOR(Integ_SimpleTest); + //GM_CLASS_ALLOCATOR(SimpleTest); - Integ_SimpleTest() + SimpleTest() : m_sessionCount(0) { } virtual int GetNumSessions() { return 0; } @@ -858,15 +858,15 @@ public: } int m_sessionCount; - AZStd::array m_sessions; + AZStd::array m_sessions; AZStd::unique_ptr m_defaultSimulator; }; -class Integ_ReplicaChunkRPCExec - : public Integ_SimpleTest +class ReplicaChunkRPCExec + : public SimpleTest { public: - Integ_ReplicaChunkRPCExec() + ReplicaChunkRPCExec() : m_chunk(nullptr) , m_replicaId(0) { } @@ -893,7 +893,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunkRPCExec, ReplicaChunkRPCExec) +TEST_F(ReplicaChunkRPCExec, DISABLED_ReplicaChunkRPCExec) { RunTickLoop([this](int tick) -> TestStatus { @@ -1050,8 +1050,8 @@ int DestroyRPCChunk::s_afterDestroyFromPrimaryCalls = 0; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -class Integ_ReplicaDestroyedInRPC - : public Integ_SimpleTest +class ReplicaDestroyedInRPC + : public SimpleTest { public: enum @@ -1080,7 +1080,7 @@ public: ReplicaId m_repId[2]; }; -TEST_F(Integ_ReplicaDestroyedInRPC, ReplicaDestroyedInRPC) +TEST_F(ReplicaDestroyedInRPC, DISABLED_ReplicaDestroyedInRPC) { RunTickLoop([this](int tick)->TestStatus { @@ -1129,11 +1129,11 @@ TEST_F(Integ_ReplicaDestroyedInRPC, ReplicaDestroyedInRPC) }); } -class Integ_ReplicaChunkAddWhileReplicated - : public Integ_SimpleTest +class ReplicaChunkAddWhileReplicated + : public SimpleTest { public: - Integ_ReplicaChunkAddWhileReplicated() + ReplicaChunkAddWhileReplicated() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1161,7 +1161,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunkAddWhileReplicated, ReplicaChunkAddWhileReplicated) +TEST_F(ReplicaChunkAddWhileReplicated, DISABLED_ReplicaChunkAddWhileReplicated) { RunTickLoop([this](int tick)-> TestStatus { @@ -1203,11 +1203,11 @@ TEST_F(Integ_ReplicaChunkAddWhileReplicated, ReplicaChunkAddWhileReplicated) } -class Integ_ReplicaRPCValues - : public Integ_SimpleTest +class ReplicaRPCValues + : public SimpleTest { public: - Integ_ReplicaRPCValues() + ReplicaRPCValues() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1236,7 +1236,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaRPCValues, ReplicaRPCValues) +TEST_F(ReplicaRPCValues, DISABLED_ReplicaRPCValues) { RunTickLoop([this](int tick)-> TestStatus { @@ -1257,11 +1257,11 @@ TEST_F(Integ_ReplicaRPCValues, ReplicaRPCValues) }); } -class Integ_FullRPCValues - : public Integ_SimpleTest +class FullRPCValues + : public SimpleTest { public: - Integ_FullRPCValues() + FullRPCValues() : m_replica(nullptr) , m_chunk(nullptr) , m_replicaId(0) @@ -1290,7 +1290,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_FullRPCValues, FullRPCValues) +TEST_F(FullRPCValues, DISABLED_FullRPCValues) { RunTickLoop([this](int tick)-> TestStatus { @@ -1364,11 +1364,11 @@ TEST_F(Integ_FullRPCValues, FullRPCValues) } -class Integ_ReplicaRemoveProxy - : public Integ_SimpleTest +class ReplicaRemoveProxy + : public SimpleTest { public: - Integ_ReplicaRemoveProxy() + ReplicaRemoveProxy() : m_replica(nullptr) , m_replicaId(0) { @@ -1395,7 +1395,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaRemoveProxy, ReplicaRemoveProxy) +TEST_F(ReplicaRemoveProxy, DISABLED_ReplicaRemoveProxy) { RunTickLoop([this](int tick)-> TestStatus { @@ -1424,11 +1424,11 @@ TEST_F(Integ_ReplicaRemoveProxy, ReplicaRemoveProxy) } -class Integ_ReplicaChunkEvents - : public Integ_SimpleTest +class ReplicaChunkEvents + : public SimpleTest { public: - Integ_ReplicaChunkEvents() + ReplicaChunkEvents() : m_replicaId(InvalidReplicaId) , m_chunk(nullptr) , m_proxyChunk(nullptr) @@ -1463,7 +1463,7 @@ public: AllEventChunk::Ptr m_proxyChunk; }; -TEST_F(Integ_ReplicaChunkEvents, ReplicaChunkEvents) +TEST_F(ReplicaChunkEvents, DISABLED_ReplicaChunkEvents) { RunTickLoop([this](int tick)-> TestStatus { @@ -1501,11 +1501,11 @@ TEST_F(Integ_ReplicaChunkEvents, ReplicaChunkEvents) } -class Integ_ReplicaChunksBeyond32 - : public Integ_SimpleTest +class ReplicaChunksBeyond32 + : public SimpleTest { public: - Integ_ReplicaChunksBeyond32() + ReplicaChunksBeyond32() : m_replicaId(InvalidReplicaId) { } @@ -1537,7 +1537,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaChunksBeyond32, ReplicaChunksBeyond32) +TEST_F(ReplicaChunksBeyond32, DISABLED_ReplicaChunksBeyond32) { RunTickLoop([this](int tick)-> TestStatus { @@ -1565,11 +1565,11 @@ TEST_F(Integ_ReplicaChunksBeyond32, ReplicaChunksBeyond32) } -class Integ_ReplicaChunkEventsDeactivate - : public Integ_SimpleTest +class ReplicaChunkEventsDeactivate + : public SimpleTest { public: - Integ_ReplicaChunkEventsDeactivate() + ReplicaChunkEventsDeactivate() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -1604,7 +1604,7 @@ public: AllEventChunk::Ptr m_proxyChunk; }; -TEST_F(Integ_ReplicaChunkEventsDeactivate, ReplicaChunkEventsDeactivate) +TEST_F(ReplicaChunkEventsDeactivate, DISABLED_ReplicaChunkEventsDeactivate) { RunTickLoop([this](int tick)-> TestStatus { @@ -1649,11 +1649,11 @@ TEST_F(Integ_ReplicaChunkEventsDeactivate, ReplicaChunkEventsDeactivate) } -class Integ_ReplicaDriller - : public Integ_SimpleTest +class ReplicaDriller + : public SimpleTest { public: - Integ_ReplicaDriller() + ReplicaDriller() : m_replicaId(InvalidReplicaId) { } @@ -2007,7 +2007,7 @@ public: m_replicaId = m_sessions[sHost].GetReplicaMgr().AddPrimary(replica); } - ~Integ_ReplicaDriller() override + ~ReplicaDriller() override { m_driller.BusDisconnect(); } @@ -2016,7 +2016,7 @@ public: ReplicaId m_replicaId; }; -TEST_F(Integ_ReplicaDriller, ReplicaDriller) +TEST_F(ReplicaDriller, DISABLED_ReplicaDriller) { RunTickLoop([this](int tick)-> TestStatus { @@ -2082,11 +2082,11 @@ TEST_F(Integ_ReplicaDriller, ReplicaDriller) } -class Integ_DataSetChangedTest - : public Integ_SimpleTest +class DataSetChangedTest + : public SimpleTest { public: - Integ_DataSetChangedTest() + DataSetChangedTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2115,7 +2115,7 @@ public: DataSetChunk::Ptr m_chunk; }; -TEST_F(Integ_DataSetChangedTest, DataSetChangedTest) +TEST_F(DataSetChangedTest, DISABLED_DataSetChangedTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2144,11 +2144,11 @@ TEST_F(Integ_DataSetChangedTest, DataSetChangedTest) } -class Integ_CustomHandlerTest - : public Integ_SimpleTest +class CustomHandlerTest + : public SimpleTest { public: - Integ_CustomHandlerTest() + CustomHandlerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2181,7 +2181,7 @@ public: AZStd::scoped_ptr m_proxyHandler; }; -TEST_F(Integ_CustomHandlerTest, CustomHandlerTest) +TEST_F(CustomHandlerTest, DISABLED_CustomHandlerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2234,11 +2234,11 @@ TEST_F(Integ_CustomHandlerTest, CustomHandlerTest) } -class Integ_NonConstMarshalerTest - : public Integ_SimpleTest +class NonConstMarshalerTest + : public SimpleTest { public: - Integ_NonConstMarshalerTest() + NonConstMarshalerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2266,7 +2266,7 @@ public: NonConstMarshalerChunk::Ptr m_chunk; }; -TEST_F(Integ_NonConstMarshalerTest, NonConstMarshalerTest) +TEST_F(NonConstMarshalerTest, DISABLED_NonConstMarshalerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2309,11 +2309,11 @@ TEST_F(Integ_NonConstMarshalerTest, NonConstMarshalerTest) } -class Integ_SourcePeerTest - : public Integ_SimpleTest +class SourcePeerTest + : public SimpleTest { public: - Integ_SourcePeerTest() + SourcePeerTest() : m_replica(nullptr) , m_replicaId(0) , m_chunk(nullptr) @@ -2343,7 +2343,7 @@ public: SourcePeerChunk::Ptr m_chunk2; }; -TEST_F(Integ_SourcePeerTest, SourcePeerTest) +TEST_F(SourcePeerTest, DISABLED_SourcePeerTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2404,8 +2404,8 @@ TEST_F(Integ_SourcePeerTest, SourcePeerTest) } -class Integ_SendWithPriority - : public Integ_SimpleTest +class SendWithPriority + : public SimpleTest { public: enum @@ -2438,8 +2438,8 @@ public: { public: ReplicaDrillerHook() - : m_expectedSendValue(Integ_SendWithPriority::kNumReplicas) - , m_expectedRecvValue(Integ_SendWithPriority::kNumReplicas) + : m_expectedSendValue(SendWithPriority::kNumReplicas) + , m_expectedRecvValue(SendWithPriority::kNumReplicas) { } @@ -2495,7 +2495,7 @@ public: PriorityChunk::Ptr m_chunks[kNumReplicas]; }; -TEST_F(Integ_SendWithPriority, SendWithPriority) +TEST_F(SendWithPriority, DISABLED_SendWithPriority) { RunTickLoop([this](int tick)-> TestStatus { @@ -2511,8 +2511,8 @@ TEST_F(Integ_SendWithPriority, SendWithPriority) } -class Integ_SuspendUpdatesTest - : public Integ_SimpleTest +class SuspendUpdatesTest + : public SimpleTest { public: enum @@ -2597,7 +2597,7 @@ public: unsigned int m_numRpcCalled = 0; }; -TEST_F(Integ_SuspendUpdatesTest, SuspendUpdatesTest) +TEST_F(SuspendUpdatesTest, DISABLED_SuspendUpdatesTest) { RunTickLoop([this](int tick)-> TestStatus { @@ -2657,7 +2657,7 @@ TEST_F(Integ_SuspendUpdatesTest, SuspendUpdatesTest) } -class Integ_BasicHostChunkDescriptorTest +class BasicHostChunkDescriptorTest : public UnitTest::GridMateMPTestFixture , public ::testing::Test { @@ -2694,17 +2694,17 @@ public: static int nProxyActivations; }; }; -int Integ_BasicHostChunkDescriptorTest::HostChunk::nPrimaryActivations = 0; -int Integ_BasicHostChunkDescriptorTest::HostChunk::nProxyActivations = 0; +int BasicHostChunkDescriptorTest::HostChunk::nPrimaryActivations = 0; +int BasicHostChunkDescriptorTest::HostChunk::nProxyActivations = 0; -TEST_F(Integ_BasicHostChunkDescriptorTest, BasicHostChunkDescriptorTest) +TEST_F(BasicHostChunkDescriptorTest, DISABLED_BasicHostChunkDescriptorTest) { AZ_TracePrintf("GridMate", "\n"); // Register test chunks ReplicaChunkDescriptorTable::Get().RegisterChunkType>(); - MPSession nodes[nNodes]; + MPSessionMedium nodes[nNodes]; // initialize transport int basePort = 4427; @@ -2791,8 +2791,8 @@ TEST_F(Integ_BasicHostChunkDescriptorTest, BasicHostChunkDescriptorTest) * Create and immedietly destroy primary replica * Test that it does not result in any network sync */ -class Integ_CreateDestroyPrimary - : public Integ_SimpleTest +class CreateDestroyPrimary + : public SimpleTest , public Debug::ReplicaDrillerBus::Handler { public: @@ -2827,7 +2827,7 @@ public: } }; -TEST_F(Integ_CreateDestroyPrimary, CreateDestroyPrimary) +TEST_F(CreateDestroyPrimary, DISABLED_CreateDestroyPrimary) { RunTickLoop([this](int tick)-> TestStatus { @@ -2861,7 +2861,7 @@ TEST_F(Integ_CreateDestroyPrimary, CreateDestroyPrimary) * The ReplicaTarget will prevent sending more updates. */ class ReplicaACKfeedbackTestFixture - : public Integ_SimpleTest + : public SimpleTest { public: ReplicaACKfeedbackTestFixture() @@ -2900,7 +2900,7 @@ public: size_t m_replicaBytesSentPrev = 0; ReplicaId m_replicaId; - Integ_ReplicaDriller::ReplicaDrillerHook m_driller; + ReplicaDriller::ReplicaDrillerHook m_driller; }; TEST_F(ReplicaACKfeedbackTestFixture, ReplicaACKfeedbackTest) diff --git a/Code/Framework/GridMate/Tests/Session.cpp b/Code/Framework/GridMate/Tests/Session.cpp index d4f56871c5..c793c3d450 100644 --- a/Code/Framework/GridMate/Tests/Session.cpp +++ b/Code/Framework/GridMate/Tests/Session.cpp @@ -40,7 +40,7 @@ namespace UnitTest } } - class Integ_LANSessionMatchmakingParamsTest + class DISABLED_LANSessionMatchmakingParamsTest : public GridMateMPTestFixture , public SessionEventBus::MultiHandler { @@ -52,7 +52,7 @@ namespace UnitTest } public: - Integ_LANSessionMatchmakingParamsTest(bool useIPv6 = false) + DISABLED_LANSessionMatchmakingParamsTest(bool useIPv6 = false) : m_hostSession(nullptr) , m_clientGridMate(nullptr) { @@ -71,7 +71,7 @@ namespace UnitTest AZ_TEST_ASSERT(GridMate::LANSessionServiceBus::FindFirstHandler(m_clientGridMate) != nullptr); ////////////////////////////////////////////////////////////////////////// } - ~Integ_LANSessionMatchmakingParamsTest() override + ~DISABLED_LANSessionMatchmakingParamsTest() override { SessionEventBus::MultiHandler::BusDisconnect(m_gridMate); SessionEventBus::MultiHandler::BusDisconnect(m_clientGridMate); @@ -192,7 +192,7 @@ namespace UnitTest IGridMate* m_clientGridMate; }; - class Integ_LANSessionTest + class DISABLED_LANSessionTest : public GridMateMPTestFixture { class TestPeerInfo @@ -264,7 +264,7 @@ namespace UnitTest }; public: - Integ_LANSessionTest(bool useIPv6 = false) + DISABLED_LANSessionTest(bool useIPv6 = false) { m_driverType = useIPv6 ? Driver::BSD_AF_INET6 : Driver::BSD_AF_INET; m_doSessionParamsTest = k_numMachines > 1; @@ -290,7 +290,7 @@ namespace UnitTest AZ_TEST_ASSERT(LANSessionServiceBus::FindFirstHandler(m_peers[i].m_gridMate) != nullptr); } } - ~Integ_LANSessionTest() override + ~DISABLED_LANSessionTest() override { StopGridMateService(m_peers[0].m_gridMate); @@ -555,15 +555,15 @@ namespace UnitTest bool m_doSessionParamsTest; }; - class Integ_LANSessionTestIPv6 - : public Integ_LANSessionTest + class DISABLED_LANSessionTestIPv6 + : public DISABLED_LANSessionTest { public: - Integ_LANSessionTestIPv6() - : Integ_LANSessionTest(true) {} + DISABLED_LANSessionTestIPv6() + : DISABLED_LANSessionTest(true) {} }; - class Integ_LANMultipleSessionTest + class DISABLED_LANMultipleSessionTest : public GridMateMPTestFixture , public SessionEventBus::Handler { @@ -620,7 +620,7 @@ namespace UnitTest m_sessions[i] = nullptr; } - Integ_LANMultipleSessionTest() + DISABLED_LANMultipleSessionTest() : GridMateMPTestFixture(200 * 1024 * 1024) { ////////////////////////////////////////////////////////////////////////// @@ -645,7 +645,7 @@ namespace UnitTest } } - ~Integ_LANMultipleSessionTest() override + ~DISABLED_LANMultipleSessionTest() override { GridMate::StopGridMateService(m_gridMates[0]); @@ -799,7 +799,7 @@ namespace UnitTest * Testing session with low latency. This is special mode usually used by tools and communication channels * where we try to response instantly on messages. */ - class Integ_LANLatencySessionTest + class DISABLED_LANLatencySessionTest : public GridMateMPTestFixture , public SessionEventBus::Handler { @@ -857,7 +857,7 @@ namespace UnitTest m_sessions[i] = nullptr; } - Integ_LANLatencySessionTest() + DISABLED_LANLatencySessionTest() #ifdef AZ_TEST_LANLATENCY_ENABLE_MONSTER_BUFFER : GridMateMPTestFixture(50 * 1024 * 1024) #endif @@ -884,7 +884,7 @@ namespace UnitTest } } - ~Integ_LANLatencySessionTest() override + ~DISABLED_LANLatencySessionTest() override { StopGridMateService(m_gridMates[0]); @@ -1162,7 +1162,7 @@ namespace UnitTest * 5. After host migration we drop the new host again. (after migration we have 3 members). * Session should be fully operational at the end with 3 members left. */ - class Integ_LANSessionMigarationTestTest + class LANSessionMigarationTestTest : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1257,7 +1257,7 @@ namespace UnitTest } } - Integ_LANSessionMigarationTestTest() + LANSessionMigarationTestTest() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1283,7 +1283,7 @@ namespace UnitTest //StartDrilling("lanmigration"); } - ~Integ_LANSessionMigarationTestTest() override + ~LANSessionMigarationTestTest() override { StopGridMateService(m_gridMates[0]); @@ -1476,7 +1476,7 @@ namespace UnitTest * 5. We join a 2 new members to the session. * Session should be fully operational at the end with 4 members in it. */ - class Integ_LANSessionMigarationTestTest2 + class LANSessionMigarationTestTest2 : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1571,7 +1571,7 @@ namespace UnitTest } } } - Integ_LANSessionMigarationTestTest2() + LANSessionMigarationTestTest2() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1597,7 +1597,7 @@ namespace UnitTest //StartDrilling("lanmigration2"); } - ~Integ_LANSessionMigarationTestTest2() override + ~LANSessionMigarationTestTest2() override { StopGridMateService(m_gridMates[0]); @@ -1816,7 +1816,7 @@ namespace UnitTest * 3. Add 2 new joins to the original session. * Original session should remain fully operational with 4 members in it. */ - class Integ_LANSessionMigarationTestTest3 + class LANSessionMigarationTestTest3 : public SessionEventBus::Handler , public GridMateMPTestFixture { @@ -1910,7 +1910,7 @@ namespace UnitTest } } } - Integ_LANSessionMigarationTestTest3() + LANSessionMigarationTestTest3() { ////////////////////////////////////////////////////////////////////////// // Create all grid mates @@ -1936,7 +1936,7 @@ namespace UnitTest //StartDrilling("lanmigration2"); } - ~Integ_LANSessionMigarationTestTest3() override + ~LANSessionMigarationTestTest3() override { StopGridMateService(m_gridMates[0]); @@ -2122,13 +2122,13 @@ namespace UnitTest } GM_TEST_SUITE(SessionSuite) -GM_TEST(Integ_LANSessionMatchmakingParamsTest) -GM_TEST(Integ_LANSessionTest) +GM_TEST(DISABLED_LANSessionMatchmakingParamsTest) +GM_TEST(DISABLED_LANSessionTest) #if (AZ_TRAIT_GRIDMATE_TEST_SOCKET_IPV6_SUPPORT_ENABLED) -GM_TEST(Integ_LANSessionTestIPv6) +GM_TEST(DISABLED_LANSessionTestIPv6) #endif -GM_TEST(Integ_LANMultipleSessionTest) -GM_TEST(Integ_LANLatencySessionTest) +GM_TEST(DISABLED_LANMultipleSessionTest) +GM_TEST(DISABLED_LANLatencySessionTest) // Manually enabled tests (require 2+ machines and online services) //GM_TEST(LANSessionMigarationTestTest) diff --git a/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp index a7e9a7ccda..1f05520457 100644 --- a/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/StreamSecureSocketDriverTests.cpp @@ -110,7 +110,7 @@ namespace UnitTest std::array m_buffer; }; - class Integ_StreamSecureSocketDriverTestsBindSocketEmpty + class DISABLED_StreamSecureSocketDriverTestsBindSocketEmpty : public GridMateMPTestFixture { public: @@ -134,7 +134,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsConnection + class DISABLED_StreamSecureSocketDriverTestsConnection : public GridMateMPTestFixture { public: @@ -146,7 +146,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsConnectionAndHelloWorld + class DISABLED_StreamSecureSocketDriverTestsConnectionAndHelloWorld : public GridMateMPTestFixture { public: @@ -190,7 +190,7 @@ namespace UnitTest } }; - class Integ_StreamSecureSocketDriverTestsPingPong + class DISABLED_StreamSecureSocketDriverTestsPingPong : public GridMateMPTestFixture { public: @@ -425,13 +425,13 @@ namespace UnitTest void BuildStateMachine() { - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_TOP), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateTop), AZ::HSM::InvalidStateId, TS_START); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_START), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateStart), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PING), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPing), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PING_GET_SERVER), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStatePingGetServer), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PONG), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPong), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PONG_GET_SERVER), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStatePongGetServer), TS_TOP); - m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_IN_ERROR), AZ::HSM::StateHandler(this, &Integ_StreamSecureSocketDriverTestsPingPong::OnStateInError), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_TOP), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateTop), AZ::HSM::InvalidStateId, TS_START); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_START), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateStart), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PING), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPing), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PING_GET_SERVER), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStatePingGetServer), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_SERVER_GET_PONG), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateServerGetPong), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_PONG_GET_SERVER), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStatePongGetServer), TS_TOP); + m_stateMachine.SetStateHandler(AZ_HSM_STATE_NAME(TS_IN_ERROR), AZ::HSM::StateHandler(this, &DISABLED_StreamSecureSocketDriverTestsPingPong::OnStateInError), TS_TOP); m_stateMachine.Start(); } @@ -486,10 +486,10 @@ namespace UnitTest } GM_TEST_SUITE(StreamSecureSocketDriverTests) - GM_TEST(Integ_StreamSecureSocketDriverTestsBindSocketEmpty); - GM_TEST(Integ_StreamSecureSocketDriverTestsConnection); - GM_TEST(Integ_StreamSecureSocketDriverTestsConnectionAndHelloWorld); - GM_TEST(Integ_StreamSecureSocketDriverTestsPingPong); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsBindSocketEmpty); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsConnection); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsConnectionAndHelloWorld); + GM_TEST(DISABLED_StreamSecureSocketDriverTestsPingPong); GM_TEST_SUITE_END() #endif // AZ_TRAIT_GRIDMATE_ENABLE_OPENSSL diff --git a/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp b/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp index f9e9395fbf..9dd22bedc7 100644 --- a/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp +++ b/Code/Framework/GridMate/Tests/StreamSocketDriverTests.cpp @@ -308,7 +308,7 @@ namespace UnitTest } }; - class Integ_StreamSocketDriverTestsTooManyConnections + class DISABLED_StreamSocketDriverTestsTooManyConnections : public GridMateMPTestFixture { public: @@ -529,7 +529,7 @@ GM_TEST_SUITE(StreamSocketDriverTests) GM_TEST(StreamSocketDriverTestsSimpleLockStepConnection); GM_TEST(StreamSocketDriverTestsEstablishConnectAndSend); GM_TEST(StreamSocketDriverTestsManyRandomPackets); - GM_TEST(Integ_StreamSocketDriverTestsTooManyConnections); + GM_TEST(DISABLED_StreamSocketDriverTestsTooManyConnections); GM_TEST(StreamSocketDriverTestsClientToInvalidServer); GM_TEST(StreamSocketDriverTestsManySends); diff --git a/Code/Framework/GridMate/Tests/TestProfiler.cpp b/Code/Framework/GridMate/Tests/TestProfiler.cpp deleted file mode 100644 index 26e9312ecf..0000000000 --- a/Code/Framework/GridMate/Tests/TestProfiler.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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 "Tests.h" -#include "TestProfiler.h" - -#include -#include - -#include -#include - -using namespace GridMate; - -typedef set ProfilerSet; - -static bool CollectPerformanceCounters(const AZ::Debug::ProfilerRegister& reg, const AZStd::thread_id&, ProfilerSet& profilers, const char* systemId) -{ - if (reg.m_type != AZ::Debug::ProfilerRegister::PRT_TIME) - { - return true; - } - if (reg.m_systemId != AZ::Crc32(systemId)) - { - return true; - } - - const AZ::Debug::ProfilerRegister* profReg = ® - profilers.insert(profReg); - return true; -} - -static AZStd::string FormatString(const AZStd::string& pre, const AZStd::string& name, const AZStd::string& post, AZ::u64 time, AZ::u64 calls) -{ - AZStd::string units = "us"; - if (AZ::u64 divtime = time / 1000) - { - time = divtime; - units = "ms"; - } - return AZStd::string::format("%s%s %s %10llu%s (%llu calls)\n", pre.c_str(), name.c_str(), post.c_str(), time, units.c_str(), calls); -} - -struct TotalSortContainer -{ - TotalSortContainer(const AZ::Debug::ProfilerRegister* self = nullptr) - { - m_self = self; - } - - void Print(AZ::s32 level, const char* systemId) - { - if (m_self && level >= 0) - { - AZStd::string levelIndent; - for (AZ::s32 i = 0; i < level; i++) - { - levelIndent += (i == level - 1) ? "+---" : "| "; - } - AZStd::string name = m_self->m_name ? m_self->m_name : m_self->m_function; - AZStd::string outputTotal = FormatString(levelIndent, name, " Total:", m_self->m_timeData.m_time, m_self->m_timeData.m_calls); - AZ_Printf(systemId, outputTotal.c_str()); - - if (m_self->m_timeData.m_childrenTime || m_self->m_timeData.m_childrenCalls) - { - AZStd::string childIndent = levelIndent; - for (auto i = name.begin(); i != name.end(); ++i) - { - childIndent += " "; - } - childIndent[level * 4] = '|'; - - AZStd::string outputChild = FormatString(childIndent, "", "Child:", m_self->m_timeData.m_childrenTime, m_self->m_timeData.m_childrenCalls); - AZ_Printf(systemId, outputChild.c_str()); - - AZStd::string outputSelf = FormatString(childIndent, "", "Self :", m_self->m_timeData.m_time - m_self->m_timeData.m_childrenTime, m_self->m_timeData.m_calls); - AZ_Printf(systemId, outputSelf.c_str()); - } - } - - for (auto i = m_children.begin(); i != m_children.end(); ++i) - { - i->Print(level + 1, systemId); - } - } - - TotalSortContainer* Find(const AZ::Debug::ProfilerRegister* obj) - { - if (m_self == obj) - { - return this; - } - - for (TotalSortContainer& child : m_children) - { - TotalSortContainer* found = child.Find(obj); - if (found) - { - return found; - } - } - - return nullptr; - } - - struct TotalSorter - { - bool operator()(const TotalSortContainer& a, const TotalSortContainer& b) const - { - if (a.m_self->m_timeData.m_time == b.m_self->m_timeData.m_time) - { - return a.m_self > b.m_self; - } - return a.m_self->m_timeData.m_time > b.m_self->m_timeData.m_time; - } - }; - set m_children; - const AZ::Debug::ProfilerRegister* m_self; -}; - -void TestProfiler::StartProfiling() -{ - StopProfiling(); - - AZ::Debug::Profiler::Create(); -} - -void TestProfiler::StopProfiling() -{ - if (AZ::Debug::Profiler::IsReady()) - { - AZ::Debug::Profiler::Destroy(); - } -} - -void TestProfiler::PrintProfilingTotal(const char* systemId) -{ - if (!AZ::Debug::Profiler::IsReady()) - { - return; - } - - ProfilerSet profilers; - AZ::Debug::Profiler::Instance().ReadRegisterValues(AZStd::bind(&CollectPerformanceCounters, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::ref(profilers), systemId)); - - // Validate we wont get stuck in an infinite loop - TotalSortContainer root; - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - if (profile->m_timeData.m_lastParent) - { - auto parent = profilers.find(profile->m_timeData.m_lastParent); - if (parent == profilers.end()) - { - // Error, just ignore this entry - i = profilers.erase(i); - continue; - } - } - ++i; - } - - // Put all root nodes into the final list - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - if (!profile->m_timeData.m_lastParent) - { - root.m_children.insert(profile); - i = profilers.erase(i); - } - else - { - ++i; - } - } - - // Put all non-root nodes into the final list - while (!profilers.empty()) - { - for (auto i = profilers.begin(); i != profilers.end(); ) - { - const AZ::Debug::ProfilerRegister* profile = *i; - TotalSortContainer* found = root.Find(profile->m_timeData.m_lastParent); - if (found) - { - found->m_children.insert(profile); - i = profilers.erase(i); - } - else - { - ++i; - } - } - } - - AZ_Printf(systemId, "Profiling timers by total execution time:\n"); - root.Print(-1, systemId); -} - -void TestProfiler::PrintProfilingSelf(const char* systemId) -{ - if (!AZ::Debug::Profiler::IsReady()) - { - return; - } - - ProfilerSet profilers; - AZ::Debug::Profiler::Instance().ReadRegisterValues(AZStd::bind(&CollectPerformanceCounters, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::ref(profilers), systemId)); - - struct SelfSorter - { - bool operator()(const AZ::Debug::ProfilerRegister* a, const AZ::Debug::ProfilerRegister* b) const - { - auto aTime = a->m_timeData.m_time - a->m_timeData.m_childrenTime; - auto bTime = b->m_timeData.m_time - b->m_timeData.m_childrenTime; - - if (aTime == bTime) - { - return a > b; - } - return aTime > bTime; - } - }; - - set selfSorted; - for (auto& profiler : profilers) - { - selfSorted.insert(profiler); - } - - AZ_Printf(systemId, "Profiling timers by exclusive execution time:\n"); - for (auto profiler : selfSorted) - { - AZStd::string str = FormatString("", profiler->m_name ? profiler->m_name : profiler->m_function, "Self Time:", - profiler->m_timeData.m_time - profiler->m_timeData.m_childrenTime, profiler->m_timeData.m_calls); - AZ_Printf(systemId, str.c_str()); - } -} diff --git a/Code/Framework/GridMate/Tests/TestProfiler.h b/Code/Framework/GridMate/Tests/TestProfiler.h deleted file mode 100644 index 816c001645..0000000000 --- a/Code/Framework/GridMate/Tests/TestProfiler.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 - * - */ -#ifndef GM_TEST_PROFILER_H -#define GM_TEST_PROFILER_H - -namespace GridMate -{ - class TestProfiler - { - public: - static void StartProfiling(); - static void StopProfiling(); - - static void PrintProfilingTotal(const char* systemId); - static void PrintProfilingSelf(const char* systemId); - }; -} - -#endif diff --git a/Code/Framework/GridMate/Tests/gridmate_test_files.cmake b/Code/Framework/GridMate/Tests/gridmate_test_files.cmake index 3ff67f8eda..cf1cd087ee 100644 --- a/Code/Framework/GridMate/Tests/gridmate_test_files.cmake +++ b/Code/Framework/GridMate/Tests/gridmate_test_files.cmake @@ -12,6 +12,7 @@ set(FILES Session.cpp Serialize.cpp Certificates.cpp + Replica.cpp ReplicaSmall.cpp ReplicaMedium.cpp ReplicaBehavior.cpp diff --git a/Code/Tools/AssetBundler/tests/tests_main.cpp b/Code/Tools/AssetBundler/tests/tests_main.cpp index 51dd0ce67c..21a6bf8a6f 100644 --- a/Code/Tools/AssetBundler/tests/tests_main.cpp +++ b/Code/Tools/AssetBundler/tests/tests_main.cpp @@ -291,6 +291,9 @@ namespace AssetBundler int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + INVOKE_AZ_UNIT_TEST_MAIN(); AZ::AllocatorInstance::Create(); diff --git a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp index 4b70f94120..d7801abb3d 100644 --- a/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/SourceFileRelocatorTests.cpp @@ -262,7 +262,7 @@ namespace UnitTests auto result = m_data->m_reporter->ComputeDestination(entryContainer, m_data->m_platformConfig.GetScanFolderByPath(scanFolderEntry.m_scanFolder.c_str()), source, destination, destInfo); - ASSERT_EQ(result.IsSuccess(), expectSuccess) << result.GetError().c_str(); + ASSERT_EQ(result.IsSuccess(), expectSuccess) << (!result.IsSuccess() ? result.GetError().c_str() : ""); if (expectSuccess) { diff --git a/Code/Tools/AssetProcessor/native/tests/test_main.cpp b/Code/Tools/AssetProcessor/native/tests/test_main.cpp index 57f14832aa..e0cdc8cb3c 100644 --- a/Code/Tools/AssetProcessor/native/tests/test_main.cpp +++ b/Code/Tools/AssetProcessor/native/tests/test_main.cpp @@ -29,6 +29,9 @@ int main(int argc, char* argv[]) { qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "1"); + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + // If "--unittest" is present on the command line, run unit testing // and return immediately. Otherwise, continue as normal. AZ::Test::addTestEnvironment(new BaseAssetProcessorTestEnvironment()); diff --git a/Code/Tools/AzTestRunner/src/main.cpp b/Code/Tools/AzTestRunner/src/main.cpp index 0874efeff2..acb208d3e5 100644 --- a/Code/Tools/AzTestRunner/src/main.cpp +++ b/Code/Tools/AzTestRunner/src/main.cpp @@ -18,45 +18,35 @@ namespace AzTestRunner const int LIB_NOT_FOUND = 102; const int SYMBOL_NOT_FOUND = 103; - // note that MODULE_SKIPPED is not an error condition, but not 0 to indicate its not the - // same as successfully running tests and finding them. - const int MODULE_SKIPPED = 104; - const char* INTEG_BOOTSTRAP = "AzTestIntegBootstrap"; - //! display proper usage of the application void usage([[maybe_unused]] AZ::Test::Platform& platform) { std::stringstream ss; ss << "AzTestRunner\n" - "Runs AZ unit and integration tests. Exit code is the result from GoogleTest.\n" + "Runs AZ tests. Exit code is the result from GoogleTest.\n" "\n" "Usage:\n" - " AzTestRunner.exe (AzRunUnitTests|AzRunIntegTests) [--integ] [--wait-for-debugger] [--pause-on-completion] [google-test-args]\n" + " AzTestRunner.exe (AzRunUnitTests|AzRunBenchmarks) [--wait-for-debugger] [--pause-on-completion] [google-test-args]\n" "\n" "Options:\n" " : the module to test\n" " : the name of the aztest hook function to run in the \n" " 'AzRunUnitTests' will hook into unit tests\n" - " 'AzRunIntegTests' will hook into integration tests\n" - " --integ: tells runner to bootstrap the engine, needed for integration tests\n" - " Note: you can run unit tests with a bootstrapped engine (AzRunUnitTests --integ),\n" - " but running integration tests without a bootstrapped engine (AzRunIntegTests w/ no --integ) might not work.\n" + " 'AzRunBenchmarks' will hook into benchmark tests\n" " --wait-for-debugger: tells runner to wait for debugger to attach to process (on supported platforms)\n" " --pause-on-completion: tells the runner to pause after running the tests\n" " --quiet: disables stdout for minimal output while running tests\n" "\n" "Example:\n" - " AzTestRunner.exe CrySystem.dll AzRunUnitTests --pause-on-completion\n" - " AzTestRunner.exe CrySystem.dll AzRunIntegTests --integ\n" + " AzTestRunner.exe AzCore.Tests.dll AzRunUnitTests --pause-on-completion\n" "\n" "Exit Codes:\n" " 0 - all tests pass\n" " 1 - test failure\n" << " " << INCORRECT_USAGE << " - incorrect usage (see above)\n" << " " << LIB_NOT_FOUND << " - library/dll could not be loaded\n" - << " " << SYMBOL_NOT_FOUND << " - export symbol not found\n" - << " " << MODULE_SKIPPED << " - non-integ module was skipped (not an error)\n"; + << " " << SYMBOL_NOT_FOUND << " - export symbol not found\n"; std::cerr << ss.str() << std::endl; } @@ -82,7 +72,6 @@ namespace AzTestRunner // capture optional arguments bool waitForDebugger = false; - bool isInteg = false; bool pauseOnCompletion = false; bool quiet = false; for (int i = 0; i < argc; i++) @@ -93,12 +82,6 @@ namespace AzTestRunner AZ::Test::RemoveParameters(argc, argv, i, i); i--; } - else if (strcmp(argv[i], "--integ") == 0) - { - isInteg = true; - AZ::Test::RemoveParameters(argc, argv, i, i); - i--; - } else if (strcmp(argv[i], "--pause-on-completion") == 0) { pauseOnCompletion = true; @@ -172,47 +155,11 @@ namespace AzTestRunner if (result != 0) { module.reset(); - - if ((isInteg) && (result == SYMBOL_NOT_FOUND)) - { - // special case: It is not required to put an INTEG test inside every DLL - so if - // we failed to find the INTEG entry point in this DLL, its not an error. - // its only an error if we find it and there are no tests, or we find it and tests actually - // fail. - std::cerr << "INTEG module has no entry point and will be skipped: " << lib << std::endl; - return MODULE_SKIPPED; - } - return result; } platform.SuppressPopupWindows(); - // Grab a bootstrapper library if requested - std::shared_ptr bootstrap; - if (isInteg) - { - bootstrap = platform.GetModule(INTEG_BOOTSTRAP); - if (!bootstrap->IsValid()) - { - std::cerr << "FAILED to load bootstrapper" << std::endl; - return LIB_NOT_FOUND; - } - - // Initialize the bootstrapper - auto init = bootstrap->GetFunction("Initialize"); - if (init->IsValid()) - { - int initResult = (*init)(); - if (initResult != 0) - { - std::cerr << "Bootstrapper Initialize failed with code " << initResult << ", exiting" << std::endl; - return initResult; - } - } - } - - // run the test main function. if (testMainFunction->IsValid()) { @@ -231,22 +178,6 @@ namespace AzTestRunner // system allocator / etc. module.reset(); - // Shutdown the bootstrapper - if (bootstrap) - { - auto shutdown = bootstrap->GetFunction("Shutdown"); - if (shutdown->IsValid()) - { - int shutdownResult = (*shutdown)(); - if (shutdownResult != 0) - { - std::cerr << "Bootstrapper shutdown failed with code " << shutdownResult << ", exiting" << std::endl; - return shutdownResult; - } - } - bootstrap.reset(); - } - if (pauseOnCompletion) { AzTestRunner::pause_on_completion(); @@ -258,6 +189,8 @@ namespace AzTestRunner int wrapped_main(int argc/*=0*/, char** argv/*=nullptr*/) { + AZ::Debug::Trace::HandleExceptions(true); + if (argc>0 && argv!=nullptr) { return wrapped_command_arg_main(argc, argv); diff --git a/Code/Tools/ProjectManager/tests/main.cpp b/Code/Tools/ProjectManager/tests/main.cpp index 3dd2fb75df..c666b7ffd0 100644 --- a/Code/Tools/ProjectManager/tests/main.cpp +++ b/Code/Tools/ProjectManager/tests/main.cpp @@ -18,6 +18,9 @@ int runDefaultRunner(int argc, char* argv[]) int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + if (argc == 1) { // if no parameters are provided, add the --unittests parameter diff --git a/Code/Tools/PythonBindingsExample/tests/TestMain.cpp b/Code/Tools/PythonBindingsExample/tests/TestMain.cpp index 7399055ca5..4c0dddecad 100644 --- a/Code/Tools/PythonBindingsExample/tests/TestMain.cpp +++ b/Code/Tools/PythonBindingsExample/tests/TestMain.cpp @@ -23,6 +23,9 @@ int runDefaultRunner(int argc, char* argv[]) int main(int argc, char* argv[]) { + AZ::Debug::Trace::HandleExceptions(true); + AZ::Test::ApplyGlobalParameters(&argc, argv); + // ran with no parameters? if (argc == 1) { diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli index dd235fcd3a..633ea85387 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli @@ -10,7 +10,6 @@ #include #include -#include "JitterTablePcf.azsli" #include "Shadow.azsli" #include "ShadowmapAtlasLib.azsli" #include "BicubicPcfFilters.azsli" @@ -82,12 +81,6 @@ class DirectionalLightShadow // result.y == true if the given coordinate is in shadow. bool2 IsShadowed(float3 shadowCoord, uint indexOfCascade); - // This checks if the point is shadowed or not for the given center coordinate and jitter. - bool IsShadowedWithJitter( - float3 jitterUnit, - float jitterDepthDiffBase, - uint jitterIndex); - // This outputs visibility ratio (from 0.0 to 1.0) of the given coordinate // from the light origin without filtering. float GetVisibilityFromLightNoFilter(); @@ -189,75 +182,6 @@ bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade return bool2(false, false); } -bool DirectionalLightShadow::IsShadowedWithJitter( - float3 jitterUnit, - float jitterDepthDiffBase, - uint jitterIndex) -{ - const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; - const float4x4 worldToLightViewMatrices[ViewSrg::MaxCascadeCount] = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_worldToLightViewMatrices; - const float4x4 lightViewToShadowmapMatrices[ViewSrg::MaxCascadeCount] = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_lightViewToShadowmapMatrices; - const float boundaryScale = - ViewSrg::m_directionalLightShadows[m_lightIndex].m_boundaryScale; - - const float2 jitterXY = g_jitterTablePcf[jitterIndex]; - - // jitterLightView is the jittering diff vector from the lighted point on the surface - // in the light view space. It is remarked as "v_J" in the comment - // named "Calculate depth adjusting diff for jittered samples" - // just before the function GetJitterUnitVectorDepthDiffBase. - const float4 jitterLightView = float4(jitterXY, 0., 0.) * boundaryScale; - - // It checks the jittered point is lit or shadowed from the detailed cascade - // to the less detailed one. - for (uint indexOfCascade = 0; indexOfCascade < cascadeCount; ++indexOfCascade) - { - // jitterShadowmap is the jittering diff vector in the shadowmap space. - const float4 jitterShadowmap = mul(lightViewToShadowmapMatrices[indexOfCascade], jitterLightView); - - // Calculation of the jittering for Z-coordinate (light direction) is required - // to check lit/shadowed for the jittered point. - // jitterDepthDiff is the Z-coordinate of the jittering diff vector - // in the shadowmap space. - float jitterDepthDiff = 0.; - - // jitterDepthDiffBase is "1/tan(theta)" in the comment. - if (jitterDepthDiffBase != 0.) - { - // jitterUnitLightView is the unit vector in the light view space - // noted as "v_M" in the comment. - const float3 jitterUnitLightView = - normalize(mul(worldToLightViewMatrices[indexOfCascade], float4(jitterUnit, 0.)).xyz); - const float lightViewToShadowmapZScale = -lightViewToShadowmapMatrices[indexOfCascade]._m22; - // jitterDepthDiff is the "d" in the note, and it is calculated by - // d = (v_J . v_M) / tan(theta) - // in the light view space. Furthermore it have to be converted - // to the light clip space, which can be done by lightViewToShadowmapZScale. - jitterDepthDiff = - dot(jitterLightView.xyz, jitterUnitLightView) * jitterDepthDiffBase * - lightViewToShadowmapZScale; - } - // jitteredCoord is the coordinate of the jittered point in the shadowmap space. - const float3 jitteredCoord = - m_shadowCoords[indexOfCascade] + float3(jitterShadowmap.xy, jitterDepthDiff); - // Check for the jittered point is lit or shadowed. - const bool2 checkedShadowed = IsShadowed( - jitteredCoord, - indexOfCascade); - // If check is done, return the lit/shadowed flag. - // Otherwise make it pend to the next cascade. - if (checkedShadowed.x) - { - m_debugInfo.m_cascadeIndex = indexOfCascade; - return checkedShadowed.y; - } - } - m_debugInfo.m_cascadeIndex = cascadeCount; - return false; -} - float DirectionalLightShadow::GetVisibilityFromLightNoFilter() { const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli deleted file mode 100644 index 9082286758..0000000000 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 - * - */ - - /* - The following is the output of - $ python3 pcf_jitter_table.py 6 g_jitterTablePcf 0 - where pcf_jitter_table.py has the following contents. - -@code -#!/usr/bin/env python3 - -import random -import sys -import math - - -""" Returns if a point in the range -[radius_min, radius_sup)*[angle_min, angle_sup) -is contained in the tuple polar coordinates. -""" -def is_point_include(radius_min, radius_sup, angle_min, angle_sup, polars): - for polar in polars: - if (radius_min <= polar[0] and polar[0] < radius_sup and - angle_min <= polar[1] and polar[1] < angle_sup): - return True - return False - - -""" Insert a randomly generated polar coordianted point in each -range [r0, r1)*[a0, a1) if there has not been such a point -in tuple coords yet, where [0, 1)*[0, 2pi) is divided -into the rad_count*agl_count ranges. -""" -def add_jitter_coords(radius_count, angle_count, polars): - radius_base = 1.0 / math.sqrt(radius_count) - for radius_index in range(radius_count): - # range of radius - radius_min = math.sqrt(radius_index) * radius_base - radius_sup = math.sqrt(radius_index + 1) * radius_base - - # randomize angle order - random_state = random.getstate() - angle_indices = list(range(angle_count)) - random.shuffle(angle_indices) - random.setstate(random_state) - - for angle_index in angle_indices: - # range of angle - angle_min = 2 * math.pi * angle_index / angle_count - angle_sup = 2 * math.pi * (angle_index + 1) / angle_count - - # if no point in the radius/angle range, add a new point - if not is_point_include(radius_min, radius_sup, - angle_min, angle_sup, - polars): - radius = radius_min + (radius_sup - radius_min) * random.random() - angle = angle_min + (angle_sup - angle_min) * random.random() - polars += [[radius, angle]] - - -""" Return a formatted string readable as an array of -orthogonal coordinated points which are in inside of the unit disk. -""" -def conv_array_string(polars): - result = "{\n" - for [radius, angle] in polars: - x = radius * math.cos(angle) - y = radius * math.sin(angle) - result += str.format(" float2({: 1.20e}, {: 1.20e}),\n", x, y) - result = result.rstrip(",\n") + "\n};\n" - return result - - -if __name__ == "__main__": - rad_size = 1 - ang_size = 1 - - if len(sys.argv) > 3: - random_seed = int(sys.argv[3]) - else: - random_seed = 0 - - if len(sys.argv) > 2: - array_name = sys.argv[2] - else: - array_name = False - - if len(sys.argv) > 1: - len_log = int(sys.argv[1]) - else: - print(" usage: {} array_len_log2 [array_file_name] [random_seed]".format(__file__)) - print(" array_len_log2 = 2 -> array length = 4") - print(" array_len_log2 = 6 -> array length = 64") - sys.exit() - - random.seed(random_seed) - coords = [] - add_jitter_coords(rad_size, ang_size, coords) - for index in range(len_log): - if index % 2 == 0: - rad_size *= 2 - else: - ang_size *= 2 - add_jitter_coords(rad_size, ang_size, coords) - - if array_name: - print(str.format("static const float2 {}[{}] =", array_name, len(coords))) - print(conv_array_string(coords)) - - @endcode - */ -#pragma once - -static const float2 g_jitterTablePcf[64] = -{ - float2( 4.21857815578105532772e-02, -8.43367430701083664601e-01), - float2(-1.66526814909220763350e-02, 2.96922406531470617352e-01), - float2(-1.06374665780382349212e-01, -3.45521852905696924552e-01), - float2( 5.42648241814168375008e-01, 7.63475573328278533936e-01), - float2(-1.55045122122251910479e-01, 5.78282315712970729216e-01), - float2( 1.01310018770242576264e-02, -6.88001749851880561870e-01), - float2(-5.41276603451248283783e-01, 5.21888233660957712168e-01), - float2(-6.69885071867917680777e-01, -6.72019666097878665134e-01), - float2( 1.22985029409499718039e-02, 4.54706838949524849713e-01), - float2( 4.00334354168925599105e-01, -6.20112671104014120949e-02), - float2( 2.32326155804074424571e-01, 5.14183027524470093184e-01), - float2(-3.26788693165450228051e-01, -6.03339478694129849323e-01), - float2( 7.72374386126136736053e-01, 1.23204314299169448432e-01), - float2(-4.45379212004159807936e-01, -6.35591042627205338178e-01), - float2( 9.86986293787213919693e-01, -5.18195017297516449806e-02), - float2(-9.09197225477999193544e-01, 1.95281945570711268356e-01), - float2( 8.78123785413316704229e-02, -2.77671865082058690055e-02), - float2( 1.93947312440399088906e-01, 4.27852204081567363825e-03), - float2(-2.06133675819526185347e-01, -1.49183652412411493771e-01), - float2(-4.11351098583102647854e-01, 2.36214692717993696158e-01), - float2( 3.50058750095615767162e-01, -3.57193658067260721989e-01), - float2(-5.54174780014121681759e-01, -2.23361040823672196698e-01), - float2(-6.29913348094886860196e-01, 1.29962593232600148729e-01), - float2( 3.96119563669521335125e-01, 4.90495219155295036906e-01), - float2( 7.26077464944819728210e-01, -3.70531027878536270426e-02), - float2(-5.50726266551596621568e-01, 6.48997654184258587762e-01), - float2(-6.98067624269093189859e-01, -3.83843898992943299842e-01), - float2( 8.72900706885875177221e-02, 8.24287559846993866941e-01), - float2( 6.65413234189638491678e-01, -5.66029707430476647367e-01), - float2(-5.97071574457786802270e-01, -6.93417220711863180327e-01), - float2( 6.09778569514949131403e-01, 6.92279483269558570946e-01), - float2(-8.10051800827623957879e-01, 5.82366304247235455627e-01), - float2(-8.77200948157437071506e-02, -1.88326609190753474499e-01), - float2( 9.79306884403889771340e-02, 1.86693151785678163046e-01), - float2( 4.60071424048798319206e-02, -1.98255149016034859510e-01), - float2(-5.37585860722621794450e-02, 3.99205315590760584366e-02), - float2( 2.18621803321778829243e-01, -3.85632280444686503795e-01), - float2(-2.98409571230789372187e-02, 4.22286693608096730390e-01), - float2( 3.58654757584850270025e-01, 2.95175871390239985548e-01), - float2(-3.85631921979480485341e-01, -3.00322047091407640096e-01), - float2( 4.49800763439369810648e-01, 3.98492182500493397068e-01), - float2(-4.97878650048238891035e-01, 2.57984038389083569776e-01), - float2(-3.12055242602567339816e-01, -4.88013525550807125697e-01), - float2( 5.87078632117718268724e-01, -6.97256834327608099322e-02), - float2( 6.23692403999373534695e-01, 3.11519734097943645779e-01), - float2( 6.64426445690903810792e-01, -2.27661844509491811950e-01), - float2(-3.24662942872471160793e-01, 5.68939932480760024447e-01), - float2(-5.31263995010459511015e-01, -4.66108719959298256619e-01), - float2( 5.10323549430644951563e-01, 5.81027848262460677731e-01), - float2( 2.82695533021593392586e-01, -7.03582425015577883620e-01), - float2(-5.98419541732174709026e-01, -4.68015982003612274198e-01), - float2(-3.95281650646674975746e-01, 6.10614720709622194050e-01), - float2( 7.87454411900813555647e-01, 1.37726315874787758053e-01), - float2(-7.36310249594224086600e-01, 4.25723821775386646049e-01), - float2( 6.48232481978769037312e-01, -5.53108138515975955585e-01), - float2(-1.88558544306507869237e-01, -7.79120748356531223067e-01), - float2(-3.78614630625567993860e-01, 7.82366459873827913007e-01), - float2(-8.48582606942172357201e-01, -3.78504015913022351381e-01), - float2( 1.91472859899175090748e-02, -9.13050020447597532325e-01), - float2( 8.08826910050883585157e-01, 4.17202663034078935489e-01), - float2(-9.27062588380768493046e-01, -2.94160352051227980130e-01), - float2( 6.67882607007592055126e-01, -6.88642020601400450808e-01), - float2(-1.59349274307943010454e-02, 9.37629353656756814317e-01), - float2( 9.86975590293644233775e-01, 1.44401793964158337014e-01) -}; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli index b91d0ce915..daed3a2921 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli @@ -13,7 +13,6 @@ #include #include #include "BicubicPcfFilters.azsli" -#include "JitterTablePcf.azsli" #include "Shadow.azsli" // ProjectedShadow calculates shadowed area projected from a light. @@ -44,11 +43,6 @@ class ProjectedShadow float GetThickness(); bool IsShadowed(float3 shadowPosition); - bool IsShadowedWithJitter( - float3 jitterUnitX, - float3 jitterUnitY, - float jitterDepthDiffBase, - uint jitterIndex); void SetShadowPosition(); float3 GetAtlasPosition(float2 texturePosition); static float UnprojectDepth(uint shadowIndex, float depthBufferValue); @@ -321,35 +315,6 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition) return false; } -bool ProjectedShadow::IsShadowedWithJitter( - float3 jitterUnitX, - float3 jitterUnitY, - float jitterDepthDiffBase, - uint jitterIndex) -{ - ViewSrg::ProjectedShadow shadow = ViewSrg::m_projectedShadows[m_shadowIndex]; - const float4x4 depthBiasMatrix = shadow.m_depthBiasMatrix; - const float boundaryScale = shadow.m_boundaryScale; - - const float2 jitterXY = g_jitterTablePcf[jitterIndex]; - - const float dist = distance(m_worldPosition, m_viewPosition); - const float boundaryRadius = dist * tan(boundaryScale); - // jitterWorldXY is the jittering diff vector from the lighted point on the surface - // in the world space. It is remarked as "v_J" in the comment - // named "Calculate depth adjusting diff for jittered samples" - // just before the function GetJitterUnitVectorDepthDiffBase. - const float3 jitterWorldXY = jitterUnitX * (jitterXY.x * boundaryRadius) + jitterUnitY * (jitterXY.y * boundaryRadius); - // The adjusting diff of depth ("d" in the comment) is calculated by - // jitterXY.y * boundaryRadius * jitterDepthDiffBase. - const float3 jitterWorldZ = m_lightDirection * (jitterXY.y * boundaryRadius * jitterDepthDiffBase); - - const float3 jitteredWorldPosition = m_worldPosition + jitterWorldXY + jitterWorldZ; - const float4 jitteredShadowmapHomogeneous = mul(depthBiasMatrix, float4(jitteredWorldPosition, 1)); - - return IsShadowed(jitteredShadowmapHomogeneous.xyz / jitteredShadowmapHomogeneous.w); -} - void ProjectedShadow::SetShadowPosition() { const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli index e05ff076cb..1fe81016cf 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/Shadow.azsli @@ -23,14 +23,11 @@ struct FilterParameter uint m_isEnabled; uint2 m_shadowmapOriginInSlice; uint m_shadowmapSize; - uint m_parameterOffset; - uint m_parameterCount; float m_lightDistanceOfCameraViewFrustum; float m_n_f_n; // n / (f - n) float m_n_f; // n - f float m_f; // f // where n: nearDepth, f: farDepth. - float2 m_padding; // explicit padding }; class Shadow diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 2065e28703..94d6f20da3 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -22,14 +22,11 @@ partial ShaderResourceGroup ViewSrg uint m_isEnabled; uint2 m_shadowmapOriginInSlice; uint m_shadowmapSize; - uint m_parameterOffset; - uint m_parameterCount; float m_lightDistanceOfCameraViewFrustum; float m_n_f_n; // n / (f - n) float m_n_f; // n - f float m_f; // f // where n: nearDepth, f: farDepth. - float2 m_padding; // explicit padding }; // Simple Point Lights diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index 60614993b5..cf456b2e41 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -286,7 +286,6 @@ set(FILES ShaderLib/Atom/Features/ScreenSpace/ScreenSpaceUtil.azsli ShaderLib/Atom/Features/Shadow/BicubicPcfFilters.azsli ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli - ShaderLib/Atom/Features/Shadow/JitterTablePcf.azsli ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli ShaderLib/Atom/Features/Shadow/Shadow.azsli ShaderLib/Atom/Features/Shadow/ShadowmapAtlasLib.azsli diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h index 75d266cc52..769c7b95a6 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h @@ -154,12 +154,6 @@ namespace AZ //! @param count Sample Count for filtering (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; - //! This specifies the width of boundary between shadowed area and lit area. - //! @param handle the light handle. - //! @param width Boundary width. The shadow is gradually changed the degree of shadowed. - //! If width == 0, softening edge is disabled. Units are in meters. - virtual void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) = 0; - //! Sets whether the directional shadowmap should use receiver plane bias. //! This attempts to reduce shadow acne when using large pcf filters. virtual void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) = 0; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index 3ab83200ae..5aa2dfb800 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -90,8 +90,6 @@ namespace AZ virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; - //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on the boundary. 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; //! Sets sample count for filtering of shadow boundary (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 6752ac4c52..1a5a776cdf 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -70,9 +70,6 @@ namespace AZ virtual void SetShadowBias(LightHandle handle, float bias) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; - //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on - //! the boundary. 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0; //! Sets sample count for filtering of shadow boundary (up to 64) virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h index dbad3af21f..309331dcf5 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/ShadowConstants.h @@ -42,7 +42,6 @@ namespace AZ // [GFX TODO][ATOM-2408] Make the max number of cascade modifiable at runtime. static constexpr uint16_t MaxNumberOfCascades = 4; static constexpr uint16_t MaxPcfSamplingCount = 64; - static constexpr float MaxSofteningBoundaryWidth = 0.1f; } // namespace Shadow } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h index 3d6c0c3015..46560f435d 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h @@ -54,8 +54,6 @@ namespace AZ::Render virtual void SetShadowBias(ShadowId id, float bias) = 0; //! Sets the shadow filter method virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0; - //! Sets the width of boundary between shadowed area and lit area. - virtual void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) = 0; //! Sets the sample count for filtering of the shadow boundary, max 64. virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0; //! Sets all of the shadow properites in one call diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 42cca0e57c..0a9f3480ad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -584,15 +584,6 @@ namespace AZ m_shadowBufferNeedsUpdate = true; } - void DirectionalLightFeatureProcessor::SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) - { - for (auto& it : m_shadowData) - { - it.second.GetData(handle.GetIndex()).m_boundaryScale = boundaryWidth / 2.f; - } - m_shadowBufferNeedsUpdate = true; - } - void DirectionalLightFeatureProcessor::SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) { m_shadowProperties.GetData(handle.GetIndex()).m_isReceiverPlaneBiasEnabled = enable; @@ -1116,50 +1107,13 @@ namespace AZ for (const auto& passIt : m_esmShadowmapsPasses) { const RPI::View* cameraView = passIt.second.front()->GetRenderPipeline()->GetDefaultView().get(); - UpdateStandardDeviations(handle, cameraView); - UpdateFilterOffsetsCounts(handle, cameraView); + UpdateFilterEnabled(handle, cameraView); UpdateShadowmapPositionInAtlas(handle, cameraView); SetFilterParameterToPass(handle, cameraView); } } - void DirectionalLightFeatureProcessor::UpdateStandardDeviations(LightHandle handle, const RPI::View* cameraView) - { - if (handle != m_shadowingLightHandle) - { - return; - } - - const DirectionalLightShadowData& data = m_shadowData.at(cameraView).GetData(handle.GetIndex()); - const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); - AZStd::fixed_vector standardDeviations; - for (size_t cascadeIndex = 0; cascadeIndex < property.m_segments.at(cameraView).size(); ++cascadeIndex) - { - const Aabb& aabb = property.m_segments.at(cameraView)[cascadeIndex].m_aabb; - const float aabbDiameter = AZStd::GetMax( - aabb.GetMax().GetX() - aabb.GetMin().GetX(), - aabb.GetMax().GetZ() - aabb.GetMin().GetZ()); - float standardDeviation = 0.f; - if (aabbDiameter > 0.f) - { - const float boundaryWidth = data.m_boundaryScale * 2.f; - const float ratioToAabbWidth = boundaryWidth / aabbDiameter; - const float widthInPixels = ratioToAabbWidth * data.m_shadowmapSize; - standardDeviation = widthInPixels / (2 * GaussianMathFilter::ReliableSectionFactor); - } - standardDeviations.push_back(standardDeviation); - } - - for (const RPI::RenderPipelineId& pipelineId : m_renderPipelineIdsForPersistentView.at(cameraView)) - { - for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses.at(pipelineId)) - { - esmPass->SetFilterParameters(standardDeviations); - } - } - } - - void DirectionalLightFeatureProcessor::UpdateFilterOffsetsCounts(LightHandle handle, const RPI::View* cameraView) + void DirectionalLightFeatureProcessor::UpdateFilterEnabled(LightHandle handle, const RPI::View* cameraView) { if (handle != m_shadowingLightHandle) { @@ -1170,29 +1124,11 @@ namespace AZ if (shadowData.m_shadowFilterMethod == aznumeric_cast(ShadowFilterMethod::Esm) || (shadowData.m_shadowFilterMethod == aznumeric_cast(ShadowFilterMethod::EsmPcf))) { - // Get array of filter counts for the camera view. - const RPI::RenderPipelineId& pipelineId = m_renderPipelineIdsForPersistentView.at(cameraView).front(); - AZ_Assert(!m_esmShadowmapsPasses.at(pipelineId).empty(), "Cannot find a EsmShadowmapsPass."); - const AZStd::array_view filterCounts = m_esmShadowmapsPasses.at(pipelineId).front()->GetFilterCounts(); - AZ_Assert(filterCounts.size() == GetCascadeCount(handle), "FilterCounts differs with cascade count."); - - // Create array of filter offsets - AZStd::vector filterOffsets; - filterOffsets.reserve(filterCounts.size()); - uint32_t filterOffset = 0; - for (const uint32_t count : filterCounts) - { - filterOffsets.push_back(filterOffset); - filterOffset += count; - } - // Write filter offsets and filter counts to ESM data for (uint16_t index = 0; index < GetCascadeCount(handle); ++index) { EsmShadowmapsPass::FilterParameter& filterParameter = m_esmParameterData.at(cameraView).GetData(index); filterParameter.m_isEnabled = true; - filterParameter.m_parameterOffset = filterOffsets[index]; - filterParameter.m_parameterCount = filterCounts[index]; } } else @@ -1202,8 +1138,6 @@ namespace AZ { EsmShadowmapsPass::FilterParameter& filterParameter = m_esmParameterData.at(cameraView).GetData(index); filterParameter.m_isEnabled = false; - filterParameter.m_parameterOffset = 0; - filterParameter.m_parameterCount = 0; } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index 039f51d549..3c1ff8eabd 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -217,7 +217,6 @@ namespace AZ void SetDebugFlags(LightHandle handle, DebugDrawFlags flags) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; - void SetShadowBoundaryWidth(LightHandle handle, float boundaryWidth) override; void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override; const Data::Instance GetLightBuffer() const; @@ -278,10 +277,8 @@ namespace AZ //! This updates the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(LightHandle handle); - //! This updates standard deviations for each cascade. - void UpdateStandardDeviations(LightHandle handle, const RPI::View* cameraView); - //! This updates filter offset and size for each cascade. - void UpdateFilterOffsetsCounts(LightHandle handle, const RPI::View* cameraView); + //! This updates if the filter is enabled. + void UpdateFilterEnabled(LightHandle handle, const RPI::View* cameraView); //! This updates shadowmap position(origin and size) in the atlas for each cascade. void UpdateShadowmapPositionInAtlas(LightHandle handle, const RPI::View* cameraView); //! This set filter parameters to passes which execute filtering. diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index 26e1757a5a..acf81ede32 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -322,11 +322,6 @@ namespace AZ { SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); } - - void DiskLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) - { - SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); - } void DiskLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index d65f587718..275712f84f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -53,7 +53,6 @@ namespace AZ void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetEsmExponent(LightHandle handle, float esmExponent) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp index 99eaa8a919..b92d538fb5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.cpp @@ -42,28 +42,6 @@ namespace AZ return m_lightTypeName; } - void EsmShadowmapsPass::SetFilterParameters(const AZStd::array_view& standardDeviations) - { - // Set descriptor for Gaussian filters for given set of standard deviations. - MathFilterDescriptor descriptor; - descriptor.m_kind = MathFilterKind::Gaussian; - descriptor.m_gaussians.reserve(standardDeviations.size()); - for (const float standardDeviation : standardDeviations) - { - descriptor.m_gaussians.emplace_back(GaussianFilterDescriptor{ standardDeviation }); - } - - // Set filter paramter buffer along with element counts for each filter. - MathFilter::BufferWithElementCounts bufferCounts = MathFilter::FindOrCreateFilterBuffer(descriptor); - m_filterTableBuffer = bufferCounts.first; - m_filterCounts = AZStd::move(bufferCounts.second); - } - - AZStd::array_view EsmShadowmapsPass::GetFilterCounts() const - { - return m_filterCounts; - } - void EsmShadowmapsPass::SetShadowmapIndexTableBuffer(const Data::Instance& tableBuffer) { m_shadowmapIndexTableBuffer = tableBuffer; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h index 6e5e1aa311..5a9898d507 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/EsmShadowmapsPass.h @@ -50,14 +50,11 @@ namespace AZ uint32_t m_isEnabled = false; AZStd::array m_shadowmapOriginInSlice = { {0, 0 } }; // shadowmap origin in the slice of the atlas. uint32_t m_shadowmapSize = static_cast(ShadowmapSize::None); // width and height of shadowmap. - uint32_t m_parameterOffset; // offset of the filter parameter. - uint32_t m_parameterCount; // element count of the filter parameter. float m_lightDistanceOfCameraViewFrustum = 0.f; float m_n_f_n = 0.f; // n / (f - n) float m_n_f = 0.f; // n - f float m_f = 0.f; // f // where n: nearDepth, f: farDepth. - AZStd::array m_padding = {{0.f, 0.f}}; // explicit padding }; virtual ~EsmShadowmapsPass() = default; @@ -65,13 +62,6 @@ namespace AZ const Name& GetLightTypeName() const; - //! This sets the standard deviations of the Gaussian filter - //! for each cascade. - void SetFilterParameters(const AZStd::array_view& standardDeviations); - - //! This returns element count of filters. - AZStd::array_view GetFilterCounts() const; - //! This sets the buffer of the table which enable to get shadowmap index //! from the coordinate in the atlas. //! Note that shadowmpa index is shader light index for a spot light diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index d3b5646e0b..dcf412c35d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -292,11 +292,6 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method); } - void PointLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) - { - SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians); - } - void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count) { SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index b784eb1bb5..54cb0303cc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -50,7 +50,6 @@ namespace AZ void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetEsmExponent(LightHandle handle, float esmExponent) override; void SetPointData(LightHandle handle, const PointLightData& data) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 51e18b8e31..cdcc07b545 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -54,10 +54,14 @@ namespace AZ { AZStd::shared_ptr> buffer = readbackResult.m_dataBuffer; + RHI::Format format = readbackResult.m_imageDescriptor.m_format; + // convert bgra to rgba by swapping channels const int numChannels = AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format); - if (readbackResult.m_imageDescriptor.m_format == RHI::Format::B8G8R8A8_UNORM) + if (format == RHI::Format::B8G8R8A8_UNORM) { + format = RHI::Format::R8G8B8A8_UNORM; + buffer = AZStd::make_shared>(readbackResult.m_dataBuffer->size()); AZStd::copy(readbackResult.m_dataBuffer->begin(), readbackResult.m_dataBuffer->end(), buffer->begin()); @@ -89,7 +93,7 @@ namespace AZ jobCompletion.StartAndWaitForCompletion(); } - Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, readbackResult.m_imageDescriptor.m_format, *buffer); + Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, format, *buffer); Utils::PngFile::SaveSettings saveSettings; saveSettings.m_compressionLevel = r_pngCompressionLevel; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 6e78d3170c..af53fc3ce1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -507,7 +507,8 @@ namespace AZ } } - //Check if buffer view data changed from previous frame. + // Check if buffer view data changed from previous frame. + // Look into making 'm_meshBuffers != meshBuffers' faster by possibly building a crc and doing a crc check. if (m_meshBuffers.size() != meshBuffers.size() || m_meshBuffers != meshBuffers) { m_meshBuffers = meshBuffers; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 6452b312c8..da92cc04e7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -186,17 +186,6 @@ namespace AZ::Render m_filterParameterNeedsUpdate = true; } - void ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) - { - AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowBoundaryWidthAngle()."); - - ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); - shadowData.m_boundaryScale = boundaryWidthRadians / 2.0f; - - m_shadowmapPassNeedsUpdate = true; - m_filterParameterNeedsUpdate = true; - } - void ProjectedShadowFeatureProcessor::SetFilteringSampleCount(ShadowId id, uint16_t count) { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetFilteringSampleCount()."); @@ -368,14 +357,13 @@ namespace AZ::Render { if (m_filterParameterNeedsUpdate) { - UpdateStandardDeviations(); - UpdateFilterOffsetsCounts(); + UpdateEsmPassEnabled(); SetFilterParameterToPass(); m_filterParameterNeedsUpdate = false; } } - void ProjectedShadowFeatureProcessor::UpdateStandardDeviations() + void ProjectedShadowFeatureProcessor::UpdateEsmPassEnabled() { if (m_esmShadowmapsPasses.empty()) { @@ -383,24 +371,7 @@ namespace AZ::Render return; } - AZStd::vector standardDeviations(m_shadowProperties.GetDataCount()); - - for (uint32_t i = 0; i < m_shadowProperties.GetDataCount(); ++i) - { - ShadowProperty& shadowProperty = m_shadowProperties.GetDataVector().at(i); - const ShadowData& shadow = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - if (!FilterMethodIsEsm(shadow)) - { - continue; - } - const FilterParameter& filter = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - const float boundaryWidthAngle = shadow.m_boundaryScale * 2.0f; - const float fieldOfView = GetMax(shadowProperty.m_desc.m_fieldOfViewYRadians, MinimumFieldOfView); - const float ratioToEntireWidth = boundaryWidthAngle / fieldOfView; - const float widthInPixels = ratioToEntireWidth * filter.m_shadowmapSize; - standardDeviations.at(i) = widthInPixels / (2.0f * GaussianMathFilter::ReliableSectionFactor); - } - if (standardDeviations.empty()) + if (m_shadowProperties.GetDataCount() == 0) { for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { @@ -411,50 +382,6 @@ namespace AZ::Render for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { esmPass->SetEnabledComputation(true); - esmPass->SetFilterParameters(standardDeviations); - } - } - - void ProjectedShadowFeatureProcessor::UpdateFilterOffsetsCounts() - { - if (m_esmShadowmapsPasses.empty()) - { - AZ_Error("ProjectedShadowFeatureProcessor", false, "Cannot find a required pass."); - return; - } - - // Get array of filter counts for the camera view. - const AZStd::array_view filterCounts = m_esmShadowmapsPasses.front()->GetFilterCounts(); - - // Create array of filter offsets. - AZStd::vector filterOffsets; - filterOffsets.reserve(filterCounts.size()); - uint32_t filterOffset = 0; - for (const uint32_t count : filterCounts) - { - filterOffsets.push_back(filterOffset); - filterOffset += count; - } - - auto& shadowProperties = m_shadowProperties.GetDataVector(); - for (uint32_t i = 0; i < shadowProperties.size(); ++i) - { - ShadowProperty& shadowProperty = shadowProperties.at(i); - const ShadowId shadowId = shadowProperty.m_shadowId; - ShadowData& shadowData = m_shadowData.GetElement(shadowId.GetIndex()); - FilterParameter& filterData = m_shadowData.GetElement(shadowId.GetIndex()); - - if (FilterMethodIsEsm(shadowData)) - { - filterData.m_parameterOffset = filterOffsets[i]; - filterData.m_parameterCount = filterCounts[i]; - } - else - { - // If filter is not required, reset offsets and counts of filter in ESM data. - filterData.m_parameterOffset = 0; - filterData.m_parameterCount = 0; - } } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index 0b266b9a40..6269166827 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -49,7 +49,6 @@ namespace AZ::Render void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override; void SetShadowBias(ShadowId id, float bias) override; void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) override; void SetFilteringSampleCount(ShadowId id, uint16_t count) override; void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override; const ProjectedShadowDescriptor& GetShadowProperties(ShadowId id) override; @@ -101,8 +100,7 @@ namespace AZ::Render //! Functions to update the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(); - void UpdateStandardDeviations(); - void UpdateFilterOffsetsCounts(); + void UpdateEsmPassEnabled(); void SetFilterParameterToPass(); bool FilterMethodIsEsm(const ShadowData& shadowData) const; diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp index 9f3d21a2f1..e4e1a887b0 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraph.cpp @@ -109,13 +109,11 @@ namespace AZ { if (attachment->GetFirstScopeAttachment() == nullptr) { + //We allow the rendering to continue even if an attachment is not used. AZ_Error( "FrameGraph", false, "Invalid State: attachment '%s' was added but never used!", attachment->GetId().GetCStr()); - - Clear(); - return ResultCode::InvalidOperation; } } } diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp index 70f08dec1e..eb80b038eb 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -111,13 +111,19 @@ namespace AZ { AZStd::lock_guard lock(m_groupsToCompileMutex); - AZ_Assert(!shaderResourceGroup.IsQueuedForCompile(), "Attempting to compile an SRG that's already been queued for compile. Only compile an SRG once per frame."); + bool isQueuedForCompile = shaderResourceGroup.IsQueuedForCompile(); + AZ_Warning( + "ShaderResourceGroupPool", !isQueuedForCompile, + "Attempting to compile an SRG that's already been queued for compile. Only compile an SRG once per frame."); - CalculateGroupDataDiff(shaderResourceGroup, groupData); + if (!isQueuedForCompile) + { + CalculateGroupDataDiff(shaderResourceGroup, groupData); - shaderResourceGroup.SetData(groupData); + shaderResourceGroup.SetData(groupData); - QueueForCompileNoLock(shaderResourceGroup); + QueueForCompileNoLock(shaderResourceGroup); + } } void ShaderResourceGroupPool::QueueForCompile(ShaderResourceGroup& group) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp index 07b18266f5..a1025e5501 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/BufferMemoryPageAllocator.cpp @@ -55,7 +55,7 @@ namespace AZ RHI::Ptr bufferMemory; const VkMemoryPropertyFlags flags = ConvertHeapMemoryLevel(m_descriptor.m_heapMemoryLevel) | m_descriptor.m_additionalMemoryPropertyFlags; - RHI::Ptr memory = GetDevice().AllocateMemory(memoryRequirements.size, memoryRequirements.memoryTypeBits, flags); + RHI::Ptr memory = GetDevice().AllocateMemory(memoryRequirements.size, memoryRequirements.memoryTypeBits, flags, m_descriptor.m_bindFlags); if (memory) { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp index d90f1c33d5..2620aa5f7b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/CommandList.cpp @@ -822,7 +822,7 @@ namespace AZ { RHI::ConstPtr shaderResourceGroup; const auto& srgBitset = pipelineLayout.GetAZSLBindingSlotsOfIndex(index); - AZStd::vector shaderResourceGroupList; + AZStd::fixed_vector shaderResourceGroupList; // Collect all the SRGs that are part of this descriptor set. They could be more than // 1, so we would need to merge their values before committing the descriptor set. for (uint32_t bindingSlot = 0; bindingSlot < srgBitset.size(); ++bindingSlot) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp index d5671cff05..3294b77eaa 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.cpp @@ -696,8 +696,7 @@ namespace AZ usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; } if (RHI::CheckBitsAny(bindFlags, BindFlags::Constant)) @@ -742,12 +741,24 @@ namespace AZ if (RHI::CheckBitsAny(bindFlags, BindFlags::RayTracingShaderTable)) { - usageFlags |= VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + usageFlags |= VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; + } + + if (ShouldApplyDeviceAddressBit(bindFlags)) + { + usageFlags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } return usageFlags; } + bool ShouldApplyDeviceAddressBit(RHI::BufferBindFlags bindFlags) + { + return RHI::CheckBitsAny( + bindFlags, + RHI::BufferBindFlags::InputAssembly | RHI::BufferBindFlags::DynamicInputAssembly | RHI::BufferBindFlags::RayTracingShaderTable); + } + VkPipelineStageFlags GetSupportedPipelineStages(RHI::PipelineStateType type) { // These stages don't need any special queue to be supported. diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h index 873b8ec2d1..b82b1a2f7c 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Conversion.h @@ -82,5 +82,6 @@ namespace AZ VkImageUsageFlags ImageUsageFlagsOfFormatFeatureFlags(VkFormatFeatureFlags formatFeatureFlags); VkAccessFlags GetSupportedAccessFlags(VkPipelineStageFlags pipelineStageFlags); + bool ShouldApplyDeviceAddressBit(RHI::BufferBindFlags bindFlags); } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp index 132f9929c1..14b6c01498 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp @@ -185,6 +185,9 @@ namespace AZ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR float16Int8 = {}; VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR separateDepthStencil = {}; + VkDeviceCreateInfo deviceInfo = {}; + deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + // If we are running Vulkan >= 1.2, then we must use VkPhysicalDeviceVulkan12Features instead // of VkPhysicalDeviceShaderFloat16Int8FeaturesKHR or VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR. if (majorVersion >= 1 && minorVersion >= 2) @@ -194,7 +197,14 @@ namespace AZ vulkan12Features.shaderFloat16 = physicalDevice.GetPhysicalDeviceVulkan12Features().shaderFloat16; vulkan12Features.shaderInt8 = physicalDevice.GetPhysicalDeviceVulkan12Features().shaderInt8; vulkan12Features.separateDepthStencilLayouts = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorBindingPartiallyBound = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorIndexing = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.descriptorBindingVariableDescriptorCount = physicalDevice.GetPhysicalDeviceVulkan12Features().separateDepthStencilLayouts; + vulkan12Features.bufferDeviceAddress = physicalDevice.GetPhysicalDeviceVulkan12Features().bufferDeviceAddress; + vulkan12Features.bufferDeviceAddressMultiDevice = physicalDevice.GetPhysicalDeviceVulkan12Features().bufferDeviceAddressMultiDevice; + vulkan12Features.runtimeDescriptorArray = physicalDevice.GetPhysicalDeviceVulkan12Features().runtimeDescriptorArray; robustness2.pNext = &vulkan12Features; + deviceInfo.pNext = &depthClipEnabled; } else { @@ -206,11 +216,11 @@ namespace AZ float16Int8.pNext = &separateDepthStencil; robustness2.pNext = &float16Int8; + + + deviceInfo.pNext = &descriptorIndexingFeatures; } - VkDeviceCreateInfo deviceInfo = {}; - deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceInfo.pNext = &descriptorIndexingFeatures; deviceInfo.flags = 0; deviceInfo.queueCreateInfoCount = static_cast(queueCreationInfo.size()); deviceInfo.pQueueCreateInfos = queueCreationInfo.data(); @@ -740,7 +750,7 @@ namespace AZ vkGetPhysicalDeviceQueueFamilyProperties(nativePhysicalDevice, &queueFamilyCount, m_queueFamilyProperties.data()); } - RHI::Ptr Device::AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags) + RHI::Ptr Device::AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags, const RHI::BufferBindFlags bufferBindFlags) { const auto& physicalDevice = static_cast(GetPhysicalDevice()); const VkPhysicalDeviceMemoryProperties& memProp = physicalDevice.GetMemoryProperties(); @@ -770,6 +780,7 @@ namespace AZ RHI::CheckBitsAll(memoryTypesToUseMask, memoryTypeBit)) { memoryDesc.m_memoryTypeIndex = memoryIndex; + memoryDesc.m_bufferBindFlags = bufferBindFlags; auto result = memory->Init(*this, memoryDesc); if (result == RHI::ResultCode::Success) { diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h index 9c21103929..44c1e20a06 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h @@ -100,7 +100,11 @@ namespace AZ RHI::Ptr AcquireCommandList(uint32_t familyQueueIndex, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY); RHI::Ptr AcquireCommandList(RHI::HardwareQueueClass queueClass, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY); - RHI::Ptr AllocateMemory(uint64_t sizeInBytes, const uint32_t memoryTypeMask, const VkMemoryPropertyFlags flags); + RHI::Ptr AllocateMemory( + uint64_t sizeInBytes, + const uint32_t memoryTypeMask, + const VkMemoryPropertyFlags flags, + const RHI::BufferBindFlags bufferBindFlags = RHI::BufferBindFlags::None); uint32_t GetCurrentFrameIndex() const; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp index 5314fc2aa1..84b6cafa7d 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMerged.cpp @@ -59,7 +59,9 @@ namespace AZ void FrameGraphExecuteGroupMerged::BeginInternal() { + m_commandList = AcquireCommandList(VK_COMMAND_BUFFER_LEVEL_PRIMARY); m_commandList->BeginCommandBuffer(); + m_workRequest.m_commandList = m_commandList; } void FrameGraphExecuteGroupMerged::EndInternal() diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp index 90e6d63044..1bcdd17ab6 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuteGroupMergedHandler.cpp @@ -41,9 +41,7 @@ namespace AZ RETURN_RESULT_IF_UNSUCCESSFUL(result); } - // Set the command list and renderpass contexts. - m_primaryCommandList = device.AcquireCommandList(m_hardwareQueueClass); - group->SetPrimaryCommandList(*m_primaryCommandList); + // Set the renderpass contexts. group->SetRenderPasscontexts(m_renderPassContexts); return RHI::ResultCode::Success; @@ -54,7 +52,8 @@ namespace AZ AZ_Assert(m_executeGroups.size() == 1, "Too many execute groups when initializing context"); FrameGraphExecuteGroupBase* group = static_cast(m_executeGroups.back()); AddWorkRequest(group->GetWorkRequest()); - m_workRequest.m_commandList = m_primaryCommandList; + //Merged handler will only have one commandlist. + m_workRequest.m_commandList = group->GetCommandLists()[0]; } } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp index e91b158629..7165b5c305 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.cpp @@ -31,7 +31,12 @@ namespace AZ { return static_cast(Base::GetDevice()); } - + + FrameGraphExecuter::FrameGraphExecuter() + { + SetJobPolicy(RHI::JobPolicy::Parallel); + } + RHI::ResultCode FrameGraphExecuter::InitInternal(const RHI::FrameGraphExecuterDescriptor& descriptor) { const RHI::ConstPtr rhiPlatformLimitsDescriptor = descriptor.m_platformLimitsDescriptor; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h index 20f9f19a6a..8fc54ca0a6 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/FrameGraphExecuter.h @@ -35,6 +35,8 @@ namespace AZ Device& GetDevice() const; private: + FrameGraphExecuter(); + ////////////////////////////////////////////////////////////////////////// // RHI::FrameGraphExecuter RHI::ResultCode InitInternal(const RHI::FrameGraphExecuterDescriptor& descriptor) override; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp index a316a5eacb..bc10ba6dd9 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.cpp @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -31,6 +32,15 @@ namespace AZ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = descriptor.m_sizeInBytes; allocInfo.memoryTypeIndex = descriptor.m_memoryTypeIndex; + + VkMemoryAllocateFlagsInfo memAllocInfo{}; + if (ShouldApplyDeviceAddressBit(descriptor.m_bufferBindFlags)) + { + memAllocInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + } + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + + allocInfo.pNext = &memAllocInfo; VkDeviceMemory deviceMemory; VkResult vkResult = vkAllocateMemory(device.GetNativeDevice(), &allocInfo, nullptr, &deviceMemory); AZ_Error( diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h index 56726a82f6..bfed64d3a0 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Memory.h @@ -37,6 +37,7 @@ namespace AZ { VkDeviceSize m_sizeInBytes = 0; uint32_t m_memoryTypeIndex = 0; + RHI::BufferBindFlags m_bufferBindFlags = RHI::BufferBindFlags::None; }; ~Memory() = default; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h index b011ddcab4..7c21f21ce7 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/MergedShaderResourceGroupPool.h @@ -38,7 +38,7 @@ namespace AZ static RHI::Ptr Create(); - using ShaderResourceGroupList = AZStd::vector; + using ShaderResourceGroupList = AZStd::fixed_vector; //! Finds or create a new instance of a MergedShaderResourceGroup. //! @param shaderResourceGroupList The list of ShaderResourceGroups that are being merged. MergedShaderResourceGroup* FindOrCreate(const ShaderResourceGroupList& shaderResourceGroupList); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp index 59dbaf4377..b2772d716e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp @@ -115,77 +115,65 @@ namespace AZ const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout(); - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask))) + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex) - { - const RHI::ShaderInputBufferIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); - } + const RHI::ShaderInputBufferIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewArray(index); + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); } - - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask))) + + auto const& shaderImageList = layout->GetShaderInputListForImages(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(shaderImageList.size()); ++groupIndex) { - auto const& shaderImageList = layout->GetShaderInputListForImages(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex) - { - const RHI::ShaderInputImageIndex index(groupIndex); - auto imgViews = groupData.GetImageViewArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); - } + const RHI::ShaderInputImageIndex index(groupIndex); + auto imgViews = groupData.GetImageViewArray(index); + uint32_t layoutIndex = + m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type); } + - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask))) + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex) + const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); + auto bufViews = groupData.GetBufferViewUnboundedArray(index); + if (bufViews.empty()) { - const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex); - auto bufViews = groupData.GetBufferViewUnboundedArray(index); - if (bufViews.empty()) - { - // skip empty unbounded arrays - continue; - } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); - descriptorSet.UpdateBufferViews(layoutIndex, bufViews); + // skip empty unbounded arrays + continue; } + + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray); + descriptorSet.UpdateBufferViews(layoutIndex, bufViews); } - - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask))) + + auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); + for (uint32_t groupIndex = 0; groupIndex < static_cast(shaderImageUnboundeArrayList.size()); ++groupIndex) { - auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays(); - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex) + const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); + auto imgViews = groupData.GetImageViewUnboundedArray(index); + if (imgViews.empty()) { - const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex); - auto imgViews = groupData.GetImageViewUnboundedArray(index); - if (imgViews.empty()) - { - // skip empty unbounded arrays - continue; - } - - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); - descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); + // skip empty unbounded arrays + continue; } + + uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray); + descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type); } - - if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask))) + + for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) { - for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex) - { - const RHI::ShaderInputSamplerIndex index(groupIndex); - auto samplerArray = groupData.GetSamplerArray(index); - uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); - descriptorSet.UpdateSamplers(layoutIndex, samplerArray); - } + const RHI::ShaderInputSamplerIndex index(groupIndex); + auto samplerArray = groupData.GetSamplerArray(index); + uint32_t layoutIndex = + m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler); + descriptorSet.UpdateSamplers(layoutIndex, samplerArray); } auto constantData = groupData.GetConstantData(); - if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask))) + if (!constantData.empty()) { descriptorSet.UpdateConstantData(constantData); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index add499f080..ea5b65be7c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -36,6 +36,7 @@ ly_add_target( Gem::Atom_RPI.Edit Gem::Atom_RPI.Public Gem::Atom_RHI.Reflect + Gem::Atom_Feature_Common.Static Gem::Atom_Bootstrap.Headers ) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h new file mode 100644 index 0000000000..27876622da --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.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 +#include + +namespace AtomToolsFramework +{ + //! Interface for describing scene content that will be rendered using the PreviewRenderer + class PreviewContent + { + public: + AZ_CLASS_ALLOCATOR(PreviewContent, AZ::SystemAllocator, 0); + + PreviewContent() = default; + virtual ~PreviewContent() = default; + + //! Initiate loading of scene content, models, materials, etc + virtual void Load() = 0; + + //! Return true if content is loaded and ready to render + virtual bool IsReady() const = 0; + + //! Return true if content failed to load + virtual bool IsError() const = 0; + + //! Report any issues encountered while loading + virtual void ReportErrors() = 0; + + //! Prepare or pose content before rendering + virtual void Update() = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h new file mode 100644 index 0000000000..ea8f5fb356 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h @@ -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 + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +class QPixmap; + +namespace AtomToolsFramework +{ + //! PreviewRendererCaptureRequest describes the size, content, and behavior of a scene to be rendered to an image + struct PreviewRendererCaptureRequest final + { + AZ_CLASS_ALLOCATOR(PreviewRendererCaptureRequest, AZ::SystemAllocator, 0); + + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h new file mode 100644 index 0000000000..8fab1cb5c1 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h @@ -0,0 +1,29 @@ +/* + * 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 AtomToolsFramework +{ + struct PreviewRendererCaptureRequest; + + //! Public interface for PreviewRenderer so that it can be used in other modules + class PreviewRendererInterface + { + public: + AZ_RTTI(PreviewRendererInterface, "{C5B5E3D0-0055-4C08-9B98-FDBBB5F05BED}"); + + virtual ~PreviewRendererInterface() = default; + virtual void AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) = 0; + virtual AZ::RPI::ScenePtr GetScene() const = 0; + virtual AZ::RPI::ViewPtr GetView() const = 0; + virtual AZ::Uuid GetEntityContextId() const = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h new file mode 100644 index 0000000000..810eccaa20 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h @@ -0,0 +1,24 @@ +/* + * 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 AtomToolsFramework +{ + //! PreviewRendererSystemRequests provides an interface for PreviewRendererSystemComponent + class PreviewRendererSystemRequests : public AZ::EBusTraits + { + public: + // Only a single handler is allowed + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + }; + using PreviewRendererSystemRequestBus = AZ::EBus; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h new file mode 100644 index 0000000000..fe1980b39b --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation + class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits + { + public: + //! Get a list of custom feature processors to register with preview image renderer + virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; + }; + + using PreviewerFeatureProcessorProviderBus = AZ::EBus; +} // namespace AtomToolsFramework 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 b407aa2b4c..69b99093f0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -25,7 +25,7 @@ namespace AtomToolsFramework { //! The RenderViewportWidget class is a Qt wrapper around an Atom viewport. - //! RenderViewportWidget renders to an internal window using RPI::ViewportContext + //! RenderViewportWidget renders to an internal window using AZ::RPI::ViewportContext //! and delegates input via its internal ViewportControllerList. //! @see AZ::RPI::ViewportContext for Atom's API for setting up class RenderViewportWidget @@ -39,7 +39,7 @@ namespace AtomToolsFramework public: //! Creates a RenderViewportWidget. //! Requires the Atom RPI to be initialized in order - //! to internally construct an RPI::ViewportContext. + //! to internally construct an AZ::RPI::ViewportContext. //! If initializeViewportContext is set to false, nothing will be displayed on-screen until InitiliazeViewportContext is called. explicit RenderViewportWidget(QWidget* parent = nullptr, bool shouldInitializeViewportContext = true); ~RenderViewportWidget(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp index 21a185b290..865f12d904 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace AtomToolsFramework { @@ -19,6 +20,7 @@ namespace AtomToolsFramework AtomToolsFrameworkSystemComponent::CreateDescriptor(), AtomToolsDocumentSystemComponent::CreateDescriptor(), AtomToolsMainWindowSystemComponent::CreateDescriptor(), + PreviewRendererSystemComponent::CreateDescriptor(), }); } @@ -28,6 +30,7 @@ namespace AtomToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp new file mode 100644 index 0000000000..a0d2034082 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace AtomToolsFramework +{ + PreviewRenderer::PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName) + { + PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); + + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); + + // Create and register a scene with all required feature processors + AZStd::unordered_set featureProcessors; + PreviewerFeatureProcessorProviderBus::Broadcast( + &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); + + AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + + // Bind m_frameworkScene to the entity context's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Failed to get scene system implementation."); + + AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(sceneName); + AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); + + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_scene); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + + // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue + // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(m_renderPipeline); + m_scene->Activate(); + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + m_passHierarchy.push_back(pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // Connect camera to pipeline's default view after camera entity activated + AZ::Matrix4x4 viewToClipMatrix; + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera); + m_view->SetViewToClipMatrix(viewToClipMatrix); + m_renderPipeline->SetDefaultView(m_view); + + m_state.reset(new PreviewRendererIdleState(this)); + + AZ::Interface::Register(this); + } + + PreviewRenderer::~PreviewRenderer() + { + PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); + + m_state.reset(); + + m_currentCaptureRequest = {}; + m_captureRequestQueue = {}; + + m_scene->Deactivate(); + m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_frameworkScene->UnsetSubsystem(m_scene); + m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + + AZ::Interface::Unregister(this); + } + + void PreviewRenderer::AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + + AZ::RPI::ScenePtr PreviewRenderer::GetScene() const + { + return m_scene; + } + + AZ::RPI::ViewPtr PreviewRenderer::GetView() const + { + return m_view; + } + + AZ::Uuid PreviewRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + + void PreviewRenderer::ProcessCaptureRequests() + { + if (!m_captureRequestQueue.empty()) + { + // pop the next request to be rendered from the queue + m_currentCaptureRequest = m_captureRequestQueue.front(); + m_captureRequestQueue.pop(); + + m_state.reset(); + m_state.reset(new PreviewRendererLoadState(this)); + } + } + + void PreviewRenderer::CancelCaptureRequest() + { + if (m_currentCaptureRequest.m_captureFailedCallback) + { + m_currentCaptureRequest.m_captureFailedCallback(); + } + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); + } + + void PreviewRenderer::CompleteCaptureRequest() + { + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); + } + + void PreviewRenderer::LoadContent() + { + m_currentCaptureRequest.m_content->Load(); + } + + void PreviewRenderer::UpdateLoadContent() + { + if (m_currentCaptureRequest.m_content->IsReady()) + { + m_state.reset(); + m_state.reset(new PreviewRendererCaptureState(this)); + return; + } + + if (m_currentCaptureRequest.m_content->IsError()) + { + CancelLoadContent(); + return; + } + } + + void PreviewRenderer::CancelLoadContent() + { + m_currentCaptureRequest.m_content->ReportErrors(); + CancelCaptureRequest(); + } + + void PreviewRenderer::PoseContent() + { + m_currentCaptureRequest.m_content->Update(); + } + + bool PreviewRenderer::StartCapture() + { + auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback; + auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback; + auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result) + { + if (result.m_dataBuffer) + { + if (captureCompleteCallback) + { + captureCompleteCallback(QPixmap::fromImage(QImage( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888))); + } + } + else + { + if (captureFailedCallback) + { + captureFailedCallback(); + } + } + }; + + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); + } + + m_renderPipeline->AddToRenderTickOnce(); + + bool startedCapture = false; + AZ::Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), captureCallback, AZ::RPI::PassAttachmentReadbackOption::Output); + return startedCapture; + } + + void PreviewRenderer::EndCapture() + { + m_currentCaptureRequest = {}; + m_renderPipeline->RemoveFromRenderTick(); + } + + void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const + { + featureProcessors.insert({ + "AZ::Render::TransformServiceFeatureProcessor", + "AZ::Render::MeshFeatureProcessor", + "AZ::Render::SimplePointLightFeatureProcessor", + "AZ::Render::SimpleSpotLightFeatureProcessor", + "AZ::Render::PointLightFeatureProcessor", + // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow + // flickering [ATOM-13568] + // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. + // Possibly re-enable with [GFX TODO][ATOM-13639] + // "AZ::Render::DirectionalLightFeatureProcessor", + "AZ::Render::DiskLightFeatureProcessor", + "AZ::Render::CapsuleLightFeatureProcessor", + "AZ::Render::QuadLightFeatureProcessor", + "AZ::Render::DecalTextureArrayFeatureProcessor", + "AZ::Render::ImageBasedLightFeatureProcessor", + "AZ::Render::PostProcessFeatureProcessor", + "AZ::Render::SkyBoxFeatureProcessor" }); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h new file mode 100644 index 0000000000..6c8e282d80 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + //! Processes requests for setting up content that gets rendered to a texture and captured to an image + class PreviewRenderer final + : public PreviewRendererInterface + , public PreviewerFeatureProcessorProviderBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0); + AZ_RTTI(PreviewRenderer, "{60FCB7AB-2A94-417A-8C5E-5B588D17F5D1}", PreviewRendererInterface); + + PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName); + ~PreviewRenderer() override; + + void AddCaptureRequest(const PreviewRendererCaptureRequest& captureRequest) override; + + AZ::RPI::ScenePtr GetScene() const override; + AZ::RPI::ViewPtr GetView() const override; + AZ::Uuid GetEntityContextId() const override; + + void ProcessCaptureRequests(); + void CancelCaptureRequest(); + void CompleteCaptureRequest(); + + void LoadContent(); + void UpdateLoadContent(); + void CancelLoadContent(); + + void PoseContent(); + + bool StartCapture(); + void EndCapture(); + + private: + //! AZ::Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... + void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = AZ::Constants::HalfPi; + + AZ::RPI::ScenePtr m_scene; + AZStd::shared_ptr m_frameworkScene; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::RPI::ViewPtr m_view; + AZStd::vector m_passHierarchy; + AZStd::unique_ptr m_entityContext; + + //! Incoming requests are appended to this queue and processed one at a time in OnTick function. + AZStd::queue m_captureRequestQueue; + PreviewRendererCaptureRequest m_currentCaptureRequest; + + AZStd::unique_ptr m_state; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp new file mode 100644 index 0000000000..5d1bd9158a --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.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 + +namespace AtomToolsFramework +{ + PreviewRendererCaptureState::PreviewRendererCaptureState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + m_renderer->PoseContent(); + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererCaptureState::~PreviewRendererCaptureState() + { + AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); + m_renderer->EndCapture(); + } + + void PreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + if ((m_ticksToCapture-- <= 0) && m_renderer->StartCapture()) + { + AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusDisconnect(); + } + } + + void PreviewRendererCaptureState::OnCaptureFinished( + [[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + { + m_renderer->CompleteCaptureRequest(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h new file mode 100644 index 0000000000..74195ab396 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished + class PreviewRendererCaptureState final + : public PreviewRendererState + , public AZ::TickBus::Handler + , public AZ::Render::FrameCaptureNotificationBus::Handler + { + public: + PreviewRendererCaptureState(PreviewRenderer* renderer); + ~PreviewRendererCaptureState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + //! AZ::Render::FrameCaptureNotificationBus::Handler overrides... + void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; + + //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials + int m_ticksToCapture = 1; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp new file mode 100644 index 0000000000..b60142dd14 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -0,0 +1,29 @@ +/* + * 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 AtomToolsFramework +{ + PreviewRendererIdleState::PreviewRendererIdleState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererIdleState::~PreviewRendererIdleState() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void PreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + m_renderer->ProcessCaptureRequests(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h new file mode 100644 index 0000000000..4a0bc9067e --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h @@ -0,0 +1,29 @@ +/* + * 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 AtomToolsFramework +{ + //! PreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick + class PreviewRendererIdleState final + : public PreviewRendererState + , public AZ::TickBus::Handler + { + public: + PreviewRendererIdleState(PreviewRenderer* renderer); + ~PreviewRendererIdleState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp new file mode 100644 index 0000000000..2a1d99a090 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.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 AtomToolsFramework +{ + PreviewRendererLoadState::PreviewRendererLoadState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + m_renderer->LoadContent(); + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererLoadState::~PreviewRendererLoadState() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void PreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + if ((m_timeRemainingS += deltaTime) > TimeOutS) + { + m_renderer->CancelLoadContent(); + return; + } + + m_renderer->UpdateLoadContent(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h new file mode 100644 index 0000000000..359329c8da --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h @@ -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 + * + */ + +#pragma once + +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded + class PreviewRendererLoadState final + : public PreviewRendererState + , public AZ::TickBus::Handler + { + public: + PreviewRendererLoadState(PreviewRenderer* renderer); + ~PreviewRendererLoadState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + static constexpr float TimeOutS = 5.0f; + float m_timeRemainingS = 0.0f; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h new file mode 100644 index 0000000000..53c452ef51 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererState.h @@ -0,0 +1,29 @@ +/* + * 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 + +namespace AtomToolsFramework +{ + class PreviewRenderer; + + //! PreviewRendererState is an interface for defining states that manages the logic flow of the PreviewRenderer + class PreviewRendererState + { + public: + explicit PreviewRendererState(PreviewRenderer* renderer) + : m_renderer(renderer) + { + } + + virtual ~PreviewRendererState() = default; + + protected: + PreviewRenderer* m_renderer = {}; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp new file mode 100644 index 0000000000..f88adfc65d --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp @@ -0,0 +1,75 @@ +/* + * 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 + +namespace AtomToolsFramework +{ + void PreviewRendererSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(0); + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("PreviewRendererSystemComponent", "System component that manages a global PreviewRenderer.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + } + } + } + + void PreviewRendererSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("PreviewRendererSystem")); + } + + void PreviewRendererSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("PreviewRendererSystem")); + } + + void PreviewRendererSystemComponent::Init() + { + } + + void PreviewRendererSystemComponent::Activate() + { + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); + PreviewRendererSystemRequestBus::Handler::BusConnect(); + } + + void PreviewRendererSystemComponent::Deactivate() + { + PreviewRendererSystemRequestBus::Handler::BusDisconnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + m_previewRenderer.reset(); + } + + void PreviewRendererSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline")); + }); + } + + void PreviewRendererSystemComponent::OnApplicationAboutToStop() + { + m_previewRenderer.reset(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h new file mode 100644 index 0000000000..8110d84794 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + //! System component that manages a global PreviewRenderer. + class PreviewRendererSystemComponent final + : public AZ::Component + , public AzFramework::AssetCatalogEventBus::Handler + , public AzFramework::ApplicationLifecycleEvents::Bus::Handler + , public PreviewRendererSystemRequestBus::Handler + { + public: + AZ_COMPONENT(PreviewRendererSystemComponent, "{E9F79FD8-82F2-4C80-966D-95F28484F229}"); + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + + protected: + // AZ::Component interface overrides... + void Init() override; + void Activate() override; + void Deactivate() override; + + private: + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + + // AzFramework::ApplicationLifecycleEvents overrides... + void OnApplicationAboutToStop() override; + + AZStd::unique_ptr m_previewRenderer; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 3d4bb82eec..a2446cebcc 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -58,4 +58,20 @@ set(FILES Source/Window/AtomToolsMainWindow.cpp Source/Window/AtomToolsMainWindowSystemComponent.cpp Source/Window/AtomToolsMainWindowSystemComponent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererCaptureRequest.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererInterface.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererSystemRequestBus.h + Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h + Source/PreviewRenderer/PreviewRenderer.cpp + Source/PreviewRenderer/PreviewRenderer.h + Source/PreviewRenderer/PreviewRendererState.h + Source/PreviewRenderer/PreviewRendererIdleState.cpp + Source/PreviewRenderer/PreviewRendererIdleState.h + Source/PreviewRenderer/PreviewRendererLoadState.cpp + Source/PreviewRenderer/PreviewRendererLoadState.h + Source/PreviewRenderer/PreviewRendererCaptureState.cpp + Source/PreviewRenderer/PreviewRendererCaptureState.h + Source/PreviewRenderer/PreviewRendererSystemComponent.cpp + Source/PreviewRenderer/PreviewRendererSystemComponent.h ) \ No newline at end of file diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index b45fbe05f6..39d8933863 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -1353,8 +1353,9 @@ namespace AZ::AtomBridge // if 2d draw need to project pos to screen first AzFramework::TextDrawParameters params; AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + const auto dpiScaleFactor = viewportContext->GetDpiScalingFactor(); params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works - params.m_position = AZ::Vector3(x, y, 1.0f); + params.m_position = AZ::Vector3(x * dpiScaleFactor, y * dpiScaleFactor, 1.0f); params.m_color = m_rendState.m_color; params.m_scale = AZ::Vector2(size); params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h index 557e6b3dd2..72c4ef97a8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -120,13 +120,6 @@ namespace AZ //! Sets the filter method of shadows. virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! Gets the width of softening boundary between shadowed area and lit area in degrees. - virtual float GetSofteningBoundaryWidthAngle() const = 0; - - //! Sets the width of softening boundary between shadowed area and lit area in degrees. - //! 0 disables softening. - virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0; - //! Gets the sample count for filtering of the shadow boundary. virtual uint32_t GetFilteringSampleCount() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index a6d3c6fbed..c76c922385 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -59,7 +59,6 @@ namespace AZ float m_bias = 0.1f; ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256; ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; - float m_boundaryWidthInDegrees = 0.25f; uint16_t m_filteringSampleCount = 12; float m_esmExponent = 87.0f; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h index 644856e768..a8088c63ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightBus.h @@ -153,15 +153,6 @@ namespace AZ //! @param method filter method. virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! This gets the width of boundary between shadowed area and lit area. - //! @return Boundary width. The shadow is gradually changed the degree of shadowed. - virtual float GetSofteningBoundaryWidth() const = 0; - - //! This specifies the width of boundary between shadowed area and lit area. - //! @param width Boundary width. The shadow is gradually changed the degree of shadowed. - //! If width == 0, softening edge is disabled. Units are in meters. - virtual void SetSofteningBoundaryWidth(float width) = 0; - //! This gets the sample count for filtering of the shadow boundary. //! @return Sample Count for filtering (up to 64) virtual uint32_t GetFilteringSampleCount() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h index 0123d06275..a58acc0114 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/DirectionalLightComponentConfig.h @@ -101,10 +101,6 @@ namespace AZ //! Method of shadow's filtering. ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; - //! Width of the boundary between shadowed area and lit one. - //! If this is 0, edge softening is disabled. Units are in meters. - float m_boundaryWidth = 0.03f; // 3cm - //! Sample Count for filtering (from 4 to 64) //! It is used only when the pixel is predicted as on the boundary. uint16_t m_filteringSampleCount = 32; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h new file mode 100644 index 0000000000..30762a60ba --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +class QPixmap; + +namespace AZ +{ + namespace Render + { + //! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like + //! being informed that material preview images are available + class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits + { + public: + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + + //! Notify that a material preview image is ready + virtual void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0; + }; + using EditorMaterialSystemComponentNotificationBus = AZ::EBus; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h index 47fad038b6..191f444586 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h @@ -5,20 +5,22 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include #include #include #include +#include namespace AZ { namespace Render { - //! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor - class EditorMaterialSystemComponentRequests - : public AZ::EBusTraits + //! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing + //! different operations like opening the material editor, the material instance inspector, and managing material preview images + class EditorMaterialSystemComponentRequests : public AZ::EBusTraits { public: // Only a single handler is allowed @@ -31,6 +33,14 @@ namespace AZ //! Open material instance editor virtual void OpenMaterialInspector( const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Generate a material preview image + virtual void RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Get recently rendered material preview image + virtual QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0; }; using EditorMaterialSystemComponentRequestBus = AZ::EBus; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h deleted file mode 100644 index 8030c3ae05..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation - //! Duplicates will be ignored - //! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp - class ThumbnailFeatureProcessorProviderRequests - : public AZ::EBusTraits - { - public: - //! Get a list of custom feature processors to register with thumbnail renderer - virtual const AZStd::vector& GetCustomFeatureProcessors() const = 0; - }; - - using ThumbnailFeatureProcessorProviderBus = AZ::EBus; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index c7af44a28e..f0418a5024 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -36,7 +36,6 @@ namespace AZ ->Field("Shadow Bias", &AreaLightComponentConfig::m_bias) ->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize) ->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod) - ->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) ->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent) ; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index c0204ecac5..36cb2a7f5a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -74,8 +74,6 @@ namespace AZ::Render ->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize) ->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod) ->Event("SetShadowFilterMethod", &AreaLightRequestBus::Events::SetShadowFilterMethod) - ->Event("GetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::GetSofteningBoundaryWidthAngle) - ->Event("SetSofteningBoundaryWidthAngle", &AreaLightRequestBus::Events::SetSofteningBoundaryWidthAngle) ->Event("GetFilteringSampleCount", &AreaLightRequestBus::Events::GetFilteringSampleCount) ->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent) @@ -95,7 +93,6 @@ namespace AZ::Render ->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias") ->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") - ->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") ->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent"); ; @@ -307,7 +304,6 @@ namespace AZ::Render m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias); m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize); m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); - m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent); } @@ -506,20 +502,6 @@ namespace AZ::Render } } - float AreaLightComponentController::GetSofteningBoundaryWidthAngle() const - { - return m_configuration.m_boundaryWidthInDegrees; - } - - void AreaLightComponentController::SetSofteningBoundaryWidthAngle(float width) - { - m_configuration.m_boundaryWidthInDegrees = width; - if (m_lightShapeDelegate) - { - m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(width); - } - } - uint32_t AreaLightComponentController::GetFilteringSampleCount() const { return m_configuration.m_filteringSampleCount; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index 3bec61551f..cc6223e7e5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -82,8 +82,6 @@ namespace AZ void SetShadowmapMaxSize(ShadowmapSize size) override; ShadowFilterMethod GetShadowFilterMethod() const override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - float GetSofteningBoundaryWidthAngle() const override; - void SetSofteningBoundaryWidthAngle(float width) override; uint32_t GetFilteringSampleCount() const override; void SetFilteringSampleCount(uint32_t count) override; float GetEsmExponent() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp index 37d94f5ed1..9d384c2e24 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp @@ -37,7 +37,6 @@ namespace AZ ->Field("IsCascadeCorrectionEnabled", &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled) ->Field("IsDebugColoringEnabled", &DirectionalLightComponentConfig::m_isDebugColoringEnabled) ->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod) - ->Field("SofteningBoundaryWidth", &DirectionalLightComponentConfig::m_boundaryWidth) ->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount) ->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp index fbc1ccc35d..78558cfc85 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.cpp @@ -80,8 +80,6 @@ namespace AZ ->Event("SetDebugColoringEnabled", &DirectionalLightRequestBus::Events::SetDebugColoringEnabled) ->Event("GetShadowFilterMethod", &DirectionalLightRequestBus::Events::GetShadowFilterMethod) ->Event("SetShadowFilterMethod", &DirectionalLightRequestBus::Events::SetShadowFilterMethod) - ->Event("GetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::GetSofteningBoundaryWidth) - ->Event("SetSofteningBoundaryWidth", &DirectionalLightRequestBus::Events::SetSofteningBoundaryWidth) ->Event("GetFilteringSampleCount", &DirectionalLightRequestBus::Events::GetFilteringSampleCount) ->Event("SetFilteringSampleCount", &DirectionalLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::GetShadowReceiverPlaneBiasEnabled) @@ -99,7 +97,6 @@ namespace AZ ->VirtualProperty("ViewFrustumCorrectionEnabled", "GetViewFrustumCorrectionEnabled", "SetViewFrustumCorrectionEnabled") ->VirtualProperty("DebugColoringEnabled", "GetDebugColoringEnabled", "SetDebugColoringEnabled") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") - ->VirtualProperty("SofteningBoundaryWidth", "GetSofteningBoundaryWidth", "SetSofteningBoundaryWidth") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") ->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled"); ; @@ -404,21 +401,6 @@ namespace AZ } } - float DirectionalLightComponentController::GetSofteningBoundaryWidth() const - { - return m_configuration.m_boundaryWidth; - } - - void DirectionalLightComponentController::SetSofteningBoundaryWidth(float width) - { - width = GetMin(Shadow::MaxSofteningBoundaryWidth, GetMax(0.f, width)); - m_configuration.m_boundaryWidth = width; - if (m_featureProcessor) - { - m_featureProcessor->SetShadowBoundaryWidth(m_lightHandle, width); - } - } - uint32_t DirectionalLightComponentController::GetFilteringSampleCount() const { return aznumeric_cast(m_configuration.m_filteringSampleCount); @@ -517,7 +499,6 @@ namespace AZ SetViewFrustumCorrectionEnabled(m_configuration.m_isCascadeCorrectionEnabled); SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled); SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); - SetSofteningBoundaryWidth(m_configuration.m_boundaryWidth); SetFilteringSampleCount(m_configuration.m_filteringSampleCount); SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h index b8052bfc36..933f2705e7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentController.h @@ -76,8 +76,6 @@ namespace AZ void SetDebugColoringEnabled(bool enabled) override; ShadowFilterMethod GetShadowFilterMethod() const override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - float GetSofteningBoundaryWidth() const override; - void SetSofteningBoundaryWidth(float width) override; uint32_t GetFilteringSampleCount() const override; void SetFilteringSampleCount(uint32_t count) override; bool GetShadowReceiverPlaneBiasEnabled() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index baf0cdced1..ebc79abca5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -147,14 +147,6 @@ namespace AZ::Render } } - void DiskLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) - { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); - } - } - void DiskLightDelegate::SetFilteringSampleCount(uint32_t count) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index e0fd16f6be..2be782c69c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -44,7 +44,6 @@ namespace AZ void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float exponent) override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 954ec4cad8..1e5b2580f7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -154,15 +154,6 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening boundary width", - "Width of the boundary between shadowed area and lit one. " - "Units are in degrees. " - "If this is 0, softening edge is disabled.") - ->Attribute(Edit::Attributes::Min, 0.f) - ->Attribute(Edit::Attributes::Max, 1.f) - ->Attribute(Edit::Attributes::Suffix, " deg") - ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count", "This is only used when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp index 2854244f6b..69ba295e9b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp @@ -133,15 +133,6 @@ namespace AZ ->EnumAttribute(ShadowFilterMethod::Esm, "ESM") ->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening boundary width", - "Width of the boundary between shadowed area and lit one. " - "Units are in meters. " - "If this is 0, softening edge is disabled.") - ->Attribute(Edit::Attributes::Min, 0.f) - ->Attribute(Edit::Attributes::Max, 0.1f) - ->Attribute(Edit::Attributes::Suffix, " m") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsEsmDisabled) ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count", "This is used only when the pixel is predicted as on the boundary. " "Specific to PCF and ESM+PCF.") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index 2bd25b76a3..336c67f55d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -56,7 +56,6 @@ namespace AZ void SetShadowBias([[maybe_unused]] float bias) override {}; void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {}; void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {}; - void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 6d08971542..9bb8188898 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -75,8 +75,6 @@ namespace AZ virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0; //! Sets the filter method for the shadow virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0; - //! Sets the width of boundary between shadowed area and lit area in degrees. - virtual void SetSofteningBoundaryWidthAngle(float widthInDegrees) = 0; //! Sets the sample count for filtering of the shadow boundary, max 64. virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index 8853db5751..661b0c6b25 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -92,14 +92,6 @@ namespace AZ::Render } } - void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) - { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); - } - } - void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index e2903b2d72..8bdee2442a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -34,7 +34,6 @@ namespace AZ void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; - void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float esmExponent) override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 896e88f4e2..1718dde5d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -6,15 +6,17 @@ * */ -#include -#include - -#include #include #include +#include +#include #include #include #include +#include +#include +#include +#include #include @@ -68,7 +70,7 @@ namespace AZ void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - AZ_UNUSED(required); + required.push_back(AZ_CRC_CE("ThumbnailerService")); } void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -82,24 +84,23 @@ namespace AZ void EditorCommonFeaturesSystemComponent::Activate() { - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique (); m_skinnedMeshDebugDisplay = AZStd::make_unique(); AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect(); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } void EditorCommonFeaturesSystemComponent::Deactivate() { - AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); - m_previewerFactory.reset(); - m_renderer.reset(); + TeardownThumbnails(); } void EditorCommonFeaturesSystemComponent::OnNewLevelCreated() @@ -191,6 +192,13 @@ namespace AZ } } + void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + SetupThumbnails(); + }); + } + const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory( const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { @@ -199,7 +207,33 @@ namespace AZ void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop() { + TeardownThumbnails(); + } + + void EditorCommonFeaturesSystemComponent::SetupThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache), + ThumbnailContext::DefaultContext); + + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); + } + + void EditorCommonFeaturesSystemComponent::TeardownThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName, + ThumbnailContext::DefaultContext); + m_renderer.reset(); + m_previewerFactory.reset(); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index 2560bf7e11..8021770873 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -11,10 +11,10 @@ #include #include #include -#include #include -#include -#include +#include +#include +#include namespace AZ { @@ -28,6 +28,7 @@ namespace AZ , public AzToolsFramework::EditorLevelNotificationBus::Handler , public AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , public AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler + , public AzFramework::AssetCatalogEventBus::Handler , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: @@ -53,15 +54,23 @@ namespace AZ void OnNewLevelCreated() override; // SliceEditorEntityOwnershipServiceBus overrides ... - void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; + void OnSliceInstantiated( + const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override; + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + // AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides... - const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; + const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory( + const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; // AzFramework::ApplicationLifecycleEvents overrides... void OnApplicationAboutToStop() override; + void SetupThumbnails(); + void TeardownThumbnails(); + private: AZStd::unique_ptr m_skinnedMeshDebugDisplay; @@ -69,8 +78,8 @@ namespace AZ AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" }; float m_envProbeHeight{ 200.0f }; - AZStd::unique_ptr m_renderer; - AZStd::unique_ptr m_previewerFactory; + AZStd::unique_ptr m_renderer; + AZStd::unique_ptr m_previewerFactory; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 8e5e7e2345..a3ae61b14b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -148,11 +148,13 @@ namespace AZ BaseClass::Activate(); MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId()); MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId()); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); UpdateMaterialSlots(); } void EditorMaterialComponent::Deactivate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialReceiverNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); BaseClass::Deactivate(); @@ -260,6 +262,18 @@ namespace AZ } } + void EditorMaterialComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + if (entityId == GetEntityId()) + { + AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( + &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); + } + } + AZ::u32 EditorMaterialComponent::OnConfigurationChanged() { return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h index f8895d994f..ce21ae82ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -21,8 +22,9 @@ namespace AZ //! In-editor material component for displaying and editing material assignments. class EditorMaterialComponent final : public EditorRenderComponentAdapter - , private MaterialReceiverNotificationBus::Handler - , private MaterialComponentNotificationBus::Handler + , public MaterialReceiverNotificationBus::Handler + , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { public: using BaseClass = EditorRenderComponentAdapter; @@ -52,6 +54,10 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override; + // Regenerates the editor component material slots based on the material and // LOD mapping from the model or other consumer of materials. // If any corresponding material assignments are found in the component diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 815f14aba7..b6875e2e9c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -23,10 +23,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -49,29 +45,18 @@ namespace AZ MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent) : AtomToolsFramework::InspectorWidget(parent) { - // Create the menu button - QToolButton* menuButton = new QToolButton(this); - menuButton->setAutoRaise(true); - menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); - menuButton->setVisible(true); - QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); - AddHeading(menuButton); - - m_messageLabel = new QLabel(this); - m_messageLabel->setWordWrap(true); - m_messageLabel->setVisible(true); - m_messageLabel->setAlignment(Qt::AlignCenter); - m_messageLabel->setText(tr("Material not available")); - AddHeading(m_messageLabel); - + CreateHeading(); + AZ::TickBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); } MaterialPropertyInspector::~MaterialPropertyInspector() { AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); - AZ::EntitySystemBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); + AZ::EntitySystemBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); } @@ -140,7 +125,7 @@ namespace AZ } Populate(); - m_messageLabel->setVisible(false); + LoadOverridesFromEntity(); return true; } @@ -152,8 +137,9 @@ namespace AZ m_dirtyPropertyFlags.set(); m_editorFunctors = {}; m_internalEditNotification = {}; - m_messageLabel->setVisible(true); - m_messageLabel->setText(tr("Material not available")); + m_updateUI = {}; + m_updatePreview = {}; + UpdateHeading(); } bool MaterialPropertyInspector::IsLoaded() const @@ -168,49 +154,63 @@ namespace AZ m_dirtyPropertyFlags.set(); m_internalEditNotification = {}; - AZ::TickBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); } - void MaterialPropertyInspector::AddDetailsGroup() + void MaterialPropertyInspector::CreateHeading() { - const AZStd::string& groupName = "Details"; - const AZStd::string& groupDisplayName = "Details"; - const AZStd::string& groupDescription = ""; + // Create the menu button + QToolButton* menuButton = new QToolButton(this); + menuButton->setAutoRaise(true); + menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); + menuButton->setVisible(true); + QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); + AddHeading(menuButton); - auto propertyGroupContainer = new QWidget(this); - propertyGroupContainer->setLayout(new QHBoxLayout()); + m_overviewImage = new QLabel(this); + m_overviewImage->setFixedSize(QSize(120, 120)); + m_overviewImage->setScaledContents(true); + m_overviewImage->setVisible(false); - AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey = - MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId); - auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this); - thumbnailWidget->setFixedSize(QSize(120, 120)); - thumbnailWidget->setVisible(true); - thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); - propertyGroupContainer->layout()->addWidget(thumbnailWidget); - - auto materialInfoWidget = new QLabel(this); + m_overviewText = new QLabel(this); QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth()); - materialInfoWidget->setSizePolicy(sizePolicy1); - materialInfoWidget->setMinimumSize(QSize(0, 0)); - materialInfoWidget->setMaximumSize(QSize(16777215, 16777215)); - materialInfoWidget->setTextFormat(Qt::AutoText); - materialInfoWidget->setScaledContents(false); - materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - materialInfoWidget->setWordWrap(true); + sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth()); + m_overviewText->setSizePolicy(sizePolicy1); + m_overviewText->setMinimumSize(QSize(0, 0)); + m_overviewText->setMaximumSize(QSize(16777215, 16777215)); + m_overviewText->setTextFormat(Qt::AutoText); + m_overviewText->setScaledContents(false); + m_overviewText->setWordWrap(true); + m_overviewText->setVisible(true); + + auto overviewContainer = new QWidget(this); + overviewContainer->setLayout(new QHBoxLayout()); + overviewContainer->layout()->addWidget(m_overviewImage); + overviewContainer->layout()->addWidget(m_overviewText); + AddHeading(overviewContainer); + } + + void MaterialPropertyInspector::UpdateHeading() + { + if (!IsLoaded()) + { + m_overviewText->setText(tr("Material not available")); + m_overviewText->setAlignment(Qt::AlignCenter); + m_overviewImage->setVisible(false); + return; + } QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str()); QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str()); QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str()); - QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); + QFileInfo materialParentSourceFileInfo( + AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); AZStd::string entityName; - AZ::ComponentApplicationBus::BroadcastResult( - entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); + AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); AZStd::string slotName; MaterialComponentRequestBus::EventResult( @@ -226,7 +226,8 @@ namespace AZ } if (!materialTypeSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); + materialInfo += + tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); } if (!materialSourceFileInfo.fileName().isEmpty()) { @@ -234,14 +235,21 @@ namespace AZ } if (!materialParentSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); + materialInfo += + tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); } materialInfo += tr(""); - materialInfoWidget->setText(materialInfo); - propertyGroupContainer->layout()->addWidget(materialInfoWidget); + m_overviewText->setText(materialInfo); + m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer); + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, + m_materialAssignmentId); + m_overviewImage->setPixmap(pixmap); + m_overviewImage->setVisible(true); + m_updatePreview |= pixmap.isNull(); } void MaterialPropertyInspector::AddUvNamesGroup() @@ -282,13 +290,8 @@ namespace AZ AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } - void MaterialPropertyInspector::Populate() + void MaterialPropertyInspector::AddPropertiesGroup() { - AddGroupsBegin(); - - AddDetailsGroup(); - AddUvNamesGroup(); - // Copy all of the properties from the material asset to the source data that will be exported for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) { @@ -327,10 +330,14 @@ namespace AZ [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } + } + void MaterialPropertyInspector::Populate() + { + AddGroupsBegin(); + AddUvNamesGroup(); + AddPropertiesGroup(); AddGroupsEnd(); - - LoadOverridesFromEntity(); } void MaterialPropertyInspector::LoadOverridesFromEntity() @@ -375,6 +382,7 @@ namespace AZ m_dirtyPropertyFlags.set(); RunEditorMaterialFunctors(); RebuildAll(); + UpdateHeading(); } void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges) @@ -398,6 +406,9 @@ namespace AZ MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); m_internalEditNotification = false; } + + // m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs + // throttling } void MaterialPropertyInspector::RunEditorMaterialFunctors() @@ -607,7 +618,8 @@ namespace AZ MaterialComponentRequestBus::Event( m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId, MaterialPropertyOverrideMap()); - QueueUpdateUI(); + m_updateUI = true; + m_updatePreview = true; }); action->setEnabled(IsLoaded()); @@ -702,10 +714,7 @@ namespace AZ void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId) { - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId) @@ -719,25 +728,39 @@ namespace AZ void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) { AZ_UNUSED(name); - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time) { AZ_UNUSED(time); AZ_UNUSED(deltaTime); - UpdateUI(); - AZ::TickBus::Handler::BusDisconnect(); + if (m_updateUI) + { + m_updateUI = false; + UpdateUI(); + } + + if (m_updatePreview) + { + m_updatePreview = false; + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId); + } } void MaterialPropertyInspector::OnMaterialsEdited() { - if (!m_internalEditNotification) + m_updateUI |= !m_internalEditNotification; + m_updatePreview = true; + } + + void MaterialPropertyInspector::OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) + { + if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId) { - QueueUpdateUI(); + m_overviewImage->setPixmap(pixmap); } } @@ -761,16 +784,6 @@ namespace AZ LoadMaterial(m_entityId, m_materialAssignmentId); } } - - void MaterialPropertyInspector::QueueUpdateUI() - { - if (!AZ::TickBus::Handler::BusIsConnected()) - { - AZ::TickBus::Handler::BusConnect(); - } - } } // namespace EditorMaterialComponentInspector } // namespace Render } // namespace AZ - -//#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h index 048c1e19cb..82f46ebc90 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h @@ -9,6 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include #include #include @@ -31,14 +32,13 @@ namespace AZ { namespace EditorMaterialComponentInspector { - using PropertyChangedCallback = AZStd::function; - class MaterialPropertyInspector : public AtomToolsFramework::InspectorWidget , public AzToolsFramework::IPropertyEditorNotify , public AZ::EntitySystemBus::Handler , public AZ::TickBus::Handler , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { Q_OBJECT public: @@ -89,11 +89,19 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialsEdited() override; - void UpdateUI(); - void QueueUpdateUI(); + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, + const AZ::Render::MaterialAssignmentId& materialAssignmentId, + const QPixmap& pixmap) override; + + void UpdateUI(); + + void CreateHeading(); + void UpdateHeading(); - void AddDetailsGroup(); void AddUvNamesGroup(); + void AddPropertiesGroup(); void LoadOverridesFromEntity(); void SaveOverridesToEntity(bool commitChanges); @@ -115,7 +123,10 @@ namespace AZ AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {}; AZStd::unordered_map m_groups = {}; bool m_internalEditNotification = {}; - QLabel* m_messageLabel = {}; + bool m_updateUI = {}; + bool m_updatePreview = {}; + QLabel* m_overviewText = {}; + QLabel* m_overviewImage = {}; }; } // namespace EditorMaterialComponentInspector } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index f5d38f48c4..d65fd0f2af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -6,23 +6,25 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include +#include +#include #include +#include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -100,6 +102,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel) ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true) ->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu) + ->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData) ; } } @@ -118,6 +121,33 @@ namespace AZ } }; + AZStd::vector EditorMaterialComponentSlot::GetPreviewPixmapData() const + { + if (!GetActiveAssetId().IsValid()) + { + return {}; + } + + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id); + if (pixmap.isNull()) + { + if (m_updatePreview) + { + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; + } + return {}; + } + + QByteArray pixmapBytes; + QDataStream stream(&pixmapBytes, QIODevice::WriteOnly); + stream << pixmap; + return AZStd::vector(pixmapBytes.begin(), pixmapBytes.end()); + } + AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const { return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId(); @@ -169,14 +199,6 @@ namespace AZ ClearOverrides(); } - void EditorMaterialComponentSlot::ClearToDefaultAsset() - { - m_materialAsset = AZ::Data::Asset(GetDefaultAssetId(), AZ::AzTypeInfo::Uuid()); - MaterialComponentRequestBus::Event( - m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId()); - ClearOverrides(); - } - void EditorMaterialComponentSlot::ClearOverrides() { MaterialComponentRequestBus::Event( @@ -315,6 +337,10 @@ namespace AZ AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast( &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId); + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; + MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index 377fe9a18b..78fc7449de 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -8,37 +8,52 @@ #pragma once -#include -#include - -#include -#include #include +#include +#include +#include +#include +#include namespace AZ { namespace Render { - static const size_t DefaultMaterialSlotIndex = std::numeric_limits::max(); - //! Details for a single editable material assignment struct EditorMaterialComponentSlot final { AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}"); AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0); - static void Reflect(ReflectContext* context); static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + static void Reflect(ReflectContext* context); + //! Get cached preview image as a buffer to use as an RPE attribute + //! If a cached image isn't avalible then a request will be made to render one + AZStd::vector GetPreviewPixmapData() const; + + //! Returns the overridden asset id if it's valid, otherwise gets the default asseet id AZ::Data::AssetId GetActiveAssetId() const; + + //! Returns the default asseet id of the material provded by the model AZ::Data::AssetId GetDefaultAssetId() const; + + //! Returns the display name of the material slot AZStd::string GetLabel() const; + + //! Returns true if the active material asset has a source material bool HasSourceData() const; + //! Assign a new material override asset void SetAsset(const Data::AssetId& assetId); + + //! Assign a new material override asset void SetAsset(const Data::Asset& asset); + + //! Remove material and prperty overrides void Clear(); - void ClearToDefaultAsset(); + + //! Remove prperty overrides void ClearOverrides(); void OpenMaterialExporter(); @@ -54,6 +69,7 @@ namespace AZ void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType); void OnMaterialChanged() const; void OnDataChanged() const; + mutable bool m_updatePreview = true; }; // Vector of slots for assignable or overridable material data. @@ -62,8 +78,8 @@ namespace AZ // Table containing all editable material data that is displayed in the edit context and inspector // The vector represents all the LODs that can have material overrides. // The container will be populated with every potential material slot on an associated model, using its default values. - // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map - // as overrides that will be applied to material instances + // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment + // map as overrides that will be applied to material instances using EditorMaterialComponentSlotsByLodContainer = AZStd::vector; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index a6b595940f..5df17a5478 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -7,6 +7,11 @@ */ #include +#include +#include +#include +#include +#include #include #include #include @@ -16,11 +21,10 @@ #include #include #include -#include #include #include #include -#include +#include // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class @@ -30,6 +34,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include #include #include +#include +#include #include AZ_POP_DISABLE_WARNING @@ -55,7 +61,7 @@ namespace AZ { ec->Class("EditorMaterialSystemComponent", "System component that manages launching and maintaining connections the material editor.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } @@ -64,17 +70,17 @@ namespace AZ void EditorMaterialSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); + provided.push_back(AZ_CRC_CE("EditorMaterialSystem")); } void EditorMaterialSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { - incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); + incompatible.push_back(AZ_CRC_CE("EditorMaterialSystem")); } void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97)); + required.push_back(AZ_CRC_CE("PreviewRendererSystem")); } void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -89,25 +95,23 @@ namespace AZ void EditorMaterialSystemComponent::Activate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); EditorMaterialSystemComponentRequestBus::Handler::BusConnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - SetupThumbnails(); m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); } void EditorMaterialSystemComponent::Deactivate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - TeardownThumbnails(); m_materialBrowserInteractions.reset(); if (m_openMaterialEditorAction) @@ -154,11 +158,76 @@ namespace AZ } } - void EditorMaterialSystemComponent::OnApplicationAboutToStop() + void EditorMaterialSystemComponent::RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) { - TeardownThumbnails(); + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + + if (auto previewRenderer = AZ::Interface::Get()) + { + AZ::Data::AssetId materialAssetId = {}; + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + return; + } + } + + AZ::Render::MaterialPropertyOverrideMap propertyOverrides; + AZ::Render::MaterialComponentRequestBus::EventResult( + propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides, + materialAssignmentId); + + previewRenderer->AddCaptureRequest( + { 128, + AZStd::make_shared( + previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(), + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId, + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), + [entityId, materialAssignmentId]() + { + AZ_Warning( + "EditorMaterialSystemComponent", false, "RenderMaterialPreview capture failed for entity %s slot %s.", + entityId.ToString().c_str(), materialAssignmentId.ToString().c_str()); + }, + [entityId, materialAssignmentId](const QPixmap& pixmap) + { + AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast( + &AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId, + materialAssignmentId, pixmap); + } }); + } } - + + QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const + { + const auto& itr1 = m_materialPreviews.find(entityId); + if (itr1 != m_materialPreviews.end()) + { + const auto& itr2 = itr1->second.find(materialAssignmentId); + if (itr2 != itr1->second.end()) + { + return itr2->second; + } + } + return QPixmap(); + } + + void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + m_materialPreviews[entityId][materialAssignmentId] = pixmap; + } + void EditorMaterialSystemComponent::OnPopulateToolMenuItems() { if (!m_openMaterialEditorAction) @@ -201,26 +270,6 @@ namespace AZ "Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions); } - void EditorMaterialSystemComponent::SetupThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache), - ThumbnailContext::DefaultContext); - } - - void EditorMaterialSystemComponent::TeardownThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); - } - AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails( const char* fullSourceFileName) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index 7fa43ea309..6fce538ead 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -5,31 +5,30 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once +#include +#include #include -#include #include #include -#include #include - -#include - #include +#include namespace AZ { namespace Render { //! System component that manages launching and maintaining connections with the material editor. - class EditorMaterialSystemComponent + class EditorMaterialSystemComponent final : public AZ::Component - , private EditorMaterialSystemComponentRequestBus::Handler - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler - , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler - , private AzToolsFramework::EditorMenuNotificationBus::Handler - , private AzToolsFramework::EditorEvents::Bus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler + , public EditorMaterialSystemComponentRequestBus::Handler + , public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler + , public AzToolsFramework::EditorMenuNotificationBus::Handler + , public AzToolsFramework::EditorEvents::Bus::Handler { public: AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}"); @@ -51,9 +50,13 @@ namespace AZ //! EditorMaterialSystemComponentRequestBus::Handler overrides... void OpenMaterialEditor(const AZStd::string& sourcePath) override; void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override; - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)override; //! AssetBrowserInteractionNotificationBus::Handler overrides... AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override; @@ -65,12 +68,9 @@ namespace AZ // AztoolsFramework::EditorEvents::Bus::Handler overrides... void NotifyRegisterViews() override; - void SetupThumbnails(); - void TeardownThumbnails(); - QAction* m_openMaterialEditorAction = nullptr; - AZStd::unique_ptr m_materialBrowserInteractions; + AZStd::unordered_map> m_materialPreviews; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp deleted file mode 100644 index 2931b647e5..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnail - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void MaterialThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::MaterialAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, - MaterialThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - MaterialThumbnail::~MaterialThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void MaterialThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && - m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnailCache - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnailCache::MaterialThumbnailCache() - : ThumbnailCache() - { - } - - MaterialThumbnailCache::~MaterialThumbnailCache() = default; - - int MaterialThumbnailCache::GetPriority() const - { - // Material thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* MaterialThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return - GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() && - // in case it's a source scene file, it will contain both material and model products - // model thumbnails are handled by MeshThumbnail - !GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h deleted file mode 100644 index 8f2053ba67..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ - class MaterialThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MaterialThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - /** - * Cache configuration for large material thumbnails - */ - class MaterialThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - MaterialThumbnailCache(); - ~MaterialThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "Material Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp index 8b2f6c8a11..c6a7ff1f50 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp @@ -6,13 +6,10 @@ * */ -#include #include #include -#include -#include -#include -#include +#include +#include namespace AZ { @@ -47,11 +44,6 @@ namespace AZ incompatible.push_back(AZ_CRC_CE("EditorMeshSystem")); } - void EditorMeshSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC_CE("ThumbnailerService")); - } - void EditorMeshSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); @@ -59,39 +51,10 @@ namespace AZ void EditorMeshSystemComponent::Activate() { - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); - SetupThumbnails(); } void EditorMeshSystemComponent::Deactivate() { - TeardownThumbnails(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); - } - - void EditorMeshSystemComponent::OnApplicationAboutToStop() - { - TeardownThumbnails(); - } - - void EditorMeshSystemComponent::SetupThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, - MAKE_TCACHE(Thumbnails::MeshThumbnailCache), - ThumbnailContext::DefaultContext); - } - - void EditorMeshSystemComponent::TeardownThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider, - Thumbnails::MeshThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h index 64d72bc33d..a784785830 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h @@ -8,7 +8,6 @@ #pragma once #include -#include namespace AZ { @@ -17,7 +16,6 @@ namespace AZ //! System component that sets up necessary logic related to EditorMeshComponent. class EditorMeshSystemComponent : public AZ::Component - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMeshSystemComponent, "{4D332E3D-C4FC-410B-A915-8E234CBDD4EC}"); @@ -26,20 +24,12 @@ namespace AZ 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 overrides... void Activate() override; void Deactivate() override; - - private: - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; - - void SetupThumbnails(); - void TeardownThumbnails(); }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp deleted file mode 100644 index 845197d939..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int MeshThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // MeshThumbnail - ////////////////////////////////////////////////////////////////////////// - MeshThumbnail::MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("MeshThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void MeshThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::ModelAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, - MeshThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - MeshThumbnail::~MeshThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void MeshThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void MeshThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void MeshThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && - m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // MeshThumbnailCache - ////////////////////////////////////////////////////////////////////////// - MeshThumbnailCache::MeshThumbnailCache() - : ThumbnailCache() - { - } - - MeshThumbnailCache::~MeshThumbnailCache() = default; - - int MeshThumbnailCache::GetPriority() const - { - // Material thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* MeshThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool MeshThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h deleted file mode 100644 index 872e1029d2..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ - class MeshThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MeshThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - /** - * Cache configuration for large material thumbnails - */ - class MeshThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - MeshThumbnailCache(); - ~MeshThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "Mesh Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp new file mode 100644 index 0000000000..91b6d2b02a --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + SharedPreviewContent::SharedPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides) + : m_scene(scene) + , m_view(view) + , m_entityContextId(entityContextId) + , m_materialPropertyOverrides(materialPropertyOverrides) + { + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "SharedPreviewContentModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_modelAsset.Create(modelAssetId); + m_materialAsset.Create(materialAssetId); + m_lightingPresetAsset.Create(lightingPresetAssetId); + } + + SharedPreviewContent::~SharedPreviewContent() + { + if (m_modelEntity) + { + m_modelEntity->Deactivate(); + AzFramework::EntityContextRequestBus::Event( + m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + } + + void SharedPreviewContent::Load() + { + m_modelAsset.QueueLoad(); + m_materialAsset.QueueLoad(); + m_lightingPresetAsset.QueueLoad(); + } + + bool SharedPreviewContent::IsReady() const + { + return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && + (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && + (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); + } + + bool SharedPreviewContent::IsError() const + { + return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); + } + + void SharedPreviewContent::ReportErrors() + { + AZ_Warning( + "SharedPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "SharedPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "SharedPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), + "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); + } + + void SharedPreviewContent::Update() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void SharedPreviewContent::UpdateModel() + { + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetMaterialOverride, + Render::DefaultMaterialAssignmentId, m_materialAsset.GetId()); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetPropertyOverrides, + Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides); + } + + void SharedPreviewContent::UpdateLighting() + { + if (m_lightingPresetAsset.IsReady()) + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + } + + void SharedPreviewContent::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + if (m_modelAsset.IsReady()) + { + m_modelAsset->GetAabb().GetAsSphere(center, radius); + } + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center + cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateLookAt(cameraPosition, center); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h new file mode 100644 index 0000000000..7308aa19bc --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + //! Creates a simple scene used for most previews and thumbnails + class SharedPreviewContent final : public AtomToolsFramework::PreviewContent + { + public: + AZ_CLASS_ALLOCATOR(SharedPreviewContent, AZ::SystemAllocator, 0); + + SharedPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides); + + ~SharedPreviewContent() override; + + void Load() override; + bool IsReady() const override; + bool IsError() const override; + void ReportErrors() override; + void Update() override; + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + Data::Asset m_modelAsset; + Data::Asset m_materialAsset; + Data::Asset m_lightingPresetAsset; + Render::MaterialPropertyOverrideMap m_materialPropertyOverrides; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp similarity index 55% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp index c8f67138ef..c2988cf53d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp @@ -11,37 +11,42 @@ #include #include #include -#include +#include +#include namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType) + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId) { - static const Data::AssetId invalidAssetId; - // if it's a source thumbnail key, find first product with a matching asset type auto sourceKey = azrtti_cast(key.data()); if (sourceKey) { bool foundIt = false; AZStd::vector productsAssetInfo; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, + sourceKey->GetSourceUuid(), productsAssetInfo); if (!foundIt) { - return invalidAssetId; + return defaultAssetId; } - auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(), + auto assetInfoIt = AZStd::find_if( + productsAssetInfo.begin(), productsAssetInfo.end(), [&assetType](const Data::AssetInfo& assetInfo) { return assetInfo.m_assetType == assetType; }); if (assetInfoIt == productsAssetInfo.end()) { - return invalidAssetId; + return defaultAssetId; } return assetInfoIt->m_assetId; @@ -53,10 +58,9 @@ namespace AZ { return productKey->GetAssetId(); } - return invalidAssetId; + return defaultAssetId; } - QString WordWrap(const QString& string, int maxLength) { QString result; @@ -81,6 +85,32 @@ namespace AZ } return result; } - } // namespace Thumbnails + + AZStd::unordered_set GetSupportedAssetTypes() + { + return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() }; + } + + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + { + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); + if (assetId.IsValid()) + { + if (typeId == RPI::AnyAsset::RTTI_Type()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); + return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); + } + return true; + } + } + + return false; + } + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h similarity index 53% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h index e4efcd6b49..6c5d83d22a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h @@ -18,13 +18,23 @@ namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { //! Get assetId by assetType that belongs to either source or product thumbnail key - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType); + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId = {}); - //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed + //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word + //! wrap needed QString WordWrap(const QString& string, int maxLength); - } // namespace Thumbnails + + //! Get the set of all asset types supported by the shared preview + AZStd::unordered_set GetSupportedAssetTypes(); + + //! Determine if a thumbnail key has an asset supported by the shared preview + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp similarity index 69% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp index 9730c7d4a9..942af55721 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp @@ -7,23 +7,21 @@ */ #include - +#include #include #include -#include -#include #include - -#include -#include +#include +#include +#include // Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class +// 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include -#include #include +#include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -32,18 +30,22 @@ namespace AZ { static constexpr int CharWidth = 6; - CommonPreviewer::CommonPreviewer(QWidget* parent) + SharedPreviewer::SharedPreviewer(QWidget* parent) : Previewer(parent) - , m_ui(new Ui::CommonPreviewerClass()) + , m_ui(new Ui::SharedPreviewerClass()) { m_ui->setupUi(this); } - CommonPreviewer::~CommonPreviewer() + SharedPreviewer::~SharedPreviewer() { } - void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) + void SharedPreviewer::Clear() const + { + } + + void SharedPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) { using namespace AzToolsFramework::AssetBrowser; using namespace AzToolsFramework::Thumbnailer; @@ -54,23 +56,23 @@ namespace AZ UpdateFileInfo(); } - const QString& CommonPreviewer::GetName() const + const QString& SharedPreviewer::GetName() const { return m_name; } - void CommonPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) + void SharedPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) { m_ui->m_previewWidget->setMaximumHeight(m_ui->m_previewWidget->width()); UpdateFileInfo(); } - void CommonPreviewer::UpdateFileInfo() const + void SharedPreviewer::UpdateFileInfo() const { - m_ui->m_fileInfoLabel->setText(Thumbnails::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); + m_ui->m_fileInfoLabel->setText(SharedPreviewUtils::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); } } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h similarity index 73% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h index 1dfa8788e0..ab6f793982 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h @@ -5,22 +5,23 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #if !defined(Q_MOC_RUN) -#include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include +#include AZ_POP_DISABLE_WARNING #endif namespace Ui { - class CommonPreviewerClass; + class SharedPreviewerClass; } namespace AzToolsFramework @@ -30,8 +31,8 @@ namespace AzToolsFramework class ProductAssetBrowserEntry; class SourceAssetBrowserEntry; class AssetBrowserEntry; - } -} + } // namespace AssetBrowser +} // namespace AzToolsFramework class QResizeEvent; @@ -39,18 +40,17 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewer final - : public AzToolsFramework::AssetBrowser::Previewer + class SharedPreviewer final : public AzToolsFramework::AssetBrowser::Previewer { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(CommonPreviewer, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewer, AZ::SystemAllocator, 0); - explicit CommonPreviewer(QWidget* parent = nullptr); - ~CommonPreviewer(); + explicit SharedPreviewer(QWidget* parent = nullptr); + ~SharedPreviewer(); // AzToolsFramework::AssetBrowser::Previewer overrides... - void Clear() const override {} + void Clear() const override; void Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) override; const QString& GetName() const override; @@ -60,9 +60,9 @@ namespace AZ private: void UpdateFileInfo() const; - QScopedPointer m_ui; + QScopedPointer m_ui; QString m_fileInfo; - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui similarity index 97% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui index f97dde0a1f..139231d607 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui @@ -1,7 +1,7 @@ - CommonPreviewerClass - + SharedPreviewerClass + 0 diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp new file mode 100644 index 0000000000..14d6e5b5f0 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp @@ -0,0 +1,33 @@ +/* + * 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 + +namespace AZ +{ + namespace LyIntegration + { + AzToolsFramework::AssetBrowser::Previewer* SharedPreviewerFactory::CreatePreviewer(QWidget* parent) const + { + return new SharedPreviewer(parent); + } + + bool SharedPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const + { + return SharedPreviewUtils::IsSupportedAssetType(entry->GetThumbnailKey()); + } + + const QString& SharedPreviewerFactory::GetName() const + { + return m_name; + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h similarity index 76% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h index 1f9cc9d5df..e3021cb8ab 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -18,14 +19,13 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewerFactory final - : public AzToolsFramework::AssetBrowser::PreviewerFactory + class SharedPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory { public: - AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewerFactory, AZ::SystemAllocator, 0); - CommonPreviewerFactory() = default; - ~CommonPreviewerFactory() = default; + SharedPreviewerFactory() = default; + ~SharedPreviewerFactory() = default; // AzToolsFramework::AssetBrowser::PreviewerFactory overrides... AzToolsFramework::AssetBrowser::Previewer* CreatePreviewer(QWidget* parent = nullptr) const override; @@ -33,7 +33,7 @@ namespace AZ const QString& GetName() const override; private: - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp new file mode 100644 index 0000000000..5d82bac139 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp @@ -0,0 +1,106 @@ +/* + * 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 + +namespace AZ +{ + namespace LyIntegration + { + static constexpr const int SharedThumbnailSize = 256; + + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnail + ////////////////////////////////////////////////////////////////////////// + SharedThumbnail::SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + : Thumbnail(key) + { + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); + if (assetId.IsValid()) + { + m_assetId = assetId; + m_typeId = typeId; + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + return; + } + } + + AZ_Error("SharedThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + m_state = State::Failed; + } + + void SharedThumbnail::LoadThread() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, SharedThumbnailSize); + // wait for response from thumbnail renderer + m_renderWait.acquire(); + } + + SharedThumbnail::~SharedThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + } + + void SharedThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) + { + m_pixmap = thumbnailImage; + m_renderWait.release(); + } + + void SharedThumbnail::ThumbnailFailedToRender() + { + m_state = State::Failed; + m_renderWait.release(); + } + + void SharedThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + { + if (m_assetId == assetId && m_state == State::Ready) + { + m_state = State::Unloaded; + Load(); + } + } + + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnailCache + ////////////////////////////////////////////////////////////////////////// + SharedThumbnailCache::SharedThumbnailCache() + : ThumbnailCache() + { + } + + SharedThumbnailCache::~SharedThumbnailCache() = default; + + int SharedThumbnailCache::GetPriority() const + { + // Custom thumbnails have a higher priority to override default source thumbnails + return 1; + } + + const char* SharedThumbnailCache::GetProviderName() const + { + return ProviderName; + } + + bool SharedThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + { + return SharedPreviewUtils::IsSupportedAssetType(key); + } + } // namespace LyIntegration +} // namespace AZ + +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h new file mode 100644 index 0000000000..dee433e0bb --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h @@ -0,0 +1,66 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +namespace AZ +{ + namespace LyIntegration + { + //! Custom thumbnail for most common Atom assets + //! Detects asset changes and updates the thumbnail + class SharedThumbnail final + : public AzToolsFramework::Thumbnailer::Thumbnail + , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler + , private AzFramework::AssetCatalogEventBus::Handler + { + Q_OBJECT + public: + SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~SharedThumbnail() override; + + //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... + void ThumbnailRendered(const QPixmap& thumbnailImage) override; + void ThumbnailFailedToRender() override; + + protected: + void LoadThread() override; + + private: + // AzFramework::AssetCatalogEventBus::Handler interface overrides... + void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; + + AZStd::binary_semaphore m_renderWait; + Data::AssetId m_assetId; + AZ::Uuid m_typeId; + }; + + //! Cache configuration for shared thumbnails + class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache + { + public: + SharedThumbnailCache(); + ~SharedThumbnailCache() override; + + int GetPriority() const override; + const char* GetProviderName() const override; + + static constexpr const char* ProviderName = "Common Feature Shared Thumbnail Provider"; + + protected: + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp new file mode 100644 index 0000000000..c43ba5f1cf --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + SharedThumbnailRenderer::SharedThumbnailRenderer() + { + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId); + } + SystemTickBus::Handler::BusConnect(); + } + + SharedThumbnailRenderer::~SharedThumbnailRenderer() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); + } + + void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) + { + if (auto previewRenderer = AZ::Interface::Get()) + { + previewRenderer->AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + previewRenderer->GetScene(), previewRenderer->GetView(), previewRenderer->GetEntityContextId(), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), + Render::MaterialPropertyOverrideMap()), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QPixmap& pixmap) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); + } }); + } + } + + bool SharedThumbnailRenderer::Installed() const + { + return true; + } + + void SharedThumbnailRenderer::OnSystemTick() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h new file mode 100644 index 0000000000..4db7728109 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + //! Provides custom thumbnail rendering of supported asset types + class SharedThumbnailRenderer final + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(SharedThumbnailRenderer, AZ::SystemAllocator, 0); + + SharedThumbnailRenderer(); + ~SharedThumbnailRenderer(); + + private: + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() const override; + + //! SystemTickBus::Handler interface overrides... + void OnSystemTick() override; + + // Default assets to be kept loaded and used for rendering if not overridden + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + + static constexpr const char* DefaultMaterialPath = ""; + const Data::AssetId DefaultMaterialAssetId; + Data::Asset m_defaultMaterialAsset; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp deleted file mode 100644 index 856d38d6cb..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - AzToolsFramework::AssetBrowser::Previewer* CommonPreviewerFactory::CreatePreviewer(QWidget* parent) const - { - return new CommonPreviewer(parent); - } - - bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const - { - return - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()).IsValid() || - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()).IsValid(); - } - - const QString& CommonPreviewerFactory::GetName() const - { - return m_name; - } - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp deleted file mode 100644 index 9c69fdd995..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - CommonThumbnailRenderer::CommonThumbnailRenderer() - : m_data(new ThumbnailRendererData) - { - // CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType - // since MaterialOrModelThumbnail dispatches event on materialAssetType address too - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); - SystemTickBus::Handler::BusConnect(); - ThumbnailFeatureProcessorProviderBus::Handler::BusConnect(); - - m_steps[Step::Initialize] = AZStd::make_shared(this); - m_steps[Step::FindThumbnailToRender] = AZStd::make_shared(this); - m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared(this); - m_steps[Step::Capture] = AZStd::make_shared(this); - m_steps[Step::ReleaseResources] = AZStd::make_shared(this); - - m_minimalFeatureProcessors = - { - "AZ::Render::TransformServiceFeatureProcessor", - "AZ::Render::MeshFeatureProcessor", - "AZ::Render::SimplePointLightFeatureProcessor", - "AZ::Render::SimpleSpotLightFeatureProcessor", - "AZ::Render::PointLightFeatureProcessor", - // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow - // flickering [ATOM-13568] - // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. - // Possibly re-enable with [GFX TODO][ATOM-13639] - // "AZ::Render::DirectionalLightFeatureProcessor", - "AZ::Render::DiskLightFeatureProcessor", - "AZ::Render::CapsuleLightFeatureProcessor", - "AZ::Render::QuadLightFeatureProcessor", - "AZ::Render::DecalTextureArrayFeatureProcessor", - "AZ::Render::ImageBasedLightFeatureProcessor", - "AZ::Render::PostProcessFeatureProcessor", - "AZ::Render::SkyBoxFeatureProcessor" - }; - } - - CommonThumbnailRenderer::~CommonThumbnailRenderer() - { - if (m_currentStep != Step::None) - { - CommonThumbnailRenderer::SetStep(Step::ReleaseResources); - } - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); - SystemTickBus::Handler::BusDisconnect(); - ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); - } - - void CommonThumbnailRenderer::SetStep(Step step) - { - if (m_currentStep != Step::None) - { - m_steps[m_currentStep]->Stop(); - } - m_currentStep = step; - m_steps[m_currentStep]->Start(); - } - - Step CommonThumbnailRenderer::GetStep() const - { - return m_currentStep; - } - - bool CommonThumbnailRenderer::Installed() const - { - return true; - } - - void CommonThumbnailRenderer::OnSystemTick() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); - } - - const AZStd::vector& CommonThumbnailRenderer::GetCustomFeatureProcessors() const - { - return m_minimalFeatureProcessors; - } - - AZStd::shared_ptr CommonThumbnailRenderer::GetData() const - { - return m_data; - } - - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) - { - m_data->m_thumbnailSize = thumbnailSize; - m_data->m_thumbnailQueue.push(thumbnailKey); - if (m_currentStep == Step::None) - { - SetStep(Step::Initialize); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h deleted file mode 100644 index 7c3b17e104..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include -#include - -#include - -// Disables warning messages triggered by the Qt library -// 4251: class needs to have dll-interface to be used by clients of class -// 4800: forcing value to bool 'true' or 'false' (performance warning) -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ThumbnailRendererStep; - - //! Provides custom rendering of material and model thumbnails - class CommonThumbnailRenderer - : public ThumbnailRendererContext - , private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , private SystemTickBus::Handler - , private ThumbnailFeatureProcessorProviderBus::Handler - { - public: - AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) - - CommonThumbnailRenderer(); - ~CommonThumbnailRenderer(); - - //! ThumbnailRendererContext overrides... - void SetStep(Step step) override; - Step GetStep() const override; - AZStd::shared_ptr GetData() const override; - - private: - //! ThumbnailerRendererRequestsBus::Handler interface overrides... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - - //! SystemTickBus::Handler interface overrides... - void OnSystemTick() override; - - //! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides... - const AZStd::vector& GetCustomFeatureProcessors() const override; - - AZStd::unordered_map> m_steps; - Step m_currentStep = Step::None; - AZStd::shared_ptr m_data; - AZStd::vector m_minimalFeatureProcessors; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h deleted file mode 100644 index d3bb2be64a..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - struct ThumbnailRendererData; - - enum class Step - { - None, - Initialize, - FindThumbnailToRender, - WaitForAssetsToLoad, - Capture, - ReleaseResources - }; - - //! An interface for ThumbnailRendererSteps to communicate with thumbnail renderer - class ThumbnailRendererContext - { - public: - virtual void SetStep(Step step) = 0; - virtual Step GetStep() const = 0; - virtual AZStd::shared_ptr GetData() const = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h deleted file mode 100644 index c471cf90d7..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 "Atom/RPI.Reflect/Model/ModelAsset.h" - -#include -#include -#include -#include -#include -#include - -namespace AzFramework -{ - class Scene; -} - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets - struct ThumbnailRendererData final - { - static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - - RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Material Thumbnail Scene"; - AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; - AZStd::shared_ptr m_frameworkScene; - RPI::RenderPipelinePtr m_renderPipeline; - AZStd::unique_ptr m_entityContext; - AZStd::vector m_passHierarchy; - - RPI::ViewPtr m_view = nullptr; - Entity* m_modelEntity = nullptr; - - int m_thumbnailSize = 512; - - //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_thumbnailQueue; - //! Current thumbnail key being rendered. - AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered; - - Data::Asset m_lightingPresetAsset; - - Data::Asset m_defaultModelAsset; - //! Model asset about to be rendered - Data::Asset m_modelAsset; - - Data::Asset m_defaultMaterialAsset; - //! Material asset about to be rendered - Data::Asset m_materialAsset; - - AZStd::unordered_set m_assetsToLoad; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp deleted file mode 100644 index f728d56bbc..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - CaptureStep::CaptureStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void CaptureStep::Start() - { - if (!m_context->GetData()->m_materialAsset || - !m_context->GetData()->m_modelAsset) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - return; - } - Render::MaterialComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_context->GetData()->m_materialAsset.GetId()); - Render::MeshComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MeshComponentRequestBus::Events::SetModelAsset, - m_context->GetData()->m_modelAsset); - RepositionCamera(); - m_readyToCapture = true; - m_ticksToCapture = 1; - TickBus::Handler::BusConnect(); - } - - void CaptureStep::Stop() - { - m_context->GetData()->m_renderPipeline->RemoveFromRenderTick(); - TickBus::Handler::BusDisconnect(); - Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); - } - - void CaptureStep::RepositionCamera() const - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - const Aabb& aabb = m_context->GetData()->m_modelAsset->GetAabb(); - Vector3 modelCenter; - float radius; - aabb.GetAsSphere(modelCenter, radius); - - float distance = StartingDistanceMultiplier * - GetMax(GetMax(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + - DepthNear; - const Quaternion cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), StartingRotationAngle); - Vector3 cameraPosition(modelCenter.GetX(), modelCenter.GetY() - distance, modelCenter.GetZ()); - cameraPosition = cameraRotation.TransformVector(cameraPosition); - auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_context->GetData()->m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); - } - - void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { - if (m_readyToCapture && m_ticksToCapture-- <= 0) - { - m_context->GetData()->m_renderPipeline->AddToRenderTickOnce(); - - RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result) - { - if (!result.m_dataBuffer) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - return; - } - uchar* data = result.m_dataBuffer.get()->data(); - QImage image( - data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); - QPixmap pixmap; - pixmap.convertFromImage(image); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - pixmap); - }; - - Render::FrameCaptureNotificationBus::Handler::BusConnect(); - bool startedCapture = false; - Render::FrameCaptureRequestBus::BroadcastResult( - startedCapture, - &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, - m_context->GetData()->m_passHierarchy, AZStd::string("Output"), readbackCallback, RPI::PassAttachmentReadbackOption::Output); - // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (startedCapture) - { - m_readyToCapture = false; - } - } - } - - void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) - { - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h deleted file mode 100644 index e93828e3b8..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! CaptureStep renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished - class CaptureStep - : public ThumbnailRendererStep - , private TickBus::Handler - , private Render::FrameCaptureNotificationBus::Handler - { - public: - CaptureStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - //! Places the camera so that the entire model is visible - void RepositionCamera() const; - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - //! Render::FrameCaptureNotificationBus::Handler overrides... - void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override; - - static constexpr float DepthNear = 0.01f; - static constexpr float StartingDistanceMultiplier = 1.75f; - static constexpr float StartingRotationAngle = Constants::QuarterPi / 2.0f; - - //! This flag is needed to wait one frame after each frame capture to reset FrameCaptureSystemComponent - bool m_readyToCapture = true; - //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials - int m_ticksToCapture = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp deleted file mode 100644 index 826ec4ae0d..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void FindThumbnailToRenderStep::Start() - { - TickBus::Handler::BusConnect(); - } - - void FindThumbnailToRenderStep::Stop() - { - TickBus::Handler::BusDisconnect(); - } - - void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { - PickNextThumbnail(); - } - - void FindThumbnailToRenderStep::PickNextThumbnail() - { - if (!m_context->GetData()->m_thumbnailQueue.empty()) - { - // pop the next thumbnailkey to be rendered from the queue - m_context->GetData()->m_thumbnailKeyRendered = m_context->GetData()->m_thumbnailQueue.front(); - m_context->GetData()->m_thumbnailQueue.pop(); - - // Find whether thumbnailkey contains a material asset or set a default material - m_context->GetData()->m_materialAsset = m_context->GetData()->m_defaultMaterialAsset; - Data::AssetId materialAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::MaterialAsset::RTTI_Type()); - if (materialAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(materialAssetId).second) - { - m_context->GetData()->m_materialAsset.Create(materialAssetId); - m_context->GetData()->m_materialAsset.QueueLoad(); - } - } - - // Find whether thumbnailkey contains a model asset or set a default model - m_context->GetData()->m_modelAsset = m_context->GetData()->m_defaultModelAsset; - Data::AssetId modelAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::ModelAsset::RTTI_Type()); - if (modelAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(modelAssetId).second) - { - m_context->GetData()->m_modelAsset.Create(modelAssetId); - m_context->GetData()->m_modelAsset.QueueLoad(); - } - } - - m_context->SetStep(Step::WaitForAssetsToLoad); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h deleted file mode 100644 index e63bc5dce5..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! FindThumbnailToRenderStep checks whether there are any new thumbnails that need to be rendered every tick - class FindThumbnailToRenderStep - : public ThumbnailRendererStep - , private TickBus::Handler - { - public: - FindThumbnailToRenderStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - void PickNextThumbnail(); - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp deleted file mode 100644 index 6f74627bee..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - InitializeStep::InitializeStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void InitializeStep::Start() - { - auto data = m_context->GetData(); - - data->m_entityContext = AZStd::make_unique(); - data->m_entityContext->InitContext(); - - // Create and register a scene with all required feature processors - RPI::SceneDescriptor sceneDesc; - - AZ::EBusAggregateResults> results; - ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors); - - AZStd::set featureProcessorNames; - for (auto& resultCollection : results.values) - { - for (auto& featureProcessorName : resultCollection) - { - if (featureProcessorNames.emplace(featureProcessorName).second) - { - sceneDesc.m_featureProcessorNames.push_back(featureProcessorName); - } - } - } - - data->m_scene = RPI::Scene::CreateScene(sceneDesc); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto* sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); - Outcome, AZStd::string> createSceneOutcome = - sceneSystem->CreateScene(data->m_sceneName); - AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); // This should never happen unless scene creation has changed. - data->m_frameworkScene = createSceneOutcome.TakeValue(); - data->m_frameworkScene->SetSubsystem(data->m_scene); - - data->m_frameworkScene->SetSubsystem(data->m_entityContext.get()); - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = data->m_pipelineName; - pipelineDesc.m_rootPassTemplate = "ThumbnailPipelineRenderToTexture"; - // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue - // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost - pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; - data->m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - data->m_scene->AddRenderPipeline(data->m_renderPipeline); - data->m_scene->Activate(); - RPI::RPISystemInterface::Get()->RegisterScene(data->m_scene); - data->m_passHierarchy.push_back(data->m_pipelineName); - data->m_passHierarchy.push_back("CopyToSwapChain"); - - // Connect camera to pipeline's default view after camera entity activated - Name viewName = Name("MainCamera"); - data->m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera); - - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, - Constants::QuarterPi, - AspectRatio, - NearDist, - FarDist, true); - data->m_view->SetViewToClipMatrix(viewToClipMatrix); - - data->m_renderPipeline->SetDefaultView(data->m_view); - - // Create lighting preset - data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(ThumbnailRendererData::LightingPresetPath); - if (data->m_lightingPresetAsset.IsReady()) - { - auto preset = data->m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = Constants::HalfPi; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, - skyboxFeatureProcessor, - exposureControlSettingInterface, - directionalLightFeatureProcessor, - cameraConfig, - lightHandles); - } - } - - // Create preview model - AzFramework::EntityContextRequestBus::EventResult(data->m_modelEntity, data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); - data->m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - data->m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - data->m_modelEntity->CreateComponent(azrtti_typeid()); - data->m_modelEntity->Init(); - data->m_modelEntity->Activate(); - - // preload default model - Data::AssetId defaultModelAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultModelAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultModelPath, - RPI::ModelAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultModelAssetId.IsValid(), "Default model asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultModelPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultModelAssetId).second) - { - data->m_defaultModelAsset.Create(defaultModelAssetId); - data->m_defaultModelAsset.QueueLoad(); - } - - // preload default material - Data::AssetId defaultMaterialAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultMaterialAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultMaterialPath, - RPI::MaterialAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultMaterialAssetId.IsValid(), "Default material asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultMaterialPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultMaterialAssetId).second) - { - data->m_defaultMaterialAsset.Create(defaultMaterialAssetId); - data->m_defaultMaterialAsset.QueueLoad(); - } - - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h deleted file mode 100644 index cdac492e80..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! InitializeStep sets up RPI system and scene and prepares it for rendering thumbnail entities - //! This step is only called once when CommonThumbnailRenderer begins rendering its first thumbnail - class InitializeStep - : public ThumbnailRendererStep - { - public: - InitializeStep(ThumbnailRendererContext* context); - - void Start() override; - - private: - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.1f; - static constexpr float FarDist = 100.0f; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp deleted file mode 100644 index a14f48e408..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - ReleaseResourcesStep::ReleaseResourcesStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void ReleaseResourcesStep::Start() - { - auto data = m_context->GetData(); - - data->m_defaultMaterialAsset.Release(); - data->m_defaultModelAsset.Release(); - data->m_materialAsset.Release(); - data->m_modelAsset.Release(); - data->m_lightingPresetAsset.Release(); - - if (data->m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity); - data->m_modelEntity = nullptr; - } - - data->m_scene->Deactivate(); - data->m_scene->RemoveRenderPipeline(data->m_renderPipeline->GetId()); - RPI::RPISystemInterface::Get()->UnregisterScene(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_entityContext.get()); - data->m_scene = nullptr; - data->m_frameworkScene = nullptr; - data->m_renderPipeline = nullptr; - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h deleted file mode 100644 index 4858b90b96..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ReleaseResourcesStep - : public ThumbnailRendererStep - { - public: - ReleaseResourcesStep(ThumbnailRendererContext* context); - - void Start() override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h deleted file mode 100644 index cc10f91525..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ThumbnailRendererContext; - - //! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces - class ThumbnailRendererStep - { - public: - explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {} - virtual ~ThumbnailRendererStep() = default; - - //! Start is called when step begins execution - virtual void Start() {} - //! Stop is called when step ends execution - virtual void Stop() {} - - protected: - ThumbnailRendererContext* m_context; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp deleted file mode 100644 index 4f32bc4b68..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 "Thumbnails/ThumbnailerBus.h" - -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void WaitForAssetsToLoadStep::Start() - { - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::Stop() - { - Data::AssetBus::Handler::BusDisconnect(); - TickBus::Handler::BusDisconnect(); - m_context->GetData()->m_assetsToLoad.clear(); - } - - void WaitForAssetsToLoadStep::LoadNextAsset() - { - if (m_context->GetData()->m_assetsToLoad.empty()) - { - // When all assets are loaded, render the thumbnail itself - m_context->SetStep(Step::Capture); - } - else - { - // Pick the the next asset and wait until its ready - const auto assetIdIt = m_context->GetData()->m_assetsToLoad.begin(); - m_context->GetData()->m_assetsToLoad.erase(assetIdIt); - m_assetId = *assetIdIt; - Data::AssetBus::Handler::BusConnect(m_assetId); - // If asset is already loaded, then AssetEvents will call OnAssetReady instantly and we don't need to wait this time - if (Data::AssetBus::Handler::BusIsConnected()) - { - TickBus::Handler::BusConnect(); - m_timeRemainingS = TimeOutS; - } - } - } - - void WaitForAssetsToLoadStep::OnAssetReady([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnAssetCanceled([[maybe_unused]] Data::AssetId assetId) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_timeRemainingS -= deltaTime; - if (m_timeRemainingS < 0) - { - auto assetIdStr = m_assetId.ToString(); - AZ_Warning("CommonThumbnailRenderer", false, "Timed out waiting for asset %s to load.", assetIdStr.c_str()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h deleted file mode 100644 index 921d1511ca..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded - class WaitForAssetsToLoadStep - : public ThumbnailRendererStep - , private Data::AssetBus::Handler - , private TickBus::Handler - { - public: - WaitForAssetsToLoadStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - void LoadNextAsset(); - - // AZ::Data::AssetBus::Handler - void OnAssetReady(Data::Asset asset) override; - void OnAssetError(Data::Asset asset) override; - void OnAssetCanceled(Data::AssetId assetId) override; - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - static constexpr float TimeOutS = 3.0f; - Data::AssetId m_assetId; - float m_timeRemainingS = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 174eb30b31..2714b65a56 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -7,9 +7,9 @@ # set(FILES + Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h - Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h Source/Module.cpp Source/Animation/EditorAttachmentComponent.h Source/Animation/EditorAttachmentComponent.cpp @@ -45,8 +45,6 @@ set(FILES Source/Material/EditorMaterialSystemComponent.h Source/Material/MaterialBrowserInteractions.h Source/Material/MaterialBrowserInteractions.cpp - Source/Material/MaterialThumbnail.cpp - Source/Material/MaterialThumbnail.h Source/Mesh/EditorMeshComponent.h Source/Mesh/EditorMeshComponent.cpp Source/Mesh/EditorMeshStats.h @@ -55,8 +53,6 @@ set(FILES Source/Mesh/EditorMeshSystemComponent.h Source/Mesh/EditorMeshStatsSerializer.cpp Source/Mesh/EditorMeshStatsSerializer.h - Source/Mesh/MeshThumbnail.h - Source/Mesh/MeshThumbnail.cpp Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp Source/PostProcess/EditorPostFxLayerComponent.cpp @@ -95,28 +91,19 @@ set(FILES Source/SkyBox/EditorHDRiSkyboxComponent.h Source/SkyBox/EditorPhysicalSkyComponent.cpp Source/SkyBox/EditorPhysicalSkyComponent.h - Source/Thumbnails/ThumbnailUtils.h - Source/Thumbnails/ThumbnailUtils.cpp - Source/Thumbnails/Preview/CommonPreviewer.cpp - Source/Thumbnails/Preview/CommonPreviewer.h - Source/Thumbnails/Preview/CommonPreviewer.ui - Source/Thumbnails/Preview/CommonPreviewerFactory.cpp - Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp - Source/Thumbnails/Rendering/CommonThumbnailRenderer.h - Source/Thumbnails/Rendering/ThumbnailRendererData.h - Source/Thumbnails/Rendering/ThumbnailRendererContext.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h + Source/SharedPreview/SharedPreviewer.cpp + Source/SharedPreview/SharedPreviewer.h + Source/SharedPreview/SharedPreviewer.ui + Source/SharedPreview/SharedPreviewerFactory.cpp + Source/SharedPreview/SharedPreviewerFactory.h + Source/SharedPreview/SharedPreviewContent.cpp + Source/SharedPreview/SharedPreviewContent.h + Source/SharedPreview/SharedPreviewUtils.cpp + Source/SharedPreview/SharedPreviewUtils.h + Source/SharedPreview/SharedThumbnail.cpp + Source/SharedPreview/SharedThumbnail.h + Source/SharedPreview/SharedThumbnailRenderer.cpp + Source/SharedPreview/SharedThumbnailRenderer.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py index 06dc15f5c1..a570489ed1 100644 --- a/Gems/Blast/Editor/Scripts/blast_asset_builder.py +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -95,7 +95,9 @@ def generate_assetinfo_product(request): outputFilename = os.path.join(request.tempDirPath, assetinfoFilename) # the only rule in it is to run this file again as a scene processor - currentScript = pathlib.Path(__file__).resolve() + currentScript = str(pathlib.Path(__file__).resolve()) + currentScript = currentScript.replace('\\', '/').lower() + currentScript = currentScript.replace('blast_asset_builder.py', 'blast_chunk_processor.py') aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]} jsonString = json.dumps(aDict) jsonFile = open(outputFilename, "w") @@ -167,124 +169,3 @@ try: pythonAssetBuilderHandler = register_asset_builder() except: pythonAssetBuilderHandler = None - -# -# SceneAPI Processor -# -blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) - -def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): - import azlmbr.scene - import azlmbr.object - import azlmbr.paths - import json, os - - jsonFilename = os.path.basename(scene.sourceFilename) - jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') - - # prepare output folder - basePath, _ = os.path.split(jsonFilename) - outputPath = os.path.join(outputDirectory, basePath) - if not os.path.exists(outputPath): - os.makedirs(outputPath, False) - - # write out a JSON file with the chunk file info - with open(jsonFilename, "w") as jsonFile: - jsonFile.write(scene.manifest.ExportToJson()) - - exportProduct = azlmbr.scene.ExportProduct() - exportProduct.filename = jsonFilename - exportProduct.sourceId = scene.sourceGuid - exportProduct.assetType = blastChunksAssetType - exportProduct.subId = 101 - - exportProductList = azlmbr.scene.ExportProductList() - exportProductList.AddProduct(exportProduct) - return exportProductList - -def on_prepare_for_export(args): - try: - scene = args[0] # azlmbr.scene.Scene - outputDirectory = args[1] # string - platformIdentifier = args[2] # string - productList = args[3] # azlmbr.scene.ExportProductList - return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) - except: - log_exception_traceback() - -def get_mesh_node_names(sceneGraph): - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - meshDataList = [] - node = sceneGraph.get_root() - children = [] - - while node.IsValid(): - # store children to process after siblings - if sceneGraph.has_node_child(node): - children.append(sceneGraph.get_node_child(node)) - - # store any node that has mesh data content - nodeContent = sceneGraph.get_node_content(node) - if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): - if sceneGraph.is_node_end_point(node) is False: - nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) - nodePath = nodeName.get_path() - if (len(nodeName.get_path())): - meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) - - # advance to next node - if sceneGraph.has_node_sibling(node): - node = sceneGraph.get_node_sibling(node) - elif children: - node = children.pop() - else: - node = azlmbr.scene.graph.NodeIndex() - - return meshDataList - -def update_manifest(scene): - import uuid, os - import azlmbr.scene as sceneApi - import azlmbr.scene.graph - from scene_api import scene_data as sceneData - - graph = sceneData.SceneGraph(scene.graph) - meshNameList = get_mesh_node_names(graph) - sceneManifest = sceneData.SceneManifest() - sourceFilenameOnly = os.path.basename(scene.sourceFilename) - sourceFilenameOnly = sourceFilenameOnly.replace('.','_') - - for activeMeshIndex in range(len(meshNameList)): - chunkName = meshNameList[activeMeshIndex] - chunkPath = chunkName.get_path() - meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) - meshGroup = sceneManifest.add_mesh_group(meshGroupName) - meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' - sceneManifest.mesh_group_select_node(meshGroup, chunkPath) - - return sceneManifest.export() - -sceneJobHandler = None - -def on_update_manifest(args): - try: - scene = args[0] - return update_manifest(scene) - except: - global sceneJobHandler - sceneJobHandler = None - log_exception_traceback() - -# try to create SceneAPI handler for processing -try: - import azlmbr.scene as sceneApi - if (sceneJobHandler == None): - sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() - sceneJobHandler.connect() - sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) - sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) -except: - sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py new file mode 100644 index 0000000000..d112f465e9 --- /dev/null +++ b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py @@ -0,0 +1,141 @@ +""" +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 +""" + +""" +This a Python Asset Builder script examines each .blast file to see if an +associated .fbx file needs to be processed by exporting all of its chunks +into a scene manifest + +This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene +manifest that writes out asset chunk data for .blast files +""" +import os, traceback, binascii, sys, json, pathlib +import azlmbr.math +import azlmbr.asset +import azlmbr.asset.entity +import azlmbr.asset.builder +import azlmbr.bus + +# +# SceneAPI Processor +# +blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) + +def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): + import azlmbr.scene + import azlmbr.object + import azlmbr.paths + import json, os + + jsonFilename = os.path.basename(scene.sourceFilename) + jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks') + + # prepare output folder + basePath, _ = os.path.split(jsonFilename) + outputPath = os.path.join(outputDirectory, basePath) + if not os.path.exists(outputPath): + os.makedirs(outputPath, False) + + # write out a JSON file with the chunk file info + with open(jsonFilename, "w") as jsonFile: + jsonFile.write(scene.manifest.ExportToJson()) + + exportProduct = azlmbr.scene.ExportProduct() + exportProduct.filename = jsonFilename + exportProduct.sourceId = scene.sourceGuid + exportProduct.assetType = blastChunksAssetType + exportProduct.subId = 101 + + exportProductList = azlmbr.scene.ExportProductList() + exportProductList.AddProduct(exportProduct) + return exportProductList + +def on_prepare_for_export(args): + try: + scene = args[0] # azlmbr.scene.Scene + outputDirectory = args[1] # string + platformIdentifier = args[2] # string + productList = args[3] # azlmbr.scene.ExportProductList + return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList) + except: + log_exception_traceback() + +def get_mesh_node_names(sceneGraph): + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + meshDataList = [] + node = sceneGraph.get_root() + children = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node)) + nodePath = nodeName.get_path() + if (len(nodeName.get_path())): + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList + +def update_manifest(scene): + import uuid, os + import azlmbr.scene as sceneApi + import azlmbr.scene.graph + from scene_api import scene_data as sceneData + + graph = sceneData.SceneGraph(scene.graph) + meshNameList = get_mesh_node_names(graph) + sceneManifest = sceneData.SceneManifest() + sourceFilenameOnly = os.path.basename(scene.sourceFilename) + sourceFilenameOnly = sourceFilenameOnly.replace('.','_') + + for activeMeshIndex in range(len(meshNameList)): + chunkName = meshNameList[activeMeshIndex] + chunkPath = chunkName.get_path() + meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) + meshGroup = sceneManifest.add_mesh_group(meshGroupName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' + sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + + return sceneManifest.export() + +sceneJobHandler = None + +def on_update_manifest(args): + try: + scene = args[0] + return update_manifest(scene) + except: + global sceneJobHandler + sceneJobHandler = None + log_exception_traceback() + +# try to create SceneAPI handler for processing +try: + import azlmbr.scene as sceneApi + if (sceneJobHandler == None): + sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + sceneJobHandler.connect() + sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export) +except: + sceneJobHandler = None diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp index 293dc51864..2dd470bd11 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp @@ -1061,12 +1061,8 @@ namespace EMStudio return true; } - if (m_activeGraph->GetCreateConnectionNode()->GetType() == StateGraphNode::TYPE_ID) - { - return false; - } - - return true; + const GraphNode* graphNode = m_activeGraph->GetCreateConnectionNode(); + return graphNode && graphNode->GetType() != StateGraphNode::TYPE_ID; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp index 759adbcb1c..49b986887c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp @@ -57,7 +57,6 @@ namespace EMStudio m_conEndOffset = QPoint(0, 0); m_conPortNr = InvalidIndex16; m_conIsInputPort = true; - m_conNode = nullptr; // nullptr when no connection is being created m_conPort = nullptr; m_conIsValid = false; m_targetPort = nullptr; @@ -151,6 +150,16 @@ namespace EMStudio return connections; } + bool NodeGraph::GetIsCreatingConnection() const + { + return (GetCreateConnectionNode() && !m_relinkConnection); + } + + bool NodeGraph::GetIsRelinkingConnection() const + { + return (GetCreateConnectionNode() && m_relinkConnection); + } + void NodeGraph::DrawOverlay(QPainter& painter) { EMotionFX::AnimGraphInstance* animGraphInstance = m_currentModelIndex.data(AnimGraphModel::ROLE_ANIM_GRAPH_INSTANCE).value(); @@ -1495,7 +1504,7 @@ namespace EMStudio { m_conPortNr = portNr; m_conIsInputPort = isInputPort; - m_conNode = portNode; + m_conNodeIndex = portNode->GetModelIndex(); m_conPort = port; m_conStartOffset = startOffset; } @@ -1505,7 +1514,7 @@ namespace EMStudio void NodeGraph::StartRelinkConnection(NodeConnection* connection, AZ::u16 portNr, GraphNode* node) { m_conPortNr = portNr; - m_conNode = node; + m_conNodeIndex = node->GetModelIndex(); m_relinkConnection = connection; //MCore::LogInfo( "StartRelinkConnection: Connection=(%s->%s) portNr=%i, graphNode=%s", connection->GetSourceNode()->GetName(), connection->GetTargetNode()->GetName(), portNr, node->GetName() ); @@ -1563,32 +1572,27 @@ namespace EMStudio m_replaceTransitionTail = nullptr; } - - // reset members void NodeGraph::StopRelinkConnection() { m_conPortNr = InvalidIndex16; - m_conNode = nullptr; + m_conNodeIndex = {}; m_relinkConnection = nullptr; m_conIsValid = false; m_targetPort = nullptr; } - - // reset members void NodeGraph::StopCreateConnection() { m_conPortNr = InvalidIndex16; m_conIsInputPort = true; - m_conNode = nullptr; // nullptr when no connection is being created + m_conNodeIndex = {}; m_conPort = nullptr; m_targetPort = nullptr; m_conIsValid = false; } - // render the connection we're creating, if any void NodeGraph::RenderReplaceTransition(QPainter& painter) { @@ -1628,6 +1632,16 @@ namespace EMStudio } } + GraphNode* NodeGraph::GetCreateConnectionNode() const + { + NodeGraph* activeGraph = m_graphWidget->GetActiveGraph(); + if (!activeGraph) + { + return nullptr; + } + + return activeGraph->FindGraphNode(m_conNodeIndex); + } // render the connection we're creating, if any void NodeGraph::RenderCreateConnection(QPainter& painter) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.h index 47b316ff81..4a059a59ec 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.h @@ -56,8 +56,8 @@ namespace EMStudio void SetScrollOffset(const QPoint& offset) { m_scrollOffset = offset; } void SetScalePivot(const QPoint& pivot) { m_scalePivot = pivot; } float GetLowestScale() const { return sLowestScale; } - bool GetIsCreatingConnection() const { return (m_conNode && m_relinkConnection == nullptr); } - bool GetIsRelinkingConnection() const { return (m_conNode && m_relinkConnection); } + bool GetIsCreatingConnection() const; + bool GetIsRelinkingConnection() const; void SetCreateConnectionIsValid(bool isValid) { m_conIsValid = isValid; } bool GetIsCreateConnectionValid() const { return m_conIsValid; } void SetTargetPort(NodePort* port) { m_targetPort = port; } @@ -79,7 +79,7 @@ namespace EMStudio bool GetReplaceTransitionValid() const { return m_replaceTransitionValid; } void RenderReplaceTransition(QPainter& painter); - GraphNode* GetCreateConnectionNode() { return m_conNode; } + GraphNode* GetCreateConnectionNode() const; NodeConnection* GetRelinkConnection() { return m_relinkConnection; } AZ::u16 GetCreateConnectionPortNr() const { return m_conPortNr; } bool GetCreateConnectionIsInputPort() const { return m_conIsInputPort; } @@ -199,7 +199,7 @@ namespace EMStudio QPoint m_conEndOffset; AZ::u16 m_conPortNr; bool m_conIsInputPort; - GraphNode* m_conNode; // nullptr when no connection is being created + QModelIndex m_conNodeIndex; NodeConnection* m_relinkConnection; // nullptr when not relinking a connection NodePort* m_conPort; NodePort* m_targetPort; diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h index d354153f9b..0006b79628 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonFixture.h @@ -27,7 +27,7 @@ namespace EMotionFX {} }; - class INTEG_PoseComparisonFixture + class PoseComparisonFixture : public SystemComponentFixture , public ::testing::WithParamInterface { @@ -47,8 +47,8 @@ namespace EMotionFX // This fixture exists to separate the tests that test the pose comparsion // functionality from the tests that use the pose comparison functionality // (even though it doesn't use the recording) - class INTEG_TestPoseComparisonFixture - : public INTEG_PoseComparisonFixture + class TestPoseComparisonFixture + : public PoseComparisonFixture { }; }; // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp index 27692a90ff..c704a5b114 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp @@ -154,14 +154,14 @@ namespace EMotionFX return MakeMatcher(new KeyTrackMatcher(expected, nodeName)); } - void INTEG_PoseComparisonFixture::SetUp() + void PoseComparisonFixture::SetUp() { SystemComponentFixture::SetUp(); LoadAssets(); } - void INTEG_PoseComparisonFixture::TearDown() + void PoseComparisonFixture::TearDown() { m_actorInstance->Destroy(); @@ -176,7 +176,7 @@ namespace EMotionFX SystemComponentFixture::TearDown(); } - void INTEG_PoseComparisonFixture::LoadAssets() + void PoseComparisonFixture::LoadAssets() { const AZStd::string actorPath = ResolvePath(GetParam().m_actorFile); m_actor = EMotionFX::GetImporter().LoadActor(actorPath); @@ -195,7 +195,7 @@ namespace EMotionFX m_actorInstance->SetAnimGraphInstance(AnimGraphInstance::Create(m_animGraph, m_actorInstance, m_motionSet)); } - TEST_P(INTEG_PoseComparisonFixture, Integ_TestPoses) + TEST_P(PoseComparisonFixture, TestPoses) { const AZStd::string recordingPath = ResolvePath(GetParam().m_recordingFile); Recorder* recording = EMotionFX::Recorder::LoadFromFile(recordingPath.c_str()); @@ -231,7 +231,7 @@ namespace EMotionFX recording->Destroy(); } - TEST_P(INTEG_TestPoseComparisonFixture, Integ_TestRecording) + TEST_P(TestPoseComparisonFixture, TestRecording) { // Make one recording, 10 seconds at 60 fps Recorder::RecordSettings settings; @@ -294,30 +294,30 @@ namespace EMotionFX recording->Destroy(); } - INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture, + INSTANTIATE_TEST_CASE_P(DISABLED_TestPoses, PoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ), PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" ) ) ); - INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture, + INSTANTIATE_TEST_CASE_P(DISABLED_TestPoseComparison, TestPoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@exefolder@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ) ) ); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp index 706ca48156..df246d230d 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.cpp @@ -17,10 +17,16 @@ #include #include +#include +#include #include +#include #include #include +#include +#include +#include namespace EditorPythonBindings { @@ -571,6 +577,37 @@ namespace EditorPythonBindings return false; } + pybind11::object PythonProxyObject::ToJson() + { + rapidjson::Document document; + AZ::JsonSerializerSettings settings; + settings.m_keepDefaults = true; + + auto resultCode = + AZ::JsonSerialization::Store(document, document.GetAllocator(), m_wrappedObject.m_address, nullptr, m_wrappedObject.m_typeId, settings); + + if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted) + { + AZ_Error("PythonProxyObject", false, "Failed to serialize to json"); + return pybind11::cast(Py_None); + } + + AZStd::string jsonString; + AZ::Outcome outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString); + + if (!outcome.IsSuccess()) + { + AZ_Error("PythonProxyObject", false, "Failed to write json string: %s", outcome.GetError().c_str()); + return pybind11::cast(Py_None); + } + + jsonString.erase(AZStd::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end()); + auto pythonCode = AZStd::string::format( + R"PYTHON(exec("import json") or json.loads("""%s"""))PYTHON", jsonString.c_str()); + + return pybind11::eval(pythonCode.c_str()); + } + bool PythonProxyObject::DoComparisonEvaluation(pybind11::object pythonOther, Comparison comparison) { bool invertLogic = false; @@ -912,6 +949,7 @@ namespace EditorPythonBindings .def("set_property", &PythonProxyObject::SetPropertyValue) .def("get_property", &PythonProxyObject::GetPropertyValue) .def("invoke", &PythonProxyObject::Invoke) + .def("to_json", &PythonProxyObject::ToJson) .def(Operator::s_isEqual, [](PythonProxyObject& self, pybind11::object rhs) { return self.DoEqualityEvaluation(rhs); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h index 5b611c32c0..a9d2fad5a0 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h +++ b/Gems/EditorPythonBindings/Code/Source/PythonProxyObject.h @@ -58,6 +58,8 @@ namespace EditorPythonBindings //! Performs an equality operation to compare this object with another object bool DoEqualityEvaluation(pybind11::object pythonOther); + pybind11::object ToJson(); + //! Perform a comparison of a Python operator enum class Comparison { diff --git a/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl b/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl index be9ddb4f20..800257e157 100644 --- a/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl +++ b/Gems/ExpressionEvaluation/Code/Source/ExpressionPrimitivesSerializers.inl @@ -28,6 +28,19 @@ namespace AZ private: using VariableDescriptor = ExpressionEvaluation::ExpressionTree::VariableDescriptor; + static constexpr AZStd::string_view EmptyAnyIdentifier = "Empty AZStd::any"; + + static bool IsEmptyAny(const rapidjson::Value& typeId) + { + if (typeId.IsString()) + { + AZStd::string_view typeName(typeId.GetString(), typeId.GetStringLength()); + return typeName == EmptyAnyIdentifier; + } + + return false; + } + JsonSerializationResult::Result Load ( void* outputValue , [[maybe_unused]] const Uuid& outputValueTypeId @@ -62,22 +75,25 @@ namespace AZ , JsonSerialization::TypeIdFieldIdentifier)); } - result.Combine(LoadTypeId(typeId, typeIdMember->value, context)); - if (typeId.IsNull()) + if (!IsEmptyAny(typeIdMember->value)) { - return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic - , "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value"); - } + result.Combine(LoadTypeId(typeId, typeIdMember->value, context)); + if (typeId.IsNull()) + { + return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic + , "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value"); + } - AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId); - if (storage.empty() || storage.type() != typeId) - { - return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the " - "reported AZ TypeId. The C++ declaration may have been deleted or changed."); - } + AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId); + if (storage.empty() || storage.type() != typeId) + { + return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the " + "reported AZ TypeId. The C++ declaration may have been deleted or changed."); + } - result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast(&storage), typeId, inputValue, "Value", context)); - outputDatum->m_value = storage; + result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast(&storage), typeId, inputValue, "Value", context)); + outputDatum->m_value = storage; + } // any storage end return context.Report(result, result.GetProcessing() != JSR::Processing::Halted @@ -123,20 +139,32 @@ namespace AZ , azrtti_typeidm_supportedTypes)>() , context)); - rapidjson::Value typeValue; - result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context)); - outputValue.AddMember - ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) - , AZStd::move(typeValue) - , context.GetJsonAllocator()); + if (!inputScriptDataPtr->m_value.empty()) + { + rapidjson::Value typeValue; + result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context)); + outputValue.AddMember + ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) + , AZStd::move(typeValue) + , context.GetJsonAllocator()); - result.Combine(ContinueStoringToJsonObjectField - ( outputValue - , "Value" - , AZStd::any_cast(const_cast(&inputScriptDataPtr->m_value)) - , defaultScriptDataPtr ? AZStd::any_cast(const_cast(&defaultScriptDataPtr->m_value)) : nullptr - , inputScriptDataPtr->m_value.type() - , context)); + result.Combine(ContinueStoringToJsonObjectField + ( outputValue + , "Value" + , AZStd::any_cast(const_cast(&inputScriptDataPtr->m_value)) + , defaultScriptDataPtr ? AZStd::any_cast(const_cast(&defaultScriptDataPtr->m_value)) : nullptr + , inputScriptDataPtr->m_value.type() + , context)); + } + else + { + rapidjson::Value emptyAny; + emptyAny.SetString(EmptyAnyIdentifier.data(), aznumeric_caster(EmptyAnyIdentifier.size()), context.GetJsonAllocator()); + outputValue.AddMember + ( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier) + , AZStd::move(emptyAny) + , context.GetJsonAllocator()); + } return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ? "VariableDescriptor Store finished saving VariableDescriptor" diff --git a/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp b/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp index c7540d091f..48826fcf10 100644 --- a/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp +++ b/Gems/HttpRequestor/Code/Tests/HttpRequestorTest.cpp @@ -7,52 +7,50 @@ */ #include +#include #include #include #include #include "HttpRequestManager.h" -class Integ_HttpTest - : public ::testing::Test +class HttpTest + : public UnitTest::ScopedAllocatorSetupFixture { -public: - HttpRequestor::ManagerPtr m_httpRequestManager; - - // to wait for test to complete - AZStd::mutex m_requestMutex; - AZStd::condition_variable m_requestConditionVar; - - AZStd::string resultData; - AZStd::atomic resultCode; - - Integ_HttpTest() - { - m_httpRequestManager = AZStd::make_shared(); - resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE; - resultData = "{}"; - - AZStd::unique_lock lock(m_requestMutex); - m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10)); - } - - virtual ~Integ_HttpTest() - { - m_httpRequestManager.reset(); - } }; -TEST_F(Integ_HttpTest, HttpRequesterTest) +TEST_F(HttpTest, DISABLED_HttpRequesterTest) { - m_httpRequestManager->AddTextRequest(HttpRequestor::TextParameters("https://httpbin.org/ip", Aws::Http::HttpMethod::HTTP_GET, [this](const AZStd::string & data, Aws::Http::HttpResponseCode code) - { - resultData = data; - resultCode = code; - m_requestConditionVar.notify_all(); - })); + HttpRequestor::Manager httpRequestManager; - AZStd::unique_lock lock(m_requestMutex); - m_requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000)); + // to wait for test to complete + AZStd::mutex requestMutex; + AZStd::condition_variable requestConditionVar; + + AZStd::string resultData = {}; + AZStd::atomic resultCode = Aws::Http::HttpResponseCode::REQUEST_NOT_MADE; + + { + AZStd::unique_lock lock(requestMutex); + requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(10)); + } + + httpRequestManager.AddTextRequest( + HttpRequestor::TextParameters("https://httpbin.org/ip", + Aws::Http::HttpMethod::HTTP_GET, + [&resultData, &resultCode, &requestConditionVar](const AZStd::string& data, Aws::Http::HttpResponseCode code) + { + resultData = data; + resultCode = code; + requestConditionVar.notify_all(); + } + ) + ); + + { + AZStd::unique_lock lock(requestMutex); + requestConditionVar.wait_for(lock, AZStd::chrono::milliseconds(5000)); + } EXPECT_NE(Aws::Http::HttpResponseCode::REQUEST_NOT_MADE, resultCode); } diff --git a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp index 7275909908..2d3f67c112 100644 --- a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp @@ -26,12 +26,12 @@ namespace UnitTest { - class Integ_BundlingSystemComponentFixture : + class BundlingSystemComponentFixture : public ::testing::Test { public: - Integ_BundlingSystemComponentFixture() = default; + BundlingSystemComponentFixture() = default; bool TestAsset(const char* assetPath) { @@ -59,7 +59,7 @@ namespace UnitTest } }; - TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundles_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundles_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -72,7 +72,7 @@ namespace UnitTest EXPECT_FALSE(TestAsset(testAssetPath)); } - TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundlesCatalogChecks_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_HasBundle_LoadBundlesCatalogChecks_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -92,7 +92,7 @@ namespace UnitTest EXPECT_FALSE(TestAsset(noCatalogAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleUnloadCheckCatalog_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleUnloadCheckCatalog_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -132,7 +132,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testDDSAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleLoadAndBundleMode_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SingleLoadAndBundleMode_Success) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -157,7 +157,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testMTLAsset)); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_OpenClosePackCount_Match) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_OpenClosePackCount_Match) { // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below @@ -198,7 +198,7 @@ namespace UnitTest EXPECT_EQ(bundleCount, 0); } - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SplitPakTestWithAsset_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SplitPakTestWithAsset_Success) { // This asset lives only within LmbrCentral/Assets/Test/SplitBundleTest/splitbundle__1.pak which is a dependent bundle of splitbundle.pak const char testDDSAsset_split[] = "textures/milestone2/am_floor_tile_ddna_test.dds.7"; @@ -228,7 +228,7 @@ namespace UnitTest } // Verify that our bundles using catalogs of the same name work properly - TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SharedCatalogName_Success) + TEST_F(BundlingSystemComponentFixture, DISABLED_BundleSystemComponent_SharedCatalogName_Success) { // This bundle was built for PC but is generic and the test should work fine on other platforms // gamepropertioessmall_pc.pak has a smaller version of the gameproperties csv diff --git a/Gems/PhysX/Code/Editor/DebugDraw.cpp b/Gems/PhysX/Code/Editor/DebugDraw.cpp index 440b198675..5936312ecf 100644 --- a/Gems/PhysX/Code/Editor/DebugDraw.cpp +++ b/Gems/PhysX/Code/Editor/DebugDraw.cpp @@ -148,16 +148,16 @@ namespace PhysX using VisibilityFunc = bool(*)(); editContext->Class( - "PhysX Collider Debug Draw", "Manages global and per-collider debug draw settings and logic") + "PhysX Collider Debug Draw", "Global and per-collider debug draw preferences.") ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Collider::m_locallyEnabled, "Draw collider", - "Shows the geometry for the collider in the viewport") + "Display collider geometry in the viewport.") ->Attribute(AZ::Edit::Attributes::CheckboxTooltip, "If set, the geometry of this collider is visible in the viewport. 'Draw Helpers' needs to be enabled to use.") ->Attribute(AZ::Edit::Attributes::Visibility, VisibilityFunc{ []() { return IsGlobalColliderDebugCheck(GlobalCollisionDebugState::Manual); } }) ->Attribute(AZ::Edit::Attributes::ReadOnly, &IsDrawColliderReadOnly) ->DataElement(AZ::Edit::UIHandlers::Button, &Collider::m_globalButtonState, "Draw collider", - "Shows the geometry for the collider in the viewport") + "Display collider geometry in the viewport.") ->Attribute(AZ::Edit::Attributes::ButtonText, "Global override") ->Attribute(AZ::Edit::Attributes::ButtonTooltip, "A global setting is overriding this property (to disable the override, " diff --git a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp index b9ed827ce0..02e684de63 100644 --- a/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp +++ b/Gems/PhysX/Code/Editor/EditorJointConfiguration.cpp @@ -51,23 +51,27 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Editor Joint Limit Config Base", "Base joint limit parameters") + "Editor Joint Limit Config Base", "Base joint limit parameters.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit", "True if the motion about the unconstrained axes of this joint are limited") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isLimited, "Limit", + "When active, the joint's degrees of freedom are limited.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit", "True if the joint is allowed to rotate beyond limits and spring back") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_isSoftLimit, "Soft limit", + "When active, motion beyond the joint limit with a spring-like return is allowed.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::m_isLimited) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointLimitConfig::IsInComponentMode) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping", "The damping strength of the drive, the force proportional to the velocity error") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_damping, "Damping", + "Dissipation of energy and reduction in spring oscillations when outside the joint limit.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited) ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) - ->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", "The spring strength of the drive, the force proportional to the position error") + ->DataElement(0, &PhysX::EditorJointLimitConfig::m_stiffness, "Stiffness", + "The spring's drive relative to the position of the follower when outside the joint limit.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConfig::IsSoftLimited) ->Attribute(AZ::Edit::Attributes::Max, s_springMax) ->Attribute(AZ::Edit::Attributes::Min, s_springMin) @@ -115,18 +119,20 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Angular Limit", "Rotation limitation") + "Angular Limit", "Rotation limitation.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_standardLimitConfig , "Standard limit configuration" - , "Common limit parameters to all joint types") - ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit", "Positive rotation angle") + , "Common limit parameters to all joint types.") + ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitPositive, "Positive angular limit", + "Positive rotation angle.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) - ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit", "Negative rotation angle") + ->DataElement(0, &PhysX::EditorJointLimitPairConfig::m_limitNegative, "Negative angular limit", + "Negative rotation angle.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitPairConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMin) ->Attribute(AZ::Edit::Attributes::Min, -s_angleMax) @@ -164,18 +170,20 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Angular Limit", "Rotation limitation") + "Angular Limit", "Rotation limitation.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_standardLimitConfig , "Standard limit configuration" - , "Common limit parameters to all joint types") - ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit", "Limit for swing angle about Y axis") + , "Common limit parameters to all joint types.") + ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitY, "Y axis angular limit", + "Limit for swing angle about Y axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) - ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit", "Limit for swing angle about Z axis") + ->DataElement(0, &PhysX::EditorJointLimitConeConfig::m_limitZ, "Z axis angular limit", + "Limit for swing angle about Z axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointLimitConeConfig::IsLimited) ->Attribute(AZ::Edit::Attributes::Max, s_angleMax) ->Attribute(AZ::Edit::Attributes::Min, s_angleMin) @@ -226,33 +234,33 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(0, &PhysX::EditorJointConfig::m_localPosition, "Local Position" - , "Local Position of joint, relative to its entity") + , "Local Position of joint, relative to its entity.") ->DataElement(0, &PhysX::EditorJointConfig::m_localRotation, "Local Rotation" - , "Local Rotation of joint, relative to its entity") + , "Local Rotation of joint, relative to its entity.") ->Attribute(AZ::Edit::Attributes::Min, LocalRotationMin) ->Attribute(AZ::Edit::Attributes::Max, LocalRotationMax) ->DataElement(0, &PhysX::EditorJointConfig::m_leadEntity, "Lead Entity" - , "Parent entity associated with joint") + , "Parent entity associated with joint.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorJointConfig::ValidateLeadEntityId) ->DataElement(0, &PhysX::EditorJointConfig::m_selfCollide, "Lead-Follower Collide" - , "Lead and follower pair will collide with each other") + , "When active, the lead and follower pair will collide with each other.") ->DataElement(0, &PhysX::EditorJointConfig::m_displayJointSetup, "Display Setup in Viewport" - , "Display joint setup in the viewport") + , "Display joint setup in the viewport.") ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode) ->DataElement(0, &PhysX::EditorJointConfig::m_selectLeadOnSnap, "Select Lead on Snap" - , "Select lead entity on snap to position in component mode") + , "Select lead entity on snap to position in component mode.") ->DataElement(0, &PhysX::EditorJointConfig::m_breakable , "Breakable" - , "Joint is breakable when force or torque exceeds limit") + , "Joint is breakable when force or torque exceeds limit.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorJointConfig::IsInComponentMode) ->DataElement(0, &PhysX::EditorJointConfig::m_forceMax, - "Maximum Force", "Amount of force joint can withstand before breakage") + "Maximum Force", "Amount of force joint can withstand before breakage.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable) ->Attribute(AZ::Edit::Attributes::Max, s_breakageMax) ->Attribute(AZ::Edit::Attributes::Min, s_breakageMin) ->DataElement(0, &PhysX::EditorJointConfig::m_torqueMax, - "Maximum Torque", "Amount of torque joint can withstand before breakage") + "Maximum Torque", "Amount of torque joint can withstand before breakage.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorJointConfig::m_breakable) ->Attribute(AZ::Edit::Attributes::Max, s_breakageMax) ->Attribute(AZ::Edit::Attributes::Min, s_breakageMin) diff --git a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp index 7a441a1c55..02f0bc038a 100644 --- a/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Configuration/PhysXConfiguration.cpp @@ -54,17 +54,17 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("Wind Configuration", "Wind settings for PhysX") + editContext->Class("Wind Configuration", "Wind force entity tags.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_globalWindTag, "Global wind tag", - "Tag value that will be used to mark entities that provide global wind value.\n" - "Global wind has no bounds and affects objects across entire level.") + "Global wind provider tags.\n" + "Global winds apply to entire world.") ->DataElement(AZ::Edit::UIHandlers::Default, &WindConfiguration::m_localWindTag, "Local wind tag", - "Tag value that will be used to mark entities that provide local wind value.\n" - "Local wind is only applied within bounds defined by PhysX collider.") + "Local wind provider tags.\n" + "Local winds are constrained to a PhysX collider's boundaries.") ; } } diff --git a/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp b/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp index e14ce62537..c199159a43 100644 --- a/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Debug/Configuration/PhysXDebugConfiguration.cpp @@ -31,38 +31,39 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("PhysX PVD Settings", "PhysX PVD Settings") + editContext->Class("PhysX PVD Settings", + "Connection configuration settings for the PhysX Visual Debugger (PVD). Requires PhysX Debug Gem.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_transportType, - "PVD Transport Type", "PVD supports writing to a TCP/IP network socket or to a file.") + "PVD Transport Type", "Output PhysX Visual Debugger data to a TCP/IP network socket or to a file.") ->EnumAttribute(Debug::PvdTransportType::Network, "Network") ->EnumAttribute(Debug::PvdTransportType::File, "File") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_host, - "PVD Host", "Host IP address of the PhysX Visual Debugger application") + "PVD Host", "Host IP address of the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_port, - "PVD Port", "Port of the PhysX Visual Debugger application") + "PVD Port", "Port of the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) + ->Attribute(AZ::Edit::Attributes::Min, AZStd::numeric_limits::min()) + ->Attribute(AZ::Edit::Attributes::Max, AZStd::numeric_limits::max()) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_timeoutInMilliseconds, - "PVD Timeout", "Timeout (in milliseconds) used when connecting to the PhysX Visual Debugger application") + "PVD Timeout", "Timeout (in milliseconds) when connecting to the PhysX Visual Debugger server.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsNetworkDebug) ->DataElement(AZ::Edit::UIHandlers::Default, &PvdConfiguration::m_fileName, - "PVD FileName", "Filename to output PhysX Visual Debugger data.") + "PVD FileName", "Output filename for PhysX Visual Debugger data.") ->Attribute(AZ::Edit::Attributes::Visibility, &PvdConfiguration::IsFileDebug) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &PvdConfiguration::m_autoConnectMode, - "PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger " - "(Requires PhysX Debug gem for Editor and Game modes).") + "PVD Auto Connect", "Automatically connect to the PhysX Visual Debugger.") ->EnumAttribute(Debug::PvdAutoConnectMode::Disabled, "Disabled") ->EnumAttribute(Debug::PvdAutoConnectMode::Editor, "Editor") ->EnumAttribute(Debug::PvdAutoConnectMode::Game, "Game") - ->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect, - "PVD Reconnect", "Reconnect (Disconnect and Connect) when switching between game and edit mode " - "(Requires PhysX Debug gem).") + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &PvdConfiguration::m_reconnect, "PVD Reconnect", + "Reconnect (disconnect and connect) to the PhysX Visual Debugger server when switching between game and edit mode.") ; } } @@ -131,7 +132,7 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("Editor Configuration", "Editor settings for PhysX") + editContext->Class("Editor Configuration", "Editor settings for PhysX.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Slider, &DebugDisplayData::m_centerOfMassDebugSize, diff --git a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp index 92952bcdaa..fa71fa0061 100644 --- a/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorBallJointComponent.cpp @@ -33,14 +33,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Ball Joint", "The ball joint supports a cone limiting the maximum rotation around the y and z axes.") + "PhysX Ball Joint", "A dynamic joint constraint with swing rotation limits around the Y and Z axes of the joint.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ball-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "Limitations for the swing (Y and Z axis) about joint") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode") + ->DataElement(0, &EditorBallJointComponent::m_swingLimit, "Swing Limit", "The rotation angle limit around the joint's Y and Z axes.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorBallJointComponent::m_componentModeDelegate, "Component Mode", "Ball Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index f8d0adf156..262e40cb99 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -53,13 +53,15 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { - editContext->Class("EditorProxyShapeConfig", "PhysX Base shape collider") + editContext->Class("EditorProxyShapeConfig", "PhysX Base collider.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", "PhysX mesh collider asset") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_pxAsset, "PhysX Mesh", + "Specifies the PhysX mesh collider asset for this PhysX collider component.") ->Attribute(AZ_CRC_CE("EditButton"), "") ->Attribute(AZ_CRC_CE("EditDescription"), "Open in Scene Settings") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", "Configuration of asset shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyAssetShapeConfig::m_configuration, "Configuration", + "PhysX mesh asset collider configuration.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } @@ -86,7 +88,7 @@ namespace PhysX { editContext->Class( "EditorProxyShapeConfig", "PhysX Base shape collider") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorProxyShapeConfig::m_shapeType, "Shape", "The shape of the collider.") ->EnumAttribute(Physics::ShapeType::Sphere, "Sphere") ->EnumAttribute(Physics::ShapeType::Box, "Box") ->EnumAttribute(Physics::ShapeType::Capsule, "Capsule") @@ -96,20 +98,20 @@ namespace PhysX // potentially be different ComponentModes for different shape types) ->Attribute(AZ::Edit::Attributes::ReadOnly, &AzToolsFramework::ComponentModeFramework::InComponentMode) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_sphere, "Sphere", "Configuration of sphere shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsSphereConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_box, "Box", "Configuration of box shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsBoxConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_capsule, "Capsule", "Configuration of capsule shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsCapsuleConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_physicsAsset, "Asset", "Configuration of asset shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::IsAssetConfig) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorProxyShapeConfig::OnConfigurationChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorProxyShapeConfig::m_subdivisionLevel, "Subdivision level", - "The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling") + "The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.") ->Attribute(AZ::Edit::Attributes::Min, Utils::MinCapsuleSubdivisionLevel) ->Attribute(AZ::Edit::Attributes::Max, Utils::MaxCapsuleSubdivisionLevel) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorProxyShapeConfig::ShowingSubdivisionLevel) @@ -200,7 +202,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Collider", "PhysX shape collider") + "PhysX Collider", "Creates geometry in the PhysX simulation, using either a primitive shape or geometry from an asset.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") @@ -208,17 +210,17 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_configuration, "Collider Configuration", "Configuration of the collider.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_shapeConfiguration, "Shape Configuration", "Configuration of the shape.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorColliderComponent::OnConfigurationChanged) ->Attribute(AZ::Edit::Attributes::RemoveNotify, &EditorColliderComponent::ValidateRigidBodyMeshGeometryType) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_componentModeDelegate, "Component Mode", "Collider Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorColliderComponent::m_colliderDebugDraw, - "Debug draw settings", "Debug draw settings") + "Debug draw settings", "Debug draw settings.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp index 94f57690ba..692671174b 100644 --- a/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorFixedJointComponent.cpp @@ -30,13 +30,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Fixed Joint", "The fixed joint constraints the position and orientation of a body to another.") + "PhysX Fixed Joint", + "A dynamic joint constraint that constrains a rigid body to the joint with no free translation or rotation on any axis.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/fixed-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorFixedJointComponent::m_componentModeDelegate, "Component Mode", "Fixed Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp index 610a0a9b2e..dff1ff86bb 100644 --- a/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorForceRegionComponent.cpp @@ -164,7 +164,7 @@ namespace PhysX { // EditorForceRegionComponent editContext->Class( - "PhysX Force Region", "The force region component is used to apply a physical force on objects within the region") + "PhysX Force Region", "The force region component is used to apply a physical force on objects within the region.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/ForceVolume.svg") @@ -173,9 +173,10 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/force-region/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC("PhysXTriggerService", 0x3a117d7b)) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces", "Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_visibleInEditor, "Visible", "Always show the component in viewport.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_debugForces, "Debug Forces", + "Draws debug arrows when an entity enters a force region. This occurs in gameplay mode to show the force direction on an entity.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorForceRegionComponent::m_forces, "Forces", "Forces in force region.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorForceRegionComponent::OnForcesChanged) ; diff --git a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp index 5537502327..1b575074e2 100644 --- a/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHingeJointComponent.cpp @@ -33,14 +33,14 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Hinge Joint", "The entity constrains two actors in PhysX, keeping the origins and x-axes together, and allows free rotation around this common axis") + "PhysX Hinge Joint", "A dynamic joint that constrains a rigid body with rotation limits around a single axis.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/hinge-joint/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "Limitations for the rotation about hinge axis") - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode") + ->DataElement(0, &EditorHingeJointComponent::m_angularLimit, "Angular Limit", "The rotation angle limit around the joint's axis.") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorHingeJointComponent::m_componentModeDelegate, "Component Mode", "Hinge Joint Component Mode.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ; } diff --git a/Gems/PhysX/Code/Source/EditorJointComponent.cpp b/Gems/PhysX/Code/Source/EditorJointComponent.cpp index 88e192026d..9a24392fd0 100644 --- a/Gems/PhysX/Code/Source/EditorJointComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorJointComponent.cpp @@ -37,11 +37,11 @@ namespace PhysX if (auto* editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Joint", "The joint constrains the position and orientation of a body to another.") + "PhysX Joint", "A dynamic joint that constrains the position and orientation of one rigid body to another.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types") + ->DataElement(0, &EditorJointComponent::m_config, "Standard Joint Parameters", "Joint parameters shared by all joint types.") ; } } diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp index 24b2586c9e..e384f222e8 100644 --- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp @@ -122,38 +122,38 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialLinearVelocity, - "Initial linear velocity", "Initial linear velocity") + "Initial linear velocity", "Linear velocity applied when the rigid body is activated.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSpeedUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_initialAngularVelocity, - "Initial angular velocity", "Initial angular velocity (limited by maximum angular velocity)") + "Initial angular velocity", "Angular velocity applied when the rigid body is activated (limited by maximum angular velocity).") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInitialVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_linearDamping, - "Linear damping", "Linear damping (must be non-negative)") + "Linear damping", "The rate of decay over time for linear velocity even if no forces are acting on the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_angularDamping, - "Angular damping", "Angular damping (must be non-negative)") + "Angular damping", "The rate of decay over time for angular velocity even if no forces are acting on the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetDampingVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_sleepMinEnergy, - "Sleep threshold", "Kinetic energy per unit mass below which body can go to sleep (must be non-negative)") + "Sleep threshold", "The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSleepThresholdUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_startAsleep, - "Start asleep", "The rigid body will be asleep when spawned") + "Start asleep", "When active, the rigid body will be asleep when spawned, and wake when the body is disturbed.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetSleepOptionsVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_interpolateMotion, - "Interpolate motion", "Makes object motion look smoother") + "Interpolate motion", "When active, simulation results are interpolated resulting in smoother motion.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInterpolationVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_gravityEnabled, - "Gravity enabled", "Rigid body will be affected by gravity") + "Gravity enabled", "When active, global gravity affects this rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetGravityVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_kinematic, - "Kinematic", "Rigid body is kinematic") + "Kinematic", "When active, the rigid body is not affected by gravity or other forces and is moved by script.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetKinematicVisibility) // Linear axis locking properties @@ -161,85 +161,90 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearX, "Lock X", - "Lock motion along X direction") + "When active, forces won't create translation on the X axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearY, "Lock Y", - "Lock motion along Y direction") + "When active, forces won't create translation on the Y axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockLinearZ, "Lock Z", - "Lock motion along Z direction") + "When active, forces won't create translation on the Z axis of the rigid body.") // Angular axis locking properties ->ClassElement(AZ::Edit::ClassElements::Group, "Angular Axis Locking") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularX, "Lock X", - "Lock rotation around X direction") + "When active, forces won't create rotation on the X axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularY, "Lock Y", - "Lock rotation around Y direction") + "When active, forces won't create rotation on the Y axis of the rigid body.") ->DataElement( AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_lockAngularZ, "Lock Z", - "Lock rotation around Z direction") + "When active, forces won't create rotation on the Z axis of the rigid body.") ->ClassElement(AZ::Edit::ClassElements::Group, "Continuous Collision Detection") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdEnabled, - "CCD enabled", "Whether continuous collision detection is enabled for this body") + "CCD enabled", "When active, the rigid body has continuous collision detection (CCD). Use this to ensure accurate " + "collision detection, particularly for fast moving rigid bodies. CCD must be activated in the global PhysX preferences.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCCDVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdMinAdvanceCoefficient, - "Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness") + "Min advance coefficient", "Lower values reduce clipping but can affect simulation smoothness.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ->Attribute(AZ::Edit::Attributes::Max, 0.99f) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_ccdFrictionEnabled, - "CCD friction", "Whether friction is applied when CCD collisions are resolved") + "CCD friction", "When active, friction is applied when continuous collision detection (CCD) collisions are resolved.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::IsCCDEnabled) ->ClassElement(AZ::Edit::ClassElements::Group, "") // end previous group by starting new unnamed expanded group ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_maxAngularVelocity, - "Maximum angular velocity", "The PhysX solver will clamp angular velocities with magnitude exceeding this value") + "Maximum angular velocity", "Clamp angular velocities to this maximum value. " + "This prevents rigid bodies from rotating at unrealistic velocities after collisions.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMaxVelocitiesVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit()) // Mass properties ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeCenterOfMass, - "Compute COM", "Whether to automatically compute the center of mass") + "Compute COM", "Compute the center of mass (COM) for this rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_centerOfMassOffset, - "COM offset", "Center of mass offset in local frame") + "COM offset", "Local space offset for the center of mass (COM).") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetCoMVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetLengthUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeMass, - "Compute Mass", "Whether to automatically compute the mass") + "Compute Mass", "When active, the mass of the rigid body is computed based on the volume and density values of its colliders.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &AzPhysics::RigidBodyConfiguration::m_mass, - "Mass", "The mass of the object (must be non-negative, with a value of zero treated as infinite)") + "Mass", "The mass of the rigid body in kilograms. A value of 0 is treated as infinite. " + "The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetMassUnit()) ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetMassVisibility) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_computeInertiaTensor, - "Compute inertia", "Whether to automatically compute the inertia values based on the mass and shape of the rigid body") + "Compute inertia", "When active, inertia is computed based on the mass and shape of the rigid body.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(Editor::InertiaHandler, &AzPhysics::RigidBodyConfiguration::m_inertiaTensor, - "Inertia diagonal", "Diagonal elements of the inertia tensor") + "Inertia diagonal", "Inertia diagonal elements that specify an inertia tensor; determines the " + "torque required to rotate the rigid body on each axis.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaVisibility) ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetInertiaUnit()) ->DataElement(AZ::Edit::UIHandlers::Default, &RigidBodyConfiguration::m_includeAllShapesInMassCalculation, - "Include non-simulated shapes in Mass", "If set, non-simulated shapes will also be included in the center of mass, inertia and mass calculations.") + "Include non-simulated shapes in Mass", + "When active, non-simulated shapes are included in the center of mass, inertia, and mass calculations.") ->Attribute(AZ::Edit::Attributes::Visibility, &AzPhysics::RigidBodyConfiguration::GetInertiaSettingsVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ; @@ -250,7 +255,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorRigidBodyConfiguration::m_centerOfMassDebugDraw, - "Debug draw COM", "Whether to debug draw the center of mass for this body") + "Debug draw COM", "Display the rigid body's center of mass (COM) in the viewport.") ; } } diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 2ea6f4eaf5..832145d016 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -79,7 +79,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Shape Collider", "Creates geometry in the PhysX simulation based on an attached shape component") + "PhysX Shape Collider", "Create a PhysX collider using a shape provided by a Shape component.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCollider.svg") @@ -88,13 +88,14 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/shape-collider/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderConfig, - "Collider configuration", "Configuration of the collider") + "Collider configuration", "Configuration of the collider.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnConfigurationChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_colliderDebugDraw, - "Debug draw settings", "Debug draw settings") + "Debug draw settings", "Debug draw settings.") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count", "Number of angular subdivisions in the PhysX cylinder") + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_subdivisionCount, "Subdivision count", + "Number of angular subdivisions in the PhysX cylinder.") ->Attribute(AZ::Edit::Attributes::Min, Utils::MinFrustumSubdivisions) ->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange) diff --git a/Gems/PhysX/Code/Source/ForceRegion.cpp b/Gems/PhysX/Code/Source/ForceRegion.cpp index 63426d304e..5314f97f9a 100644 --- a/Gems/PhysX/Code/Source/ForceRegion.cpp +++ b/Gems/PhysX/Code/Source/ForceRegion.cpp @@ -62,10 +62,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Force Region", "Applies forces on entities within a region") + "Force Region", "Applies forces on entities within a region.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceRegion::m_forces, "Forces", "Forces acting in the region.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } diff --git a/Gems/PhysX/Code/Source/ForceRegionForces.cpp b/Gems/PhysX/Code/Source/ForceRegionForces.cpp index 202a073640..6ed4c3e93a 100644 --- a/Gems/PhysX/Code/Source/ForceRegionForces.cpp +++ b/Gems/PhysX/Code/Source/ForceRegionForces.cpp @@ -37,13 +37,13 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "World Space Force", "Applies a force in world space") + "World Space Force", "Applies a force in world space.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space") + ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceWorldSpace::m_direction, "Direction", "Direction of the force in world space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceWorldSpace::m_magnitude, "Magnitude", "Magnitude of the force in world space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -109,13 +109,13 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Local Space Force", "Applies a force in the volume's local space") + "Local Space Force", "Applies a force in the volume's local space.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space") + ->DataElement(AZ::Edit::UIHandlers::Vector3, &ForceLocalSpace::m_direction, "Direction", "Direction of the force in local space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLocalSpace::m_magnitude, "Magnitude", "Magnitude of the force in local space.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -179,10 +179,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Point Force", "Applies a force relative to the center of the volume") + "Point Force", "Applies a force directed towards or away from the center of the volume.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForcePoint::m_magnitude, "Magnitude", "Magnitude of the point force.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -242,19 +242,24 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Spline Follow Force", "Applies a force to make objects follow a spline at a given speed") + "Spline Follow Force", "Applies a force to make objects follow a spline at a given speed.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio", "Amount of damping applied to an entity that is moving towards a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_dampingRatio, "Damping Ratio", + "Values below 1 cause the entity to approach the spline faster but lead to overshooting and oscillation, " + "while higher values will cause it to approach more slowly but more smoothly.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDampingRatio) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency", "Frequency at which an entity moves towards a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_frequency, "Frequency", + "Affects how quickly the entity approaches the spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinFrequency) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxFrequency) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed", "Speed at which entities in the force region move along a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_targetSpeed, "Target Speed", + "Speed at which entities in the force region move along a spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionMinValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead", "Distance at which entities look ahead in their path to reach a point on a spline") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSplineFollow::m_lookAhead, "Lookahead", + "Distance at which entities look ahead in their path to reach a point on a spline.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxValue) ; @@ -393,10 +398,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Simple Drag Force", "Simulates a drag force on entities") + "Simple Drag Force", "Simulates a drag force on entities.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceSimpleDrag::m_volumeDensity, "Region Density", "Density of the region.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDensity) ; @@ -463,10 +468,10 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "Linear Damping Force", "Applies an opposite force to the entity's velocity") + "Linear Damping Force", "Applies an opposite force to the entity's velocity.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force") + ->DataElement(AZ::Edit::UIHandlers::Default, &ForceLinearDamping::m_damping, "Damping", "Amount of damping applied to an opposite force.") ->Attribute(AZ::Edit::Attributes::Min, s_forceRegionZeroValue) ->Attribute(AZ::Edit::Attributes::Max, s_forceRegionMaxDamping) ; diff --git a/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp b/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp index 530bd03732..ae74859528 100644 --- a/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp +++ b/Gems/PhysX/Code/Source/Joint/Configuration/PhysXJointConfiguration.cpp @@ -59,22 +59,22 @@ namespace PhysX ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitY, "Swing limit Y", - "Maximum angle from the Y axis of the joint frame") + "The rotation angle limit around the joint's Y axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitZ, "Swing limit Z", - "Maximum angle from the Z axis of the joint frame") + "The rotation angle limit around the joint's Z axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitLower, "Twist lower limit", - "Lower limit for rotation about the X axis of the joint frame") + "The lower rotation angle limit around the joint's X axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, -180.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitUpper, "Twist upper limit", - "Upper limit for rotation about the X axis of the joint frame") + "The upper rotation angle limit around the joint's X axis.") ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") ->Attribute(AZ::Edit::Attributes::Min, -180.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp index ed9030ac4f..6af08cfaeb 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterController.cpp @@ -42,16 +42,16 @@ namespace PhysX "PhysX Character Controller Configuration", "PhysX Character Controller Configuration") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &CharacterControllerConfiguration::m_slopeBehaviour, - "Slope Behaviour", "Behaviour of the controller on surfaces above the maximum slope") + "Slope Behavior", "Behavior of the controller on surfaces that exceed the Maximum Slope Angle.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->EnumAttribute(SlopeBehaviour::PreventClimbing, "Prevent Climbing") ->EnumAttribute(SlopeBehaviour::ForceSliding, "Force Sliding") ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_contactOffset, - "Contact Offset", "Extra distance outside the controller used for smoother contact resolution") + "Contact Offset", "Distance from the controller boundary where contact with surfaces can be resolved.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterControllerConfiguration::m_scaleCoefficient, - "Scale", "Scalar coefficient used to scale the controller, usually slightly smaller than 1") + "Scale", "Scales the controller. Usually less than 1.0 to ensure visual contact between the character and surface.") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::Step, 0.01f) ; diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp index 4a4f12558d..e86b81359c 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterGameplayComponent.cpp @@ -33,7 +33,7 @@ namespace PhysX "PhysX Character Gameplay Configuration", "PhysX Character Gameplay Configuration") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterGameplayConfiguration::m_gravityMultiplier, - "Gravity Multiplier", "Multiplier to be combined with the world gravity value for applying character gravity") + "Gravity Multiplier", "Multiplier for global gravity value that applies only to this character entity.") ->Attribute(AZ::Edit::Attributes::Step, 0.1f) ; } diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp index 4e24067dbf..114f9bc2f7 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterControllerComponent.cpp @@ -36,18 +36,18 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape") + "EditorCharacterControllerProxyShapeConfig", "PhysX character controller shape.") ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorCharacterControllerProxyShapeConfig::m_shapeType, "Shape", - "The shape associated with the character controller") + "The shape of the character controller.") ->EnumAttribute(Physics::ShapeType::Capsule, "Capsule") ->EnumAttribute(Physics::ShapeType::Box, "Box") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_box, "Box", - "Configuration of box shape") + "Configuration of box shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsBoxConfig) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerProxyShapeConfig::m_capsule, "Capsule", - "Configuration of capsule shape") + "Configuration of capsule shape.") ->Attribute(AZ::Edit::Attributes::Visibility, &EditorCharacterControllerProxyShapeConfig::IsCapsuleConfig) ; } @@ -93,7 +93,8 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Character Controller", "PhysX Character Controller") + "PhysX Character Controller", + "Provides basic character interactions with the physical world, such as preventing movement through other PhysX bodies.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") @@ -101,12 +102,12 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-controller/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_configuration, - "Configuration", "Configuration for the character controller") + "Configuration", "Configuration for the character controller.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnControllerConfigChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterControllerComponent::m_proxyShapeConfiguration, - "Shape Configuration", "The configuration for the shape associated with the character controller") + "Shape Configuration", "The configuration for the shape associated with the character controller.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCharacterControllerComponent::OnShapeConfigChanged) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp index 81d158d81c..de4deb442f 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/EditorCharacterGameplayComponent.cpp @@ -43,7 +43,7 @@ namespace PhysX if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( - "PhysX Character Gameplay", "PhysX Character Gameplay") + "PhysX Character Gameplay", "An example implementation of character physics behavior such as gravity.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXCharacter.svg") @@ -51,7 +51,7 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/character-gameplay/") ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCharacterGameplayComponent::m_gameplayConfig, - "Gameplay Configuration", "Gameplay Configuration") + "Gameplay Configuration", "Gameplay Configuration.") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp index 6fa3bdbffd..57972fea3e 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp @@ -82,7 +82,7 @@ namespace PhysX if (editContext) { editContext->Class( - "PhysX Ragdoll", "Provides simulation of characters in PhysX.") + "PhysX Ragdoll", "Creates a PhysX ragdoll simulation for an animation actor.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXRagdoll.svg") @@ -91,26 +91,28 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/ragdoll/") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_positionIterations, "Position Iteration Count", - "A higher iteration count generally improves fidelity at the cost of performance, but note that very high " - "values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints") + "The frequency at which ragdoll collider positions are resolved. Higher values can increase fidelity but decrease " + "performance. Very high values might introduce instability.") ->Attribute(AZ::Edit::Attributes::Min, 1) ->Attribute(AZ::Edit::Attributes::Max, 255) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_velocityIterations, "Velocity Iteration Count", - "A higher iteration count generally improves fidelity at the cost of performance, but note that very high " - "values may lead to severe instability if ragdoll colliders interfere with satisfying joint constraints") + "The frequency at which ragdoll collider velocities are resolved. Higher values can increase fidelity but decrease " + "performance. Very high values might introduce instability.") ->Attribute(AZ::Edit::Attributes::Min, 1) ->Attribute(AZ::Edit::Attributes::Max, 255) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_enableJointProjection, - "Enable Joint Projection", "Whether to use joint projection to preserve joint constraints " - "in demanding situations at the expense of potentially reducing physical correctness") + "Enable Joint Projection", "When active, preserves joint constraints in volatile simulations. " + "Might not be physically correct in all simulations.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionLinearTolerance, - "Joint Projection Linear Tolerance", "Linear joint error above which projection will be applied") + "Joint Projection Linear Tolerance", + "Maximum linear joint error. Projection is applied to linear joint errors above this value.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 1e-3f) ->Attribute(AZ::Edit::Attributes::Visibility, &RagdollComponent::IsJointProjectionVisible) ->DataElement(AZ::Edit::UIHandlers::Default, &RagdollComponent::m_jointProjectionAngularToleranceDegrees, - "Joint Projection Angular Tolerance", "Angular joint error (in degrees) above which projection will be applied") + "Joint Projection Angular Tolerance", + "Maximum angular joint error. Projection is applied to angular joint errors above this value.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.1f) ->Attribute(AZ::Edit::Attributes::Suffix, " degrees") diff --git a/Gems/PhysX/Code/Source/SystemComponent.cpp b/Gems/PhysX/Code/Source/SystemComponent.cpp index f56ad43079..2f4d082ccb 100644 --- a/Gems/PhysX/Code/Source/SystemComponent.cpp +++ b/Gems/PhysX/Code/Source/SystemComponent.cpp @@ -101,7 +101,7 @@ namespace PhysX if (AZ::EditContext* editContext = serialize->GetEditContext()) { - editContext->Class("PhysX", "Global PhysX physics configuration") + editContext->Class("PhysX", "Global PhysX physics configuration.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "PhysX") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) diff --git a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp index 878ede5e68..a11f2c9905 100644 --- a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp +++ b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxManipulatorBounds.cpp @@ -48,10 +48,10 @@ namespace WhiteBox float time; AZ::Vector3 normal; const float rayLength = 1000.0f; - const int intersected = AZ::Intersect::IntersectSegmentTriangleCCW( + const bool intersected = AZ::Intersect::IntersectSegmentTriangleCCW( rayOrigin, rayOrigin + rayDirection * rayLength, p0, p1, p2, normal, time); - if (intersected != 0) + if (intersected) { rayIntersectionDistance = time * rayLength; intersectedTriangleIndex = triangleIndex / 3;