diff --git a/Assets/Editor/Icons/Components/NonUniformScale.svg b/Assets/Editor/Icons/Components/NonUniformScale.svg
new file mode 100644
index 0000000000..f377232d62
--- /dev/null
+++ b/Assets/Editor/Icons/Components/NonUniformScale.svg
@@ -0,0 +1,27 @@
+
+
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
index c8e66740e4..62a6ed7f8c 100644
--- a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
@@ -53,5 +53,6 @@ set(GEM_DEPENDENCIES
Gem::ImguiAtom
Gem::Atom_AtomBridge
Gem::AtomFont
+ Gem::NvCloth
Gem::Blast
)
diff --git a/AutomatedTesting/Gem/Code/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
index 8c5da63f42..a6bbeee350 100644
--- a/AutomatedTesting/Gem/Code/tool_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
@@ -68,5 +68,6 @@ set(GEM_DEPENDENCIES
Gem::ImguiAtom
Gem::AtomFont
Gem::AtomToolsFramework.Editor
+ Gem::NvCloth.Editor
Gem::Blast.Editor
)
diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
index 31afab87ed..3124f1048a 100644
--- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
@@ -107,20 +107,21 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
endif()
## NvCloth ##
-# [TODO LYN-1928] Enable when AutomatedTesting runs with Atom
-#if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
-# ly_add_pytest(
-# NAME AutomatedTesting::NvClothTests
-# TEST_SUITE main
-# TEST_SERIAL
-# PATH ${CMAKE_CURRENT_LIST_DIR}/NvCloth/TestSuite_Active.py
-# TIMEOUT 1500
-# RUNTIME_DEPENDENCIES
-# Legacy::Editor
-# AZ::AssetProcessor
-# AutomatedTesting.Assets
-# )
-#endif()
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+ ly_add_pytest(
+ NAME AutomatedTesting::NvClothTests_Main
+ TEST_SUITE main
+ TEST_SERIAL
+ PATH ${CMAKE_CURRENT_LIST_DIR}/NvCloth/TestSuite_Active.py
+ TIMEOUT 1500
+ RUNTIME_DEPENDENCIES
+ Legacy::Editor
+ AZ::AssetProcessor
+ AutomatedTesting.Assets
+ COMPONENT
+ NvCloth
+ )
+endif()
## Editor Python Bindings ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py
index 2677ba5605..625c9772bd 100755
--- a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py
+++ b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh.py
@@ -20,7 +20,7 @@ class Tests:
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
-def run():
+def C18977329_NvCloth_AddClothSimulationToMesh():
"""
Summary:
Load level with Entity having Mesh and Cloth components already setup. Verify that editor remains stable in Game mode.
@@ -89,4 +89,7 @@ def run():
helper.close_editor()
if __name__ == "__main__":
- run()
+ import ImportPathHelper as imports
+ imports.init()
+ from editor_python_test_tools.utils import Report
+ Report.start_test(C18977329_NvCloth_AddClothSimulationToMesh)
diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py
index 2d4fa4e325..9b3135cd2b 100755
--- a/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py
+++ b/AutomatedTesting/Gem/PythonTests/NvCloth/C18977330_NvCloth_AddClothSimulationToActor.py
@@ -20,7 +20,7 @@ class Tests:
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
-def run():
+def C18977330_NvCloth_AddClothSimulationToActor():
"""
Summary:
Load level with Entity having Actor and Cloth components already setup. Verify that editor remains stable in Game mode.
@@ -89,4 +89,7 @@ def run():
helper.close_editor()
if __name__ == "__main__":
- run()
+ import ImportPathHelper as imports
+ imports.init()
+ from editor_python_test_tools.utils import Report
+ Report.start_test(C18977330_NvCloth_AddClothSimulationToActor)
diff --git a/AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py b/AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py
index 162c54afc8..86bfc48636 100755
--- a/AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py
+++ b/AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py
@@ -21,14 +21,15 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesti
from base import TestAutomationBase
-@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
+ @pytest.mark.xfail(reason="Running with atom null renderer is causing this test to fail")
def test_C18977329_NvCloth_AddClothSimulationToMesh(self, request, workspace, editor, launcher_platform):
from . import C18977329_NvCloth_AddClothSimulationToMesh as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(reason="Running with atom null renderer is causing this test to fail")
def test_C18977330_NvCloth_AddClothSimulationToActor(self, request, workspace, editor, launcher_platform):
from . import C18977330_NvCloth_AddClothSimulationToActor as test_module
self._run_test(request, workspace, editor, test_module)
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py
index aafa2ff9b7..f84e367d1d 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py
+++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py
@@ -27,6 +27,155 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
@pytest.mark.parametrize("level", ["auto_test"])
class TestAtomEditorComponentsMain(object):
- # It requires at least one test
- def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
- pass
+ @pytest.mark.test_case_id(
+ "C32078130", # Display Mapper
+ "C32078129", # Light
+ "C32078131", # Radius Weight Modifier
+ "C32078127", # PostFX Layer
+ "C32078125", # Physical Sky
+ "C32078115", # Global Skylight (IBL)
+ "C32078121", # Exposure Control
+ "C32078120", # Directional Light
+ "C32078119", # DepthOfField
+ "C32078118") # Decal (Atom)
+ def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
+ cfg_args = [level]
+
+ expected_lines = [
+ # Decal (Atom) Component
+ "Decal (Atom) Entity successfully created",
+ "Decal (Atom)_test: Component added to the entity: True",
+ "Decal (Atom)_test: Component removed after UNDO: True",
+ "Decal (Atom)_test: Component added after REDO: True",
+ "Decal (Atom)_test: Entered game mode: True",
+ "Decal (Atom)_test: Exit game mode: True",
+ "Decal (Atom) Controller|Configuration|Material: SUCCESS",
+ "Decal (Atom)_test: Entity is hidden: True",
+ "Decal (Atom)_test: Entity is shown: True",
+ "Decal (Atom)_test: Entity deleted: True",
+ "Decal (Atom)_test: UNDO entity deletion works: True",
+ "Decal (Atom)_test: REDO entity deletion works: True",
+ # DepthOfField Component
+ "DepthOfField Entity successfully created",
+ "DepthOfField_test: Component added to the entity: True",
+ "DepthOfField_test: Component removed after UNDO: True",
+ "DepthOfField_test: Component added after REDO: True",
+ "DepthOfField_test: Entered game mode: True",
+ "DepthOfField_test: Exit game mode: True",
+ "DepthOfField_test: Entity disabled initially: True",
+ "DepthOfField_test: Entity enabled after adding required components: True",
+ "DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
+ "DepthOfField_test: Entity is hidden: True",
+ "DepthOfField_test: Entity is shown: True",
+ "DepthOfField_test: Entity deleted: True",
+ "DepthOfField_test: UNDO entity deletion works: True",
+ "DepthOfField_test: REDO entity deletion works: True",
+ # Exposure Control Component
+ "Exposure Control Entity successfully created",
+ "Exposure Control_test: Component added to the entity: True",
+ "Exposure Control_test: Component removed after UNDO: True",
+ "Exposure Control_test: Component added after REDO: True",
+ "Exposure Control_test: Entered game mode: True",
+ "Exposure Control_test: Exit game mode: True",
+ "Exposure Control_test: Entity disabled initially: True",
+ "Exposure Control_test: Entity enabled after adding required components: True",
+ "Exposure Control_test: Entity is hidden: True",
+ "Exposure Control_test: Entity is shown: True",
+ "Exposure Control_test: Entity deleted: True",
+ "Exposure Control_test: UNDO entity deletion works: True",
+ "Exposure Control_test: REDO entity deletion works: True",
+ # Global Skylight (IBL) Component
+ "Global Skylight (IBL) Entity successfully created",
+ "Global Skylight (IBL)_test: Component added to the entity: True",
+ "Global Skylight (IBL)_test: Component removed after UNDO: True",
+ "Global Skylight (IBL)_test: Component added after REDO: True",
+ "Global Skylight (IBL)_test: Entered game mode: True",
+ "Global Skylight (IBL)_test: Exit game mode: True",
+ "Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
+ "Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
+ "Global Skylight (IBL)_test: Entity is hidden: True",
+ "Global Skylight (IBL)_test: Entity is shown: True",
+ "Global Skylight (IBL)_test: Entity deleted: True",
+ "Global Skylight (IBL)_test: UNDO entity deletion works: True",
+ "Global Skylight (IBL)_test: REDO entity deletion works: True",
+ # Physical Sky Component
+ "Physical Sky Entity successfully created",
+ "Physical Sky component was added to entity",
+ "Entity has a Physical Sky component",
+ "Physical Sky_test: Component added to the entity: True",
+ "Physical Sky_test: Component removed after UNDO: True",
+ "Physical Sky_test: Component added after REDO: True",
+ "Physical Sky_test: Entered game mode: True",
+ "Physical Sky_test: Exit game mode: True",
+ "Physical Sky_test: Entity is hidden: True",
+ "Physical Sky_test: Entity is shown: True",
+ "Physical Sky_test: Entity deleted: True",
+ "Physical Sky_test: UNDO entity deletion works: True",
+ "Physical Sky_test: REDO entity deletion works: True",
+ # PostFX Layer Component
+ "PostFX Layer Entity successfully created",
+ "PostFX Layer_test: Component added to the entity: True",
+ "PostFX Layer_test: Component removed after UNDO: True",
+ "PostFX Layer_test: Component added after REDO: True",
+ "PostFX Layer_test: Entered game mode: True",
+ "PostFX Layer_test: Exit game mode: True",
+ "PostFX Layer_test: Entity is hidden: True",
+ "PostFX Layer_test: Entity is shown: True",
+ "PostFX Layer_test: Entity deleted: True",
+ "PostFX Layer_test: UNDO entity deletion works: True",
+ "PostFX Layer_test: REDO entity deletion works: True",
+ # Radius Weight Modifier Component
+ "Radius Weight Modifier Entity successfully created",
+ "Radius Weight Modifier_test: Component added to the entity: True",
+ "Radius Weight Modifier_test: Component removed after UNDO: True",
+ "Radius Weight Modifier_test: Component added after REDO: True",
+ "Radius Weight Modifier_test: Entered game mode: True",
+ "Radius Weight Modifier_test: Exit game mode: True",
+ "Radius Weight Modifier_test: Entity is hidden: True",
+ "Radius Weight Modifier_test: Entity is shown: True",
+ "Radius Weight Modifier_test: Entity deleted: True",
+ "Radius Weight Modifier_test: UNDO entity deletion works: True",
+ "Radius Weight Modifier_test: REDO entity deletion works: True",
+ # Light Component
+ "Light Entity successfully created",
+ "Light_test: Component added to the entity: True",
+ "Light_test: Component removed after UNDO: True",
+ "Light_test: Component added after REDO: True",
+ "Light_test: Entered game mode: True",
+ "Light_test: Exit game mode: True",
+ "Light_test: Entity is hidden: True",
+ "Light_test: Entity is shown: True",
+ "Light_test: Entity deleted: True",
+ "Light_test: UNDO entity deletion works: True",
+ "Light_test: REDO entity deletion works: True",
+ # Display Mapper Component
+ "Display Mapper Entity successfully created",
+ "Display Mapper_test: Component added to the entity: True",
+ "Display Mapper_test: Component removed after UNDO: True",
+ "Display Mapper_test: Component added after REDO: True",
+ "Display Mapper_test: Entered game mode: True",
+ "Display Mapper_test: Exit game mode: True",
+ "Display Mapper_test: Entity is hidden: True",
+ "Display Mapper_test: Entity is shown: True",
+ "Display Mapper_test: Entity deleted: True",
+ "Display Mapper_test: UNDO entity deletion works: True",
+ "Display Mapper_test: REDO entity deletion works: True",
+ ]
+
+ unexpected_lines = [
+ "failed to open",
+ "Traceback (most recent call last):",
+ ]
+
+ hydra.launch_and_validate_results(
+ request,
+ TEST_DIRECTORY,
+ editor,
+ "hydra_AtomEditorComponents_AddedToEntity.py",
+ timeout=EDITOR_TIMEOUT,
+ expected_lines=expected_lines,
+ unexpected_lines=unexpected_lines,
+ halt_on_unexpected=True,
+ null_renderer=True,
+ cfg_args=cfg_args,
+ )
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py
index 8ca5b5aa31..0fb873e677 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py
+++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py
@@ -19,170 +19,6 @@ import pytest
@pytest.mark.parametrize("level", ["auto_test"])
class TestAtomEditorComponentsSandbox(object):
- @pytest.mark.test_case_id(
- "C32078117", # Area Light
- "C32078130", # Display Mapper
- "C32078129", # Light
- "C32078131", # Radius Weight Modifier
- "C32078127", # PostFX Layer
- "C32078126", # Point Light
- "C32078125", # Physical Sky
- "C32078115", # Global Skylight (IBL)
- "C32078121", # Exposure Control
- "C32078120", # Directional Light
- "C32078119", # DepthOfField
- "C32078118") # Decal
- def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
- cfg_args = [level]
-
- expected_lines = [
- # Decal Component
- "Decal (Atom) Entity successfully created",
- "Decal (Atom)_test: Component added to the entity: True",
- "Decal (Atom)_test: Component removed after UNDO: True",
- "Decal (Atom)_test: Component added after REDO: True",
- "Decal (Atom)_test: Entered game mode: True",
- "Decal (Atom)_test: Exit game mode: True",
- "Decal (Atom) Controller|Configuration|Material: SUCCESS",
- "Decal (Atom)_test: Entity is hidden: True",
- "Decal (Atom)_test: Entity is shown: True",
- "Decal (Atom)_test: Entity deleted: True",
- "Decal (Atom)_test: UNDO entity deletion works: True",
- "Decal (Atom)_test: REDO entity deletion works: True",
- # DepthOfField Component
- "DepthOfField Entity successfully created",
- "DepthOfField_test: Component added to the entity: True",
- "DepthOfField_test: Component removed after UNDO: True",
- "DepthOfField_test: Component added after REDO: True",
- "DepthOfField_test: Entered game mode: True",
- "DepthOfField_test: Exit game mode: True",
- "DepthOfField_test: Entity disabled initially: True",
- "DepthOfField_test: Entity enabled after adding required components: True",
- "DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
- "DepthOfField_test: Entity is hidden: True",
- "DepthOfField_test: Entity is shown: True",
- "DepthOfField_test: Entity deleted: True",
- "DepthOfField_test: UNDO entity deletion works: True",
- "DepthOfField_test: REDO entity deletion works: True",
- # Directional Light Component
- "Directional Light Entity successfully created",
- "Directional Light_test: Component added to the entity: True",
- "Directional Light_test: Component removed after UNDO: True",
- "Directional Light_test: Component added after REDO: True",
- "Directional Light_test: Entered game mode: True",
- "Directional Light_test: Exit game mode: True",
- "Directional Light Controller|Configuration|Shadow|Camera: SUCCESS",
- "Directional Light_test: Entity is hidden: True",
- "Directional Light_test: Entity is shown: True",
- "Directional Light_test: Entity deleted: True",
- "Directional Light_test: UNDO entity deletion works: True",
- "Directional Light_test: REDO entity deletion works: True",
- # Exposure Control Component
- "Exposure Control Entity successfully created",
- "Exposure Control_test: Component added to the entity: True",
- "Exposure Control_test: Component removed after UNDO: True",
- "Exposure Control_test: Component added after REDO: True",
- "Exposure Control_test: Entered game mode: True",
- "Exposure Control_test: Exit game mode: True",
- "Exposure Control_test: Entity disabled initially: True",
- "Exposure Control_test: Entity enabled after adding required components: True",
- "Exposure Control_test: Entity is hidden: True",
- "Exposure Control_test: Entity is shown: True",
- "Exposure Control_test: Entity deleted: True",
- "Exposure Control_test: UNDO entity deletion works: True",
- "Exposure Control_test: REDO entity deletion works: True",
- # Global Skylight (IBL) Component
- "Global Skylight (IBL) Entity successfully created",
- "Global Skylight (IBL)_test: Component added to the entity: True",
- "Global Skylight (IBL)_test: Component removed after UNDO: True",
- "Global Skylight (IBL)_test: Component added after REDO: True",
- "Global Skylight (IBL)_test: Entered game mode: True",
- "Global Skylight (IBL)_test: Exit game mode: True",
- "Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
- "Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
- "Global Skylight (IBL)_test: Entity is hidden: True",
- "Global Skylight (IBL)_test: Entity is shown: True",
- "Global Skylight (IBL)_test: Entity deleted: True",
- "Global Skylight (IBL)_test: UNDO entity deletion works: True",
- "Global Skylight (IBL)_test: REDO entity deletion works: True",
- # Physical Sky Component
- "Physical Sky Entity successfully created",
- "Physical Sky component was added to entity",
- "Entity has a Physical Sky component",
- "Physical Sky_test: Component added to the entity: True",
- "Physical Sky_test: Component removed after UNDO: True",
- "Physical Sky_test: Component added after REDO: True",
- "Physical Sky_test: Entered game mode: True",
- "Physical Sky_test: Exit game mode: True",
- "Physical Sky_test: Entity is hidden: True",
- "Physical Sky_test: Entity is shown: True",
- "Physical Sky_test: Entity deleted: True",
- "Physical Sky_test: UNDO entity deletion works: True",
- "Physical Sky_test: REDO entity deletion works: True",
- # PostFX Layer Component
- "PostFX Layer Entity successfully created",
- "PostFX Layer_test: Component added to the entity: True",
- "PostFX Layer_test: Component removed after UNDO: True",
- "PostFX Layer_test: Component added after REDO: True",
- "PostFX Layer_test: Entered game mode: True",
- "PostFX Layer_test: Exit game mode: True",
- "PostFX Layer_test: Entity is hidden: True",
- "PostFX Layer_test: Entity is shown: True",
- "PostFX Layer_test: Entity deleted: True",
- "PostFX Layer_test: UNDO entity deletion works: True",
- "PostFX Layer_test: REDO entity deletion works: True",
- # Radius Weight Modifier Component
- "Radius Weight Modifier Entity successfully created",
- "Radius Weight Modifier_test: Component added to the entity: True",
- "Radius Weight Modifier_test: Component removed after UNDO: True",
- "Radius Weight Modifier_test: Component added after REDO: True",
- "Radius Weight Modifier_test: Entered game mode: True",
- "Radius Weight Modifier_test: Exit game mode: True",
- "Radius Weight Modifier_test: Entity is hidden: True",
- "Radius Weight Modifier_test: Entity is shown: True",
- "Radius Weight Modifier_test: Entity deleted: True",
- "Radius Weight Modifier_test: UNDO entity deletion works: True",
- "Radius Weight Modifier_test: REDO entity deletion works: True",
- # Light Component
- "Light Entity successfully created",
- "Light_test: Component added to the entity: True",
- "Light_test: Component removed after UNDO: True",
- "Light_test: Component added after REDO: True",
- "Light_test: Entered game mode: True",
- "Light_test: Exit game mode: True",
- "Light_test: Entity is hidden: True",
- "Light_test: Entity is shown: True",
- "Light_test: Entity deleted: True",
- "Light_test: UNDO entity deletion works: True",
- "Light_test: REDO entity deletion works: True",
- # Display Mapper Component
- "Display Mapper Entity successfully created",
- "Display Mapper_test: Component added to the entity: True",
- "Display Mapper_test: Component removed after UNDO: True",
- "Display Mapper_test: Component added after REDO: True",
- "Display Mapper_test: Entered game mode: True",
- "Display Mapper_test: Exit game mode: True",
- "Display Mapper_test: Entity is hidden: True",
- "Display Mapper_test: Entity is shown: True",
- "Display Mapper_test: Entity deleted: True",
- "Display Mapper_test: UNDO entity deletion works: True",
- "Display Mapper_test: REDO entity deletion works: True",
- ]
-
- unexpected_lines = [
- "failed to open",
- "Traceback (most recent call last):",
- ]
-
- hydra.launch_and_validate_results(
- request,
- TEST_DIRECTORY,
- editor,
- "hydra_AtomEditorComponents_AddedToEntity.py",
- timeout=EDITOR_TIMEOUT,
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- halt_on_unexpected=True,
- null_renderer=True,
- cfg_args=cfg_args,
- )
+ # It requires at least one test
+ def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
+ pass
diff --git a/AutomatedTesting/Gem/PythonTests/physics/C14861501_PhysXCollider_RenderMeshAutoAssigned.py b/AutomatedTesting/Gem/PythonTests/physics/C14861501_PhysXCollider_RenderMeshAutoAssigned.py
index e415687001..bc7b1b5e00 100755
--- a/AutomatedTesting/Gem/PythonTests/physics/C14861501_PhysXCollider_RenderMeshAutoAssigned.py
+++ b/AutomatedTesting/Gem/PythonTests/physics/C14861501_PhysXCollider_RenderMeshAutoAssigned.py
@@ -98,5 +98,5 @@ if __name__ == "__main__":
import ImportPathHelper as imports
imports.init()
- from utils import Report
+ from editor_python_test_tools.utils import Report
Report.start_test(C14861501_PhysXCollider_RenderMeshAutoAssigned)
diff --git a/AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py b/AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py
index d65e9050bd..57cdc8f9c5 100755
--- a/AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py
+++ b/AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py
@@ -114,5 +114,5 @@ if __name__ == "__main__":
import ImportPathHelper as imports
imports.init()
- from utils import Report
+ from editor_python_test_tools.utils import Report
Report.start_test(C4044695_PhysXCollider_AddMultipleSurfaceFbx)
diff --git a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py
index 3bbfe64e38..2b82c3e596 100755
--- a/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py
+++ b/AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py
@@ -429,6 +429,8 @@ class TestAutomation(TestAutomationBase):
from . import C4976236_AddPhysxColliderComponent as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(
+ reason="This will fail due to this issue ATOM-15487.")
def test_C14861502_PhysXCollider_AssetAutoAssigned(self, request, workspace, editor, launcher_platform):
from . import C14861502_PhysXCollider_AssetAutoAssigned as test_module
self._run_test(request, workspace, editor, test_module)
diff --git a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly
index 17fee158d8..1afbf787db 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly
+++ b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:a2a3360287a4711882c4254d64ca2ba70cd743012a7d38ca29aa2a57f151efaa
-size 6661
+oid sha256:e15d484113e8151072b410924747a8ad304f6f12457fad577308c0491693ab34
+size 5472
diff --git a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml
index 6c8b361e57..9775a35c53 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml
+++ b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak
index e80d5ca1d9..08a775b6c8 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak
+++ b/AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:cd8105f020151e65093988dfb09ab42ff8d33ef5b97c61fbe0011384870aadf8
-size 39238
+oid sha256:64de37c805b0be77cdb7a85b5406af58b7f845e7d97fec1721ac5d789bb641db
+size 38856
diff --git a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly
index 031989ee11..385027c479 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly
+++ b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f53fb5e096ff562e9f0f12856ce387891596776d086f49c7ed3a59dcd0a0c11a
-size 6535
+oid sha256:7b595323d4d51211463dea0338abb6ce2a4a0a8d41efb12ac3c9dccd1f972171
+size 5504
diff --git a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml
index 290a28f223..7ccc1d51eb 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml
+++ b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak
index fb91adeba5..12ce03fa87 100644
--- a/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak
+++ b/AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:87fbd9fda267daa505f11276b64f47c26115bee9e6d14f2a6f5a1cf1e1234218
-size 39179
+oid sha256:617c455668fc41cb7fd69de690e4aa3c80f2cb36deaa371902b79de18fcd1cb2
+size 39233
diff --git a/Code/CryEngine/CryCommon/WinBase.cpp b/Code/CryEngine/CryCommon/WinBase.cpp
index d48a3327a7..e6ea1cd4a8 100644
--- a/Code/CryEngine/CryCommon/WinBase.cpp
+++ b/Code/CryEngine/CryCommon/WinBase.cpp
@@ -77,7 +77,7 @@ unsigned int g_EnableMultipleAssert = 0;//set to something else than 0 if to ena
#endif
#if defined(APPLE)
- #include "../CrySystem/SystemUtilsApple.h"
+ #include
#endif
#include "StringUtils.h"
diff --git a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp
index d31f122d9b..8818dfa0d9 100644
--- a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp
+++ b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp
@@ -108,10 +108,11 @@ bool CLevelInfo::ReadInfo()
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
+ // Set up a default game type for legacy code.
+ m_defaultGameTypeName = "Mission0";
+
if (usePrefabSystemForLevels)
{
- // Set up a default game type for legacy code.
- m_defaultGameTypeName = "Mission0";
return true;
}
diff --git a/Code/CryEngine/CrySystem/Log.cpp b/Code/CryEngine/CrySystem/Log.cpp
index cdf145e4be..62cf29fef9 100644
--- a/Code/CryEngine/CrySystem/Log.cpp
+++ b/Code/CryEngine/CrySystem/Log.cpp
@@ -51,7 +51,7 @@
#define LOG_BACKUP_PATH "@log@/LogBackups"
#if defined(IOS)
-#include "SystemUtilsApple.h"
+#include
#endif
//////////////////////////////////////////////////////////////////////
diff --git a/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp b/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp
index 1f3275f1c6..dc0a28490d 100644
--- a/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp
+++ b/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp
@@ -15,7 +15,7 @@
#include
#include "MobileDetectSpec.h"
-#include "SystemUtilsApple.h"
+#include
namespace MobileSysInspect
{
diff --git a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake b/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake
index 9c26988e94..4d5680a30d 100644
--- a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake
+++ b/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake
@@ -8,8 +8,3 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
-
-set(FILES
- ../../SystemUtilsApple.h
- ../../SystemUtilsApple.mm
-)
diff --git a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake b/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake
index a5d743e6d7..bbe61fb488 100644
--- a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake
+++ b/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake
@@ -13,8 +13,6 @@ set(FILES
../../MobileDetectSpec_Ios.cpp
../../MobileDetectSpec.cpp
../../MobileDetectSpec.h
- ../../SystemUtilsApple.h
- ../../SystemUtilsApple.mm
)
diff --git a/Code/CryEngine/CrySystem/SystemWin32.cpp b/Code/CryEngine/CrySystem/SystemWin32.cpp
index ce352966ac..b47519eb03 100644
--- a/Code/CryEngine/CrySystem/SystemWin32.cpp
+++ b/Code/CryEngine/CrySystem/SystemWin32.cpp
@@ -66,7 +66,7 @@ __pragma(comment(lib, "Winmm.lib"))
#endif
#if defined(APPLE)
-#include "SystemUtilsApple.h"
+#include
#endif
diff --git a/Code/CryEngine/CrySystem/crysystem_mac_files.cmake b/Code/CryEngine/CrySystem/crysystem_mac_files.cmake
index 7e539e6825..f5b9ea77a2 100644
--- a/Code/CryEngine/CrySystem/crysystem_mac_files.cmake
+++ b/Code/CryEngine/CrySystem/crysystem_mac_files.cmake
@@ -9,7 +9,3 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
-set(FILES
- SystemUtilsApple.h
- SystemUtilsApple.mm
-)
diff --git a/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.cpp b/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.cpp
new file mode 100644
index 0000000000..0b7e3300cf
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.cpp
@@ -0,0 +1,485 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace AZ::JsonMathMatrixSerializerInternal
+{
+ template
+ JsonSerializationResult::Result LoadArray(MatrixType& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+
+ constexpr size_t ElementCount = RowCount * ColumnCount;
+ static_assert(ElementCount == 9 || ElementCount == 12 || ElementCount == 16,
+ "MathMatrixSerializer only support Matrix3x3, Matrix3x4 and Matrix4x4.");
+
+ rapidjson::SizeType arraySize = inputValue.Size();
+ if (arraySize < ElementCount)
+ {
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
+ "Not enough numbers in JSON array to load math matrix from.");
+ }
+
+ AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid());
+ if (!floatSerializer)
+ {
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the JSON float serializer.");
+ }
+
+ constexpr const char* names[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"};
+ float values[ElementCount];
+ for (int i = 0; i < ElementCount; ++i)
+ {
+ ScopedContextPath subPath(context, names[i]);
+ JSR::Result intermediate = floatSerializer->Load(values + i, azrtti_typeid(), inputValue[i], context);
+ if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediate;
+ }
+ }
+
+ size_t valueIndex = 0;
+ for (size_t r = 0; r < RowCount; ++r)
+ {
+ for (size_t c = 0; c < ColumnCount; ++c)
+ {
+ output.SetElement(aznumeric_caster(r), aznumeric_caster(c), values[valueIndex++]);
+ }
+ }
+
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read math matrix.");
+ }
+
+ JsonSerializationResult::Result LoadFloatFromObject(
+ float& output,
+ const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context,
+ const char* name,
+ const char* altName)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+
+ AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid());
+ if (!floatSerializer)
+ {
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the json float serializer.");
+ }
+
+ const char* nameUsed = name;
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+ auto iterator = inputValue.FindMember(rapidjson::StringRef(name));
+ if (iterator == inputValue.MemberEnd())
+ {
+ nameUsed = altName;
+ iterator = inputValue.FindMember(rapidjson::StringRef(altName));
+ if (iterator == inputValue.MemberEnd())
+ {
+ // field not found so leave default value
+ result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed));
+ nameUsed = nullptr;
+ }
+ }
+
+ if (nameUsed)
+ {
+ ScopedContextPath subPath(context, nameUsed);
+ JSR::Result intermediate = floatSerializer->Load(&output, azrtti_typeid(), iterator->value, context);
+ if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediate;
+ }
+ else
+ {
+ result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
+ }
+ }
+
+ return context.Report(result, "Successfully read float.");
+ }
+
+ JsonSerializationResult::Result LoadVector3FromObject(
+ Vector3& output,
+ const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context,
+ AZStd::fixed_vector names)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+ constexpr size_t ElementCount = 3; // Vector3
+
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+ float values[ElementCount];
+ for (int i = 0; i < ElementCount; ++i)
+ {
+ values[i] = output.GetElement(i);
+ auto name = names[i * 2];
+ auto altName = names[(i * 2) + 1];
+
+ JSR::Result intermediate = LoadFloatFromObject(values[i], inputValue, context, name.data(), altName.data());
+ if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediate;
+ }
+ else
+ {
+ result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
+ }
+ }
+
+ for (int i = 0; i < ElementCount; ++i)
+ {
+ output.SetElement(i, values[i]);
+ }
+
+ return context.Report(result, "Successfully read math matrix.");
+ }
+
+ JsonSerializationResult::Result LoadQuaternionAndScale(
+ AZ::Quaternion& quaternion,
+ float& scale,
+ const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+ scale = 1.0f;
+ JSR::Result intermediateScale = LoadFloatFromObject(scale, inputValue, context, "scale", "Scale");
+ if (intermediateScale.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediateScale;
+ }
+ result.Combine(intermediateScale);
+
+ if (AZ::IsClose(scale, 0.0f))
+ {
+ result.Combine({ JSR::Tasks::ReadField, JSR::Outcomes::Unsupported });
+ return context.Report(result, "Scale can not be zero.");
+ }
+
+ AZ::Vector3 degreesRollPitchYaw = AZ::Vector3::CreateZero();
+ JSR::Result intermediateDegrees = LoadVector3FromObject(degreesRollPitchYaw, inputValue, context, { "roll", "Roll", "pitch", "Pitch", "yaw", "Yaw" });
+ if (intermediateDegrees.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediateDegrees;
+ }
+ result.Combine(intermediateDegrees);
+
+ // the quaternion should be equivalent to a series of rotations in the order z, then y, then x
+ const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(degreesRollPitchYaw);
+ quaternion = AZ::Quaternion::CreateRotationX(eulerRadians.GetX()) *
+ AZ::Quaternion::CreateRotationY(eulerRadians.GetY()) *
+ AZ::Quaternion::CreateRotationZ(eulerRadians.GetZ());
+
+ return context.Report(result, "Successfully read math yaw, pitch, roll, and scale.");
+ }
+
+ template
+ JsonSerializationResult::Result LoadObject(MatrixType& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+ output = MatrixType::CreateIdentity();
+
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+ float scale;
+ AZ::Quaternion rotation;
+
+ JSR::Result intermediate = LoadQuaternionAndScale(rotation, scale, inputValue, context);
+ if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediate;
+ }
+ result.Combine(intermediate);
+
+ AZ::Vector3 translation = AZ::Vector3::CreateZero();
+ JSR::Result intermediateTranslation = LoadVector3FromObject(translation, inputValue, context, { "x", "X", "y", "Y", "z", "Z" });
+ if (intermediateTranslation.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediateTranslation;
+ }
+ result.Combine(intermediateTranslation);
+
+ // composed a matrix by rotation, then scale, then translation
+ auto matrix = MatrixType::CreateFromQuaternion(rotation);
+ matrix.MultiplyByScale(Vector3{ scale });
+ matrix.SetTranslation(translation);
+
+ if (matrix == MatrixType::CreateIdentity())
+ {
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity matrix for empty object.");
+ }
+
+ output = matrix;
+ return context.Report(result, "Successfully read math matrix.");
+ }
+
+ template<>
+ JsonSerializationResult::Result LoadObject(Matrix3x3& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+ output = Matrix3x3::CreateIdentity();
+
+ JSR::ResultCode result(JSR::Tasks::ReadField);
+ float scale;
+ AZ::Quaternion rotation;
+
+ JSR::Result intermediate = LoadQuaternionAndScale(rotation, scale, inputValue, context);
+ if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
+ {
+ return intermediate;
+ }
+ result.Combine(intermediate);
+
+ // composed a matrix by rotation then scale
+ auto matrix = Matrix3x3::CreateFromQuaternion(rotation);
+ matrix.MultiplyByScale(Vector3{ scale });
+
+ if (matrix == Matrix3x3::CreateIdentity())
+ {
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity matrix for empty object.");
+ }
+
+ output = matrix;
+ return context.Report(result, "Successfully read math matrix.");
+ }
+
+ template
+ JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId,
+ const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+
+ constexpr size_t ElementCount = RowCount * ColumnCount;
+ static_assert(ElementCount == 9 || ElementCount == 12 || ElementCount == 16,
+ "MathMatrixSerializer only support Matrix3x3, Matrix3x4 and Matrix4x4.");
+
+ AZ_Assert(azrtti_typeid() == outputValueTypeId,
+ "Unable to deserialize Matrix%zux%zu to json because the provided type is %s",
+ RowCount, ColumnCount, outputValueTypeId.ToString().c_str());
+ AZ_UNUSED(outputValueTypeId);
+
+ MatrixType* matrix = reinterpret_cast(outputValue);
+ AZ_Assert(matrix, "Output value for JsonMatrix%zux%zuSerializer can't be null.", RowCount, ColumnCount);
+
+ switch (inputValue.GetType())
+ {
+ case rapidjson::kArrayType:
+ return LoadArray(*matrix, inputValue, context);
+ case rapidjson::kObjectType:
+ return LoadObject(*matrix, inputValue, context);
+
+ case rapidjson::kStringType:
+ [[fallthrough]];
+ case rapidjson::kNumberType:
+ [[fallthrough]];
+ case rapidjson::kNullType:
+ [[fallthrough]];
+ case rapidjson::kFalseType:
+ [[fallthrough]];
+ case rapidjson::kTrueType:
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
+ "Unsupported type. Math matrix can only be read from arrays or objects.");
+
+ default:
+ return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unknown,
+ "Unknown json type encountered in math matrix.");
+ }
+ }
+
+ template
+ AZ::Quaternion CreateQuaternion(const MatrixType& matrix);
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix3x3& matrix)
+ {
+ return Quaternion::CreateFromMatrix3x3(matrix);
+ }
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix3x4& matrix)
+ {
+ return Quaternion::CreateFromMatrix3x4(matrix);
+ }
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix4x4& matrix)
+ {
+ return Quaternion::CreateFromMatrix4x4(matrix);
+ }
+
+ template
+ JsonSerializationResult::Result StoreRotationAndScale(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
+ const Uuid& valueTypeId, JsonSerializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+ AZ_UNUSED(valueTypeId);
+
+ const MatrixType* matrix = reinterpret_cast(inputValue);
+ AZ_Assert(matrix, "Input value for JsonMatrixSerializer can't be null.");
+ const MatrixType* defaultMatrix = reinterpret_cast(defaultValue);
+
+ if (!context.ShouldKeepDefaults() && defaultMatrix && *matrix == *defaultMatrix)
+ {
+ return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default math Matrix used.");
+ }
+
+ MatrixType matrixToExport = *matrix;
+ AZ::Vector3 scale = matrixToExport.ExtractScale();
+
+ AZ::Quaternion rotation = CreateQuaternion(matrixToExport);
+ auto degrees = rotation.GetEulerDegrees();
+ outputValue.AddMember(rapidjson::StringRef("roll"), degrees.GetX(), context.GetJsonAllocator());
+ outputValue.AddMember(rapidjson::StringRef("pitch"), degrees.GetY(), context.GetJsonAllocator());
+ outputValue.AddMember(rapidjson::StringRef("yaw"), degrees.GetZ(), context.GetJsonAllocator());
+ outputValue.AddMember(rapidjson::StringRef("scale"), scale.GetX(), context.GetJsonAllocator());
+
+ return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Success, "Math Matrix successfully stored.");
+ }
+
+ template
+ JsonSerializationResult::Result StoreTranslation(rapidjson::Value& outputValue, const void* inputValue,
+ const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
+ {
+ namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
+ AZ_UNUSED(valueTypeId);
+
+ const MatrixType* matrix = reinterpret_cast(inputValue);
+ AZ_Assert(matrix, "Input value for JsonMatrixSerializer can't be null.");
+ const MatrixType* defaultMatrix = reinterpret_cast(defaultValue);
+
+ if (!context.ShouldKeepDefaults() && defaultMatrix && *matrix == *defaultMatrix)
+ {
+ return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default math Matrix used.");
+ }
+
+ auto translation = matrix->GetTranslation();
+ outputValue.AddMember(rapidjson::StringRef("x"), translation.GetX(), context.GetJsonAllocator());
+ outputValue.AddMember(rapidjson::StringRef("y"), translation.GetY(), context.GetJsonAllocator());
+ outputValue.AddMember(rapidjson::StringRef("z"), translation.GetZ(), context.GetJsonAllocator());
+
+ return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Success, "Math Matrix successfully stored.");
+ }
+}
+
+namespace AZ
+{
+ // Matrix3x3
+
+ AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix3x3Serializer, SystemAllocator, 0);
+
+ JsonSerializationResult::Result JsonMatrix3x3Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
+ const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ return JsonMathMatrixSerializerInternal::Load(
+ outputValue,
+ outputValueTypeId,
+ inputValue,
+ context);
+ }
+
+ JsonSerializationResult::Result JsonMatrix3x3Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
+ const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
+ {
+ outputValue.SetObject();
+
+ return JsonMathMatrixSerializerInternal::StoreRotationAndScale(
+ outputValue,
+ inputValue,
+ defaultValue,
+ valueTypeId,
+ context);
+ }
+
+
+ // Matrix3x4
+
+ AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix3x4Serializer, SystemAllocator, 0);
+
+ JsonSerializationResult::Result JsonMatrix3x4Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
+ const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ return JsonMathMatrixSerializerInternal::Load(
+ outputValue,
+ outputValueTypeId,
+ inputValue,
+ context);
+ }
+
+ JsonSerializationResult::Result JsonMatrix3x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
+ const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
+ {
+ outputValue.SetObject();
+
+ auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale(
+ outputValue,
+ inputValue,
+ defaultValue,
+ valueTypeId,
+ context);
+
+ auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation(
+ outputValue,
+ inputValue,
+ defaultValue,
+ valueTypeId,
+ context);
+
+ result.GetResultCode().Combine(resultTranslation);
+ return result;
+ }
+
+ // Matrix4x4
+
+ AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix4x4Serializer, SystemAllocator, 0);
+
+ JsonSerializationResult::Result JsonMatrix4x4Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
+ const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+ {
+ return JsonMathMatrixSerializerInternal::Load(
+ outputValue,
+ outputValueTypeId,
+ inputValue,
+ context);
+ }
+
+ JsonSerializationResult::Result JsonMatrix4x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
+ const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
+ {
+ outputValue.SetObject();
+
+ auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale(
+ outputValue,
+ inputValue,
+ defaultValue,
+ valueTypeId,
+ context);
+
+ auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation(
+ outputValue,
+ inputValue,
+ defaultValue,
+ valueTypeId,
+ context);
+
+ result.GetResultCode().Combine(resultTranslation);
+ return result;
+ }
+}
diff --git a/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.h b/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.h
new file mode 100644
index 0000000000..81c9635a79
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.h
@@ -0,0 +1,54 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#include
+
+namespace AZ
+{
+ class JsonMatrix3x3Serializer
+ : public BaseJsonSerializer
+ {
+ public:
+ AZ_RTTI(JsonMatrix3x3Serializer, "{8C76CD6A-8576-4604-A746-CF7A7F20F366}", BaseJsonSerializer);
+ AZ_CLASS_ALLOCATOR_DECL;
+ JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context) override;
+ JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
+ const Uuid& valueTypeId, JsonSerializerContext& context) override;
+ };
+
+ class JsonMatrix3x4Serializer
+ : public BaseJsonSerializer
+ {
+ public:
+ AZ_RTTI(JsonMatrix3x4Serializer, "{E801333B-4AF1-4F43-976C-579670B02DC5}", BaseJsonSerializer);
+ AZ_CLASS_ALLOCATOR_DECL;
+ JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context) override;
+ JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
+ const Uuid& valueTypeId, JsonSerializerContext& context) override;
+ };
+
+ class JsonMatrix4x4Serializer
+ : public BaseJsonSerializer
+ {
+ public:
+ AZ_RTTI(JsonMatrix4x4Serializer, "{46E888FC-248A-4910-9221-4E101A10AEA1}", BaseJsonSerializer);
+ AZ_CLASS_ALLOCATOR_DECL;
+ JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+ JsonDeserializerContext& context) override;
+ JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
+ const Uuid& valueTypeId, JsonSerializerContext& context) override;
+ };
+}
diff --git a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
index e918f8fdb3..3c683f1988 100644
--- a/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/MathReflection.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -366,6 +367,9 @@ namespace AZ
{
context.Serializer()->HandlesType();
context.Serializer()->HandlesType();
+ context.Serializer()->HandlesType();
+ context.Serializer()->HandlesType();
+ context.Serializer()->HandlesType();
context.Serializer()->HandlesType();
context.Serializer()->HandlesType();
context.Serializer()->HandlesType();
diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl
index 90b9ba5afd..1016027966 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl
+++ b/Code/Framework/AzCore/AzCore/Serialization/EditContextConstants.inl
@@ -53,6 +53,10 @@ namespace AZ
//! RemoveableByUser : A bool which determines if the component can be removed by the user.
//! Setting this to false prevents the user from removing this component. Default behavior is removeable by user.
const static AZ::Crc32 RemoveableByUser = AZ_CRC("RemoveableByUser", 0x32c7fd50);
+ //! An int which, if specified, causes a component to be forced to a particular position in the sorted list of
+ //! components on an entity, and prevents dragging or moving operations which would affect that position.
+ const static AZ::Crc32 FixedComponentListIndex = AZ_CRC_CE("FixedComponentListIndex");
+
const static AZ::Crc32 AppearsInAddComponentMenu = AZ_CRC("AppearsInAddComponentMenu", 0x53790e31);
const static AZ::Crc32 ForceAutoExpand = AZ_CRC("ForceAutoExpand", 0x1a5c79d2); // Ignores expansion state set by user, enforces expansion.
const static AZ::Crc32 AutoExpand = AZ_CRC("AutoExpand", 0x306ff5c0); // Expands automatically unless user changes expansion state.
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index 5357ed66a6..dc0fb13f00 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -290,6 +290,8 @@ set(FILES
Math/MathScriptHelpers.h
Math/MathUtils.cpp
Math/MathUtils.h
+ Math/MathMatrixSerializer.h
+ Math/MathMatrixSerializer.cpp
Math/MathVectorSerializer.h
Math/MathVectorSerializer.cpp
Math/Matrix3x3.cpp
diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/MathMatrixSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/MathMatrixSerializerTests.cpp
new file mode 100644
index 0000000000..b9d1edab76
--- /dev/null
+++ b/Code/Framework/AzCore/Tests/Serialization/Json/MathMatrixSerializerTests.cpp
@@ -0,0 +1,562 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace JsonSerializationTests
+{
+ namespace DataHelper
+ {
+ // Build Matrix
+
+ template
+ MatrixType BuildMatrixRotationWithSale(const AZ::Vector3& angles, float scale)
+ {
+ // start a matrix with angle degrees
+ const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(angles);
+ const auto rotX = MatrixType::CreateRotationX(eulerRadians.GetX());
+ const auto rotY = MatrixType::CreateRotationY(eulerRadians.GetY());
+ const auto rotZ = MatrixType::CreateRotationZ(eulerRadians.GetZ());
+ auto matrix = rotX * rotY * rotZ;
+
+ // apply a scale
+ matrix.MultiplyByScale(AZ::Vector3{ scale });
+ return matrix;
+ }
+
+ template
+ MatrixType BuildMatrix(const AZ::Vector3& angles, float scale, const AZ::Vector3& translation)
+ {
+ auto matrix = BuildMatrixRotationWithSale(angles, scale);
+ matrix.SetTranslation(translation);
+ return matrix;
+ }
+
+ template <>
+ AZ::Matrix3x3 BuildMatrix(const AZ::Vector3& angles, float scale, const AZ::Vector3&)
+ {
+ return BuildMatrixRotationWithSale(angles, scale);
+ }
+
+ // Arbitrary Matrix
+
+ template
+ MatrixType CreateArbitraryMatrixRotationAndSale(AZ::SimpleLcgRandom& random)
+ {
+ // start a matrix with arbitrary degrees
+ float roll = random.GetRandomFloat() * 360.0f;
+ float pitch = random.GetRandomFloat() * 360.0f;
+ float yaw = random.GetRandomFloat() * 360.0f;
+ const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(AZ::Vector3{ roll, pitch, yaw });
+ const auto rotX = MatrixType::CreateRotationX(eulerRadians.GetX());
+ const auto rotY = MatrixType::CreateRotationY(eulerRadians.GetY());
+ const auto rotZ = MatrixType::CreateRotationZ(eulerRadians.GetZ());
+ auto matrix = rotX * rotY * rotZ;
+
+ // apply a scale
+ matrix.MultiplyByScale(AZ::Vector3{ random.GetRandomFloat() });
+ return matrix;
+ }
+
+ template
+ void AssignArbitrarySetTranslation(MatrixType& matrix, AZ::SimpleLcgRandom& random)
+ {
+ float x = random.GetRandomFloat() * 10000.0f;
+ float y = random.GetRandomFloat() * 10000.0f;
+ float z = random.GetRandomFloat() * 10000.0f;
+ matrix.SetTranslation(AZ::Vector3{ x, y, z });
+ }
+
+ template
+ MatrixType CreateArbitraryMatrix(size_t seed);
+
+ template <>
+ AZ::Matrix3x3 CreateArbitraryMatrix(size_t seed)
+ {
+ AZ::SimpleLcgRandom random(seed);
+ return CreateArbitraryMatrixRotationAndSale(random);
+ }
+
+ template <>
+ AZ::Matrix3x4 CreateArbitraryMatrix(size_t seed)
+ {
+ AZ::SimpleLcgRandom random(seed);
+ auto matrix = CreateArbitraryMatrixRotationAndSale(random);
+ AssignArbitrarySetTranslation(matrix, random);
+ return matrix;
+ }
+
+ template <>
+ AZ::Matrix4x4 CreateArbitraryMatrix(size_t seed)
+ {
+ AZ::SimpleLcgRandom random(seed);
+ auto matrix = CreateArbitraryMatrixRotationAndSale(random);
+ AssignArbitrarySetTranslation(matrix, random);
+ return matrix;
+ }
+
+ // CreateQuaternion
+
+ template
+ AZ::Quaternion CreateQuaternion(const MatrixType& matrix);
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix3x3& matrix)
+ {
+ return AZ::Quaternion::CreateFromMatrix3x3(matrix);
+ }
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix3x4& matrix)
+ {
+ return AZ::Quaternion::CreateFromMatrix3x4(matrix);
+ }
+
+ template<>
+ AZ::Quaternion CreateQuaternion(const AZ::Matrix4x4& matrix)
+ {
+ return AZ::Quaternion::CreateFromMatrix4x4(matrix);
+ }
+
+ template
+ void AddRotation(rapidjson::Value& value, const MatrixType& matrix, rapidjson::Document::AllocatorType& allocator)
+ {
+ AZ::Quaternion rotation = CreateQuaternion(matrix);
+ const auto degrees = rotation.GetEulerDegrees();
+ value.AddMember("yaw", degrees.GetX(), allocator);
+ value.AddMember("pitch", degrees.GetY(), allocator);
+ value.AddMember("roll", degrees.GetZ(), allocator);
+ }
+
+ void AddScale(rapidjson::Value& value, float scale, rapidjson::Document::AllocatorType& allocator)
+ {
+ value.AddMember("scale", scale, allocator);
+ }
+
+ void AddTranslation(rapidjson::Value& value, const AZ::Vector3& translation, rapidjson::Document::AllocatorType& allocator)
+ {
+ value.AddMember("x", translation.GetX(), allocator);
+ value.AddMember("y", translation.GetY(), allocator);
+ value.AddMember("z", translation.GetZ(), allocator);
+ }
+
+ template
+ void AddData(rapidjson::Value& value, const MatrixType& matrix, rapidjson::Document::AllocatorType& allocator);
+
+ template <>
+ void AddData(rapidjson::Value& value, const AZ::Matrix3x3& matrix, rapidjson::Document::AllocatorType& allocator)
+ {
+ AddScale(value, matrix.RetrieveScale().GetX(), allocator);
+ AddRotation(value, matrix, allocator);
+ }
+
+ template <>
+ void AddData(rapidjson::Value& value, const AZ::Matrix3x4& matrix, rapidjson::Document::AllocatorType& allocator)
+ {
+ AddScale(value, matrix.RetrieveScale().GetX(), allocator);
+ AddTranslation(value, matrix.GetTranslation(), allocator);
+ AddRotation(value, matrix, allocator);
+ }
+
+ template <>
+ void AddData(rapidjson::Value& value, const AZ::Matrix4x4& matrix, rapidjson::Document::AllocatorType& allocator)
+ {
+ AddScale(value, matrix.RetrieveScale().GetX(), allocator);
+ AddTranslation(value, matrix.GetTranslation(), allocator);
+ AddRotation(value, matrix, allocator);
+ }
+ };
+
+ template
+ class MathMatrixSerializerTestDescription :
+ public JsonSerializerConformityTestDescriptor
+ {
+ public:
+ AZStd::shared_ptr CreateSerializer() override
+ {
+ return AZStd::make_shared();
+ }
+
+ AZStd::shared_ptr CreateDefaultInstance() override
+ {
+ return AZStd::make_shared(MatrixType::CreateIdentity());
+ }
+
+ AZStd::shared_ptr CreateFullySetInstance() override
+ {
+ auto angles = AZ::Vector3 { 0.0f, 0.0f, 0.0f };
+ auto scale = 10.0f;
+ auto translation = AZ::Vector3{ 10.0f, 20.0f, 30.0f };
+ auto matrix = DataHelper::BuildMatrix(angles, scale, translation);
+ return AZStd::make_shared(matrix);
+ }
+
+ AZStd::string_view GetJsonForFullySetInstance() override
+ {
+ if constexpr (RowCount * ColumnCount == 9)
+ {
+ return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0}";
+ }
+ else if constexpr (RowCount * ColumnCount == 12)
+ {
+ return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0,\"x\":10.0,\"y\":20.0,\"z\":30.0}";
+ }
+ else if constexpr (RowCount * ColumnCount == 16)
+ {
+ return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0,\"x\":10.0,\"y\":20.0,\"z\":30.0}";
+ }
+ else
+ {
+ static_assert((RowCount >= 3 && RowCount <= 4) && (ColumnCount >= 3 && ColumnCount <= 4),
+ "Only matrix 3x3, 3x4 or 4x4 are supported by this test.");
+ }
+ return "{}";
+ }
+
+ void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
+ {
+ features.EnableJsonType(rapidjson::kArrayType);
+ features.EnableJsonType(rapidjson::kObjectType);
+ features.m_fixedSizeArray = true;
+ features.m_supportsPartialInitialization = false;
+ features.m_supportsInjection = false;
+ }
+
+ bool AreEqual(const MatrixType& lhs, const MatrixType& rhs) override
+ {
+ for (int r = 0; r < RowCount; ++r)
+ {
+ for (int c = 0; c < ColumnCount; ++c)
+ {
+ if (!AZ::IsClose(lhs.GetElement(r, c), rhs.GetElement(r, c), AZ::Constants::Tolerance))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ };
+
+ using MathMatrixSerializerConformityTestTypes = ::testing::Types<
+ MathMatrixSerializerTestDescription,
+ MathMatrixSerializerTestDescription,
+ MathMatrixSerializerTestDescription
+ >;
+ INSTANTIATE_TYPED_TEST_CASE_P(JsonMathMatrixSerializer, JsonSerializerConformityTests, MathMatrixSerializerConformityTestTypes);
+
+ template
+ class JsonMathMatrixSerializerTests
+ : public BaseJsonSerializerFixture
+ {
+ public:
+ using Descriptor = T;
+
+ void SetUp() override
+ {
+ BaseJsonSerializerFixture::SetUp();
+ m_serializer = AZStd::make_unique();
+ }
+
+ void TearDown() override
+ {
+ m_serializer.reset();
+ BaseJsonSerializerFixture::TearDown();
+ }
+
+ protected:
+ AZStd::unique_ptr m_serializer;
+ };
+
+ struct Matrix3x3Descriptor
+ {
+ using MatrixType = AZ::Matrix3x3;
+ using Serializer = AZ::JsonMatrix3x3Serializer;
+ constexpr static size_t RowCount = 3;
+ constexpr static size_t ColumnCount = 3;
+ constexpr static size_t ElementCount = RowCount * ColumnCount;
+ constexpr static bool HasTranslation = false;
+ };
+
+ struct Matrix3x4Descriptor
+ {
+ using MatrixType = AZ::Matrix3x4;
+ using Serializer = AZ::JsonMatrix3x4Serializer;
+ constexpr static size_t RowCount = 3;
+ constexpr static size_t ColumnCount = 4;
+ constexpr static size_t ElementCount = RowCount * ColumnCount;
+ constexpr static bool HasTranslation = true;
+ };
+
+ struct Matrix4x4Descriptor
+ {
+ using MatrixType = AZ::Matrix4x4;
+ using Serializer = AZ::JsonMatrix4x4Serializer;
+ constexpr static size_t RowCount = 4;
+ constexpr static size_t ColumnCount = 4;
+ constexpr static size_t ElementCount = RowCount * ColumnCount;
+ constexpr static bool HasTranslation = true;
+ };
+
+ using JsonMathMatrixSerializerTypes = ::testing::Types <
+ Matrix3x3Descriptor, Matrix3x4Descriptor, Matrix4x4Descriptor>;
+ TYPED_TEST_CASE(JsonMathMatrixSerializerTests, JsonMathMatrixSerializerTypes);
+
+ // Load array tests
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_Array_ReturnsConvertAndLoadsMatrix)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
+ for (size_t i = 0; i < JsonMathMatrixSerializerTests::Descriptor::ElementCount; ++i)
+ {
+ arrayValue.PushBack(static_cast(i + 1), this->m_jsonDocument->GetAllocator());
+ }
+
+ auto output = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateZero();
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ ASSERT_EQ(Outcomes::Success, result.GetOutcome());
+
+ for (int r = 0; r < JsonMathMatrixSerializerTests::Descriptor::RowCount; ++r)
+ {
+ for (int c = 0; c < JsonMathMatrixSerializerTests::Descriptor::ColumnCount; ++c)
+ {
+ auto testValue = static_cast((r * JsonMathMatrixSerializerTests::Descriptor::ColumnCount) + c + 1);
+ EXPECT_FLOAT_EQ(testValue, output.GetElement(r, c));
+ }
+ }
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_InvalidEntries_ReturnsUnsupportedAndLeavesMatrixUntouched)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
+ for (size_t i = 0; i < JsonMathMatrixSerializerTests::Descriptor::ElementCount; ++i)
+ {
+ if (i == 1)
+ {
+ arrayValue.PushBack(rapidjson::StringRef("Invalid"), this->m_jsonDocument->GetAllocator());
+ }
+ else
+ {
+ arrayValue.PushBack(static_cast(i + 1), this->m_jsonDocument->GetAllocator());
+ }
+ }
+
+ auto output = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateZero();
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome());
+
+ for (int r = 0; r < JsonMathMatrixSerializerTests::Descriptor::RowCount; ++r)
+ {
+ for (int c = 0; c < JsonMathMatrixSerializerTests::Descriptor::ColumnCount; ++c)
+ {
+ EXPECT_FLOAT_EQ(0.0f, output.GetElement(r, c));
+ }
+ }
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_FloatSerializerMissingForArray_ReturnsCatastrophic)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ this->m_jsonRegistrationContext->EnableRemoveReflection();
+ this->m_jsonRegistrationContext->template Serializer()->template HandlesType();
+ this->m_jsonRegistrationContext->DisableRemoveReflection();
+
+ rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
+ for (size_t i = 0; i < JsonMathMatrixSerializerTests::Descriptor::ElementCount + 1; ++i)
+ {
+ arrayValue.PushBack(static_cast(i + 1), this->m_jsonDocument->GetAllocator());
+ }
+
+ typename JsonMathMatrixSerializerTests::Descriptor::MatrixType output;
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ EXPECT_EQ(Outcomes::Catastrophic, result.GetOutcome());
+
+ this->m_jsonRegistrationContext->template Serializer()->template HandlesType();
+ }
+
+ // Load object tests
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_ValidObjectLowerCase_ReturnsSuccessAndLoadsMatrix)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
+ auto input = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateIdentity();
+ DataHelper::AddData(objectValue, input, this->m_jsonDocument->GetAllocator());
+
+ auto output = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateZero();
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ ASSERT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+ EXPECT_TRUE(input == output);
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_ValidObjectWithExtraFields_ReturnsPartialConvertAndLoadsMatrix)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
+ auto input = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateIdentity();
+ DataHelper::AddScale(objectValue, input.RetrieveScale().GetX(), this->m_jsonDocument->GetAllocator());
+ DataHelper::AddRotation(objectValue, input, this->m_jsonDocument->GetAllocator());
+ objectValue.AddMember(rapidjson::StringRef("extra"), "no value", this->m_jsonDocument->GetAllocator());
+
+ auto output = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateZero();
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ ASSERT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+ EXPECT_TRUE(input == output);
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, SaveLoad_Identity_LoadsDefaultMatrixWithIdentity)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ auto defaultValue = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateIdentity();
+
+ rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
+ this->m_serializer->Store(
+ objectInput,
+ &defaultValue,
+ &defaultValue,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonSerializationContext);
+
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer writer(buffer);
+ objectInput.Accept(writer);
+
+ auto output = defaultValue;
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+
+ EXPECT_TRUE(defaultValue == output);
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, LoadSave_Zero_SavesAndLoadsIdentityMatrix)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ auto defaultValue = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateIdentity();
+ auto input = JsonMathMatrixSerializerTests::Descriptor::MatrixType::CreateZero();
+
+ rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
+ this->m_serializer->Store(
+ objectInput,
+ &input,
+ &defaultValue,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonSerializationContext);
+
+ auto output = defaultValue;
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid::Descriptor::MatrixType>(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+
+ ASSERT_EQ(Outcomes::Unsupported, result.GetOutcome());
+ EXPECT_TRUE(defaultValue == output);
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, Load_InvalidFields_ReturnsUnsupportedAndLeavesMatrixUntouched)
+ {
+ using namespace AZ::JsonSerializationResult;
+ using Descriptor = typename JsonMathMatrixSerializerTests::Descriptor;
+
+ const auto defaultValue = Descriptor::MatrixType::CreateIdentity();
+ rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
+ auto input = Descriptor::MatrixType::CreateIdentity();
+ DataHelper::AddData(objectValue, input, this->m_jsonDocument->GetAllocator());
+ objectValue["yaw"] = "Invalid";
+
+ auto output = Descriptor::MatrixType::CreateZero();
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+ ASSERT_EQ(Outcomes::Unsupported, result.GetOutcome());
+ EXPECT_TRUE(input == output);
+ }
+
+ TYPED_TEST(JsonMathMatrixSerializerTests, LoadSave_Arbitrary_SavesAndLoadsArbitraryMatrix)
+ {
+ using namespace AZ::JsonSerializationResult;
+ using Descriptor = typename JsonMathMatrixSerializerTests::Descriptor;
+
+ auto defaultValue = Descriptor::MatrixType::CreateIdentity();
+ size_t elementCount = Descriptor::RowCount * Descriptor::ColumnCount;
+ auto input = DataHelper::CreateArbitraryMatrix(elementCount);
+
+ rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
+ this->m_serializer->Store(
+ objectInput,
+ &input,
+ &defaultValue,
+ azrtti_typeid(),
+ *this->m_jsonSerializationContext);
+
+ auto output = defaultValue;
+ ResultCode result = this->m_serializer->Load(
+ &output,
+ azrtti_typeid(),
+ *this->m_jsonDocument,
+ *this->m_jsonDeserializationContext);
+
+ EXPECT_EQ(Processing::Completed, result.GetProcessing());
+
+ for (int r = 0; r < Descriptor::RowCount; ++r)
+ {
+ for (int c = 0; c < Descriptor::ColumnCount; ++c)
+ {
+ EXPECT_NEAR(input.GetElement(r, c), output.GetElement(r, c), AZ::Constants::Tolerance);
+ }
+ }
+ }
+
+} // namespace JsonSerializationTests
diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
index 2129761bfe..f90717d003 100644
--- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake
+++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
@@ -111,6 +111,7 @@ set(FILES
Serialization/Json/JsonSerializerMock.h
Serialization/Json/MapSerializerTests.cpp
Serialization/Json/MathVectorSerializerTests.cpp
+ Serialization/Json/MathMatrixSerializerTests.cpp
Serialization/Json/SmartPointerSerializerTests.cpp
Serialization/Json/StringSerializerTests.cpp
Serialization/Json/TestCases.h
diff --git a/Code/Framework/AzFramework/AzFramework/Components/NonUniformScaleComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/NonUniformScaleComponent.cpp
index 095d986fa1..57f14ddb38 100644
--- a/Code/Framework/AzFramework/AzFramework/Components/NonUniformScaleComponent.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Components/NonUniformScaleComponent.cpp
@@ -36,6 +36,8 @@ namespace AzFramework
void NonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
+ incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
+
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/WorldBodyBus.h b/Code/Framework/AzFramework/AzFramework/Physics/Components/SimulatedBodyComponentBus.h
similarity index 54%
rename from Code/Framework/AzFramework/AzFramework/Physics/WorldBodyBus.h
rename to Code/Framework/AzFramework/AzFramework/Physics/Components/SimulatedBodyComponentBus.h
index 943e03d0f3..ac6d44af8b 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/WorldBodyBus.h
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Components/SimulatedBodyComponentBus.h
@@ -19,44 +19,29 @@
namespace AzPhysics
{
- struct SimulatedBody;
-}
-
-namespace Physics
-{
- //! Requests for generic physical world bodies
- class WorldBodyRequests
+ //! Requests for physics simulated body components.
+ class SimulatedBodyComponentRequests
: public AZ::ComponentBus
{
public:
using MutexType = AZStd::recursive_mutex;
- //! Enable physics for this body
+ //! Enable physics for this body.
virtual void EnablePhysics() = 0;
- //! Disable physics for this body
+ //! Disable physics for this body.
virtual void DisablePhysics() = 0;
- //! Retrieve whether physics is enabled for this body
+ //! Retrieve whether physics is enabled for this body.
virtual bool IsPhysicsEnabled() const = 0;
- //! Retrieves the AABB(aligned-axis bounding box) for this body
+ //! Retrieves the AABB(aligned-axis bounding box) for this body.
virtual AZ::Aabb GetAabb() const = 0;
- //! Retrieves current WorldBody* for this body. Note: Do not hold a reference to AzPhysics::SimulatedBody* as could be deleted
- virtual AzPhysics::SimulatedBody* GetWorldBody() = 0;
-
- //! Perform a single-object raycast against this body
+ //! Get the Simulated Body Handle for this body.
+ virtual AzPhysics::SimulatedBodyHandle GetSimulatedBodyHandle() const = 0;
+ //! Retrieves current WorldBody* for this body.
+ //! @note Do not hold a reference to AzPhysics::SimulatedBody* as it could be deleted or moved.
+ virtual AzPhysics::SimulatedBody* GetSimulatedBody() = 0;
+ //! Perform a single-object raycast against this body.
virtual AzPhysics::SceneQueryHit RayCast(const AzPhysics::RayCastRequest& request) = 0;
};
- using WorldBodyRequestBus = AZ::EBus;
-
- //! Notifications for generic physical world bodies
- class WorldBodyNotifications
- : public AZ::ComponentBus
- {
- public:
- //! Notification for physics enabled
- virtual void OnPhysicsEnabled() = 0;
- //! Notification for physics disabled
- virtual void OnPhysicsDisabled() = 0;
- };
- using WorldBodyNotificationBus = AZ::EBus;
+ using SimulatedBodyComponentRequestsBus = AZ::EBus;
}
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp
index ae8f4308df..b5f113582b 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Utils.cpp
@@ -21,7 +21,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -39,19 +39,19 @@ namespace Physics
{
namespace ReflectionUtils
{
- void ReflectWorldBodyBus(AZ::ReflectContext* context)
+ void ReflectSimulatedBodyComponentRequestsBus(AZ::ReflectContext* context)
{
if (auto* behaviorContext = azrtti_cast(context))
{
- behaviorContext->EBus("WorldBodyRequestBus")
+ behaviorContext->EBus("SimulatedBodyComponentRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "physics")
->Attribute(AZ::Script::Attributes::Category, "PhysX")
- ->Event("EnablePhysics", &WorldBodyRequests::EnablePhysics)
- ->Event("DisablePhysics", &WorldBodyRequests::DisablePhysics)
- ->Event("IsPhysicsEnabled", &WorldBodyRequests::IsPhysicsEnabled)
- ->Event("GetAabb", &WorldBodyRequests::GetAabb)
- ->Event("RayCast", &WorldBodyRequests::RayCast)
+ ->Event("EnablePhysics", &AzPhysics::SimulatedBodyComponentRequests::EnablePhysics)
+ ->Event("DisablePhysics", &AzPhysics::SimulatedBodyComponentRequests::DisablePhysics)
+ ->Event("IsPhysicsEnabled", &AzPhysics::SimulatedBodyComponentRequests::IsPhysicsEnabled)
+ ->Event("GetAabb", &AzPhysics::SimulatedBodyComponentRequests::GetAabb)
+ ->Event("RayCast", &AzPhysics::SimulatedBodyComponentRequests::RayCast)
;
}
}
@@ -131,7 +131,7 @@ namespace Physics
AnimationConfiguration::Reflect(context);
CharacterConfiguration::Reflect(context);
AzPhysics::SimulatedBody::Reflect(context);
- ReflectWorldBodyBus(context);
+ ReflectSimulatedBodyComponentRequestsBus(context);
CollisionFilteringRequests::Reflect(context);
AzPhysics::SceneQuery::ReflectSceneQueryObjects(context);
ReflectWindBus(context);
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h
index 2649655f50..c324104027 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.h
@@ -48,15 +48,21 @@ namespace AzFramework
};
//! The interface used by MultiViewportController to manage individual instances.
+ template
class MultiViewportControllerInstanceInterface
{
public:
- explicit MultiViewportControllerInstanceInterface(ViewportId viewport)
+ using ControllerType = TController;
+
+ MultiViewportControllerInstanceInterface(ViewportId viewport, ControllerType* controller)
: m_viewportId(viewport)
+ , m_controller(controller)
{
}
ViewportId GetViewportId() const { return m_viewportId; }
+ ControllerType* GetController() { return m_controller; }
+ const ControllerType* GetController() const { return m_controller; }
virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; }
virtual void ResetInputChannels() {}
@@ -64,6 +70,7 @@ namespace AzFramework
private:
ViewportId m_viewportId;
+ ControllerType* m_controller;
};
} //namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl
index cc59418dac..4d82acdfba 100644
--- a/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl
+++ b/Code/Framework/AzFramework/AzFramework/Viewport/MultiViewportController.inl
@@ -17,8 +17,8 @@ namespace AzFramework
MultiViewportController::~MultiViewportController()
{
static_assert(
- AZStd::is_constructible::value,
- "TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId) constructor"
+ AZStd::is_same::value,
+ "TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId, ViewportController) constructor"
);
}
@@ -50,7 +50,7 @@ namespace AzFramework
template
void MultiViewportController::RegisterViewportContext(ViewportId viewport)
{
- m_instances[viewport] = AZStd::make_unique(viewport);
+ m_instances[viewport] = AZStd::make_unique(viewport, static_cast(this));
}
template
diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake
index 88f68d8bab..1b1cd49aa7 100644
--- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake
+++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake
@@ -213,6 +213,12 @@ set(FILES
StreamingInstall/StreamingInstall.cpp
StreamingInstall/StreamingInstallRequests.h
StreamingInstall/StreamingInstallNotifications.h
+ Physics/Collision/CollisionEvents.h
+ Physics/Collision/CollisionEvents.cpp
+ Physics/Collision/CollisionLayers.h
+ Physics/Collision/CollisionLayers.cpp
+ Physics/Collision/CollisionGroups.h
+ Physics/Collision/CollisionGroups.cpp
Physics/Common/PhysicsSceneQueries.h
Physics/Common/PhysicsSceneQueries.cpp
Physics/Common/PhysicsEvents.h
@@ -223,12 +229,7 @@ set(FILES
Physics/Common/PhysicsSimulatedBodyEvents.h
Physics/Common/PhysicsSimulatedBodyEvents.cpp
Physics/Common/PhysicsTypes.h
- Physics/Collision/CollisionEvents.h
- Physics/Collision/CollisionEvents.cpp
- Physics/Collision/CollisionLayers.h
- Physics/Collision/CollisionLayers.cpp
- Physics/Collision/CollisionGroups.h
- Physics/Collision/CollisionGroups.cpp
+ Physics/Components/SimulatedBodyComponentBus.h
Physics/Configuration/CollisionConfiguration.h
Physics/Configuration/CollisionConfiguration.cpp
Physics/Configuration/RigidBodyConfiguration.h
@@ -265,7 +266,6 @@ set(FILES
Physics/ShapeConfiguration.h
Physics/ShapeConfiguration.cpp
Physics/SystemBus.h
- Physics/WorldBodyBus.h
Physics/ColliderComponentBus.h
Physics/RagdollPhysicsBus.h
Physics/CharacterPhysicsDataBus.h
diff --git a/Code/CryEngine/CrySystem/SystemUtilsApple.h b/Code/Framework/AzFramework/Platform/Common/Apple/AzFramework/Utils/SystemUtilsApple.h
similarity index 100%
rename from Code/CryEngine/CrySystem/SystemUtilsApple.h
rename to Code/Framework/AzFramework/Platform/Common/Apple/AzFramework/Utils/SystemUtilsApple.h
diff --git a/Code/CryEngine/CrySystem/SystemUtilsApple.mm b/Code/Framework/AzFramework/Platform/Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
similarity index 100%
rename from Code/CryEngine/CrySystem/SystemUtilsApple.mm
rename to Code/Framework/AzFramework/Platform/Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Utils/SystemUtilsApple.h b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Utils/SystemUtilsApple.h
new file mode 100644
index 0000000000..33a89bd146
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Utils/SystemUtilsApple.h
@@ -0,0 +1,16 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+#pragma once
+
+#include "../../../Common/Apple/AzFramework/Utils/SystemUtilsApple.h"
diff --git a/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake
index 9f4a09418f..b69278665a 100644
--- a/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake
+++ b/Code/Framework/AzFramework/Platform/Mac/platform_mac_files.cmake
@@ -36,4 +36,6 @@ set(FILES
../Common/Unimplemented/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard_Unimplemented.cpp
AzFramework/Archive/ArchiveVars_Platform.h
AzFramework/Archive/ArchiveVars_Mac.h
+ ../Common/Apple/AzFramework/Utils/SystemUtilsApple.h
+ ../Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
)
diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Utils/SystemUtilsApple.h b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Utils/SystemUtilsApple.h
new file mode 100644
index 0000000000..5ac96c8523
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Utils/SystemUtilsApple.h
@@ -0,0 +1,15 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+#pragma once
+
+#include "../../../Common/Apple/AzFramework/Utils/SystemUtilsApple.h"
diff --git a/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake b/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake
index c3e5e7b7c1..f1bf958067 100644
--- a/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake
+++ b/Code/Framework/AzFramework/Platform/iOS/platform_ios_files.cmake
@@ -36,5 +36,7 @@ set(FILES
AzFramework/Process/ProcessCommon.h
AzFramework/Process/ProcessWatcher_iOS.cpp
AzFramework/Process/ProcessCommunicator_iOS.cpp
+ ../Common/Apple/AzFramework/Utils/SystemUtilsApple.h
+ ../Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EntityPropertyEditorRequestsBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EntityPropertyEditorRequestsBus.h
index 35b2e485b5..1959183fa0 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EntityPropertyEditorRequestsBus.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EntityPropertyEditorRequestsBus.h
@@ -31,6 +31,10 @@ namespace AzToolsFramework
//! Allows a component to get the list of selected entities
//! \param selectedEntityIds the return vector holding the entities required
virtual void GetSelectedEntities(EntityIdList& selectedEntityIds) = 0;
+
+ //! Explicitly sets a component as having been the most recently added.
+ //! This means that the next time the UI refreshes, that component will be ensured to be visible.
+ virtual void SetNewComponentId(AZ::ComponentId componentId) = 0;
};
using EntityPropertyEditorRequestBus = AZ::EBus;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index 475510c52f..d4485f8e99 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -182,6 +182,22 @@ namespace AzToolsFramework
instanceToParentUnder = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
parent = instanceToParentUnder->get().GetContainerEntityId();
}
+
+ //Detect whether this instantiation would produce a cyclical dependency
+ auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath);
+ Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
+
+ // If the template isn't currently loaded, there's no way for it to be in the hierarchy so we just skip the check.
+ if (templateId != Prefab::InvalidTemplateId && IsPrefabInInstanceAncestorHierarchy(templateId, instanceToParentUnder->get()))
+ {
+ return AZ::Failure(
+ AZStd::string::format(
+ "Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).",
+ relativePath.Native().c_str(),
+ instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()
+ )
+ );
+ }
{
// Initialize Undo Batch object
@@ -192,7 +208,7 @@ namespace AzToolsFramework
instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
// Instantiate the Prefab
- auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(filePath, instanceToParentUnder);
+ auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder);
if (!instanceToCreate)
{
@@ -242,6 +258,23 @@ namespace AzToolsFramework
return AZ::Success();
}
+ bool PrefabPublicHandler::IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance)
+ {
+ InstanceOptionalConstReference currentInstance = instance;
+
+ while (currentInstance.has_value())
+ {
+ if (currentInstance->get().GetTemplateId() == prefabTemplateId)
+ {
+ return true;
+ }
+
+ currentInstance = currentInstance->get().GetParentInstance();
+ }
+
+ return false;
+ }
+
void PrefabPublicHandler::CreateLink(
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
index 5ade666a40..03b3827328 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h
@@ -106,6 +106,14 @@ namespace AzToolsFramework
const AZStd::vector& entityIds, EntityList& inputEntityList, EntityList& topLevelEntities,
AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance);
+ /* Detects whether an instance of prefabTemplateId is present in the hierarchy of ancestors of instance.
+ *
+ * \param prefabTemplateId The template id to test for
+ * \param instance The instance whose ancestor hierarchy prefabTemplateId will be tested against.
+ * \return true if an instance of the template of id prefabTemplateId could be found in the ancestor hierarchy of instance, false otherwise.
+ */
+ bool IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance);
+
static Instance* GetParentInstance(Instance* instance);
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp
index 4413586e77..3910e80f75 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp
@@ -721,6 +721,8 @@ namespace AzToolsFramework
TemplateId PrefabSystemComponent::GetTemplateIdFromFilePath(AZ::IO::PathView filePath) const
{
+ AZ_Assert(!filePath.IsAbsolute(), "Prefab - GetTemplateIdFromFilePath was passed an absolute path. Prefabs use paths relative to the project folder.");
+
auto found = m_templateFilePathToIdMap.find(filePath);
if (found != m_templateFilePathToIdMap.end())
{
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
index 5e928a382a..989398f196 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp
@@ -39,9 +39,10 @@ namespace AzToolsFramework
editContext->Class("Non-uniform Scale",
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
- ->Attribute(AZ::Edit::Attributes::Category, "Non-uniform Scale")
- ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
- ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+ ->Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 1)
+ ->Attribute(AZ::Edit::Attributes::RemoveableByUser, true)
+ ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/NonUniformScale.svg")
+ ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/NonUniformScale.svg")
->DataElement(
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_scale, "Non-uniform Scale",
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
@@ -61,6 +62,8 @@ namespace AzToolsFramework
void EditorNonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
+ incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
+
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp
index dcced5b705..f8d02b6581 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp
@@ -25,11 +25,15 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
#include
#include
@@ -1196,6 +1200,66 @@ namespace AzToolsFramework
destinationComponent->SetWorldTM(const_cast(sourceComponent)->GetWorldTM());
}
+ AZ::Component* TransformComponent::FindPresentOrPendingComponent(AZ::Uuid componentUuid)
+ {
+ // first check if the component is present and valid
+ if (AZ::Component* foundComponent = GetEntity()->FindComponent(componentUuid))
+ {
+ return foundComponent;
+ }
+
+ // then check to see if there's a component pending because it's in an invalid state
+ AZStd::vector pendingComponents;
+ AzToolsFramework::EditorPendingCompositionRequestBus::Event(GetEntityId(),
+ &AzToolsFramework::EditorPendingCompositionRequests::GetPendingComponents, pendingComponents);
+
+ for (const auto pendingComponent : pendingComponents)
+ {
+ if (pendingComponent->RTTI_IsTypeOf(componentUuid))
+ {
+ return pendingComponent;
+ }
+ }
+
+ return nullptr;
+ }
+
+ bool TransformComponent::IsAddNonUniformScaleButtonReadOnly()
+ {
+ return FindPresentOrPendingComponent(EditorNonUniformScaleComponent::TYPEINFO_Uuid()) != nullptr;
+ }
+
+ AZ::Crc32 TransformComponent::OnAddNonUniformScaleButtonPressed()
+ {
+ // if there is already a non-uniform scale component, do nothing
+ if (FindPresentOrPendingComponent(EditorNonUniformScaleComponent::TYPEINFO_Uuid()))
+ {
+ return AZ::Edit::PropertyRefreshLevels::None;
+ }
+
+ const AZStd::vector entityList = { GetEntityId() };
+ const AZ::ComponentTypeList componentsToAdd = { EditorNonUniformScaleComponent::TYPEINFO_Uuid() };
+
+ AzToolsFramework::EntityCompositionRequests::AddComponentsOutcome addComponentsOutcome;
+ AzToolsFramework::EntityCompositionRequestBus::BroadcastResult(addComponentsOutcome,
+ &AzToolsFramework::EntityCompositionRequests::AddComponentsToEntities, entityList, componentsToAdd);
+
+ const auto nonUniformScaleComponent = FindPresentOrPendingComponent(EditorNonUniformScaleComponent::RTTI_Type());
+ AZ::ComponentId nonUniformScaleComponentId =
+ nonUniformScaleComponent ? nonUniformScaleComponent->GetId() : AZ::InvalidComponentId;
+
+ if (!addComponentsOutcome.IsSuccess() || !nonUniformScaleComponent)
+ {
+ AZ_Warning("Transform component", false, "Failed to add non-uniform scale component.");
+ return AZ::Edit::PropertyRefreshLevels::None;
+ }
+
+ AzToolsFramework::EntityPropertyEditorRequestBus::Broadcast(
+ &AzToolsFramework::EntityPropertyEditorRequests::SetNewComponentId, nonUniformScaleComponentId);
+
+ return AZ::Edit::PropertyRefreshLevels::EntireTree;
+ }
+
void TransformComponent::Reflect(AZ::ReflectContext* context)
{
// reflect data for script, serialization, editing..
@@ -1211,6 +1275,7 @@ namespace AzToolsFramework
serializeContext->Class()->
Field("Parent Entity", &TransformComponent::m_parentEntityId)->
Field("Transform Data", &TransformComponent::m_editorTransform)->
+ Field("AddNonUniformScaleButton", &TransformComponent::m_addNonUniformScaleButton)->
Field("Cached World Transform", &TransformComponent::m_cachedWorldTransform)->
Field("Cached World Transform Parent", &TransformComponent::m_cachedWorldTransformParent)->
Field("Parent Activation Transform Mode", &TransformComponent::m_parentActivationTransformMode)->
@@ -1224,6 +1289,7 @@ namespace AzToolsFramework
{
ptrEdit->Class("Transform", "Controls the placement of the entity in the world in 3d")->
ClassElement(AZ::Edit::ClassElements::EditorData, "")->
+ Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 0)->
Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Transform.svg")->
Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Transform.png")->
Attribute(AZ::Edit::Attributes::AutoExpand, true)->
@@ -1234,6 +1300,10 @@ namespace AzToolsFramework
DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")->
Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChanged)->
Attribute(AZ::Edit::Attributes::AutoExpand, true)->
+ DataElement(AZ::Edit::UIHandlers::Button, &TransformComponent::m_addNonUniformScaleButton, "", "")->
+ Attribute(AZ::Edit::Attributes::ButtonText, "Add non-uniform scale")->
+ Attribute(AZ::Edit::Attributes::ReadOnly, &TransformComponent::IsAddNonUniformScaleButtonReadOnly)->
+ Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::OnAddNonUniformScaleButtonPressed)->
DataElement(AZ::Edit::UIHandlers::ComboBox, &TransformComponent::m_parentActivationTransformMode,
"Parent activation", "Configures relative transform behavior when parent activates.")->
EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainOriginalRelativeTransform, "Original relative transform")->
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h
index 8327c5f128..3d1e1ed672 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include "EditorComponentBase.h"
#include "TransformComponentBus.h"
@@ -228,6 +229,10 @@ namespace AzToolsFramework
void CheckApplyCachedWorldTransform(const AZ::Transform& parentWorld);
+ AZ::Component* FindPresentOrPendingComponent(AZ::Uuid componentUuid);
+ bool IsAddNonUniformScaleButtonReadOnly();
+ AZ::Crc32 OnAddNonUniformScaleButtonPressed();
+
// Drives transform behavior when parent activates. See AZ::TransformConfig::ParentActivationTransformMode for details.
AZ::TransformConfig::ParentActivationTransformMode m_parentActivationTransformMode;
@@ -260,6 +265,10 @@ namespace AzToolsFramework
bool m_worldTransformDirty = true;
bool m_isStatic = false;
+ // This is a workaround for a bug which causes the button to appear with incorrect placement if a UI
+ // element is used rather than a data element.
+ bool m_addNonUniformScaleButton = false;
+
// Deprecated
AZ::InterpolationMode m_interpolatePosition;
AZ::InterpolationMode m_interpolateRotation;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
index 181f5b9a9d..bfb2ff4256 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
@@ -63,6 +63,7 @@ AZ_POP_DISABLE_WARNING
#include
#include
#include
+#include
#include
#include
#include
@@ -494,6 +495,11 @@ namespace AzToolsFramework
}
}
+ void EntityPropertyEditor::SetNewComponentId(AZ::ComponentId componentId)
+ {
+ m_newComponentId = componentId;
+ }
+
void EntityPropertyEditor::SetOverrideEntityIds(const AzToolsFramework::EntityIdSet& entities)
{
m_overrideSelectedEntityIds = entities;
@@ -1039,15 +1045,23 @@ namespace AzToolsFramework
sortedComponents.end(),
[=](const OrderedSortComponentEntry& component1, const OrderedSortComponentEntry& component2)
{
- // Transform component must be first, always
- // If component 1 is a transform component, it is sorted earlier
- if (component1.m_component->RTTI_IsTypeOf(AZ::EditorTransformComponentTypeId))
+ AZStd::optional fixedComponentListIndex1 = GetFixedComponentListIndex(component1.m_component);
+ AZStd::optional fixedComponentListIndex2 = GetFixedComponentListIndex(component2.m_component);
+
+ // If both components have fixed list indices, sort based on those indices
+ if (fixedComponentListIndex1.has_value() && fixedComponentListIndex2.has_value())
+ {
+ return fixedComponentListIndex1.value() < fixedComponentListIndex2.value();
+ }
+
+ // If component 1 has a fixed list index, sort it first
+ if (fixedComponentListIndex1.has_value())
{
return true;
}
- // If component 2 is a transform component, component 1 is never sorted earlier
- if (component2.m_component->RTTI_IsTypeOf(AZ::EditorTransformComponentTypeId))
+ // If component 2 has a fixed list index, component 1 should not be sorted before it
+ if (fixedComponentListIndex2.has_value())
{
return false;
}
@@ -1128,10 +1142,7 @@ namespace AzToolsFramework
{
if (auto attributeData = azdynamic_cast*>(attribute))
{
- if (!attributeData->Get(nullptr))
- {
- return false;
- }
+ return attributeData->Get(nullptr);
}
}
}
@@ -1166,6 +1177,36 @@ namespace AzToolsFramework
return true;
}
+ AZStd::optional EntityPropertyEditor::GetFixedComponentListIndex(const AZ::Component* component)
+ {
+ auto componentClassData = component ? GetComponentClassData(component) : nullptr;
+ if (componentClassData && componentClassData->m_editData)
+ {
+ if (auto editorDataElement = componentClassData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData))
+ {
+ if (auto attribute = editorDataElement->FindAttribute(AZ::Edit::Attributes::FixedComponentListIndex))
+ {
+ if (auto attributeData = azdynamic_cast*>(attribute))
+ {
+ return { attributeData->Get(nullptr) };
+ }
+ }
+ }
+ }
+ return {};
+ }
+
+ bool EntityPropertyEditor::IsComponentDraggable(const AZ::Component* component)
+ {
+ return !GetFixedComponentListIndex(component).has_value();
+ }
+
+ bool EntityPropertyEditor::AreComponentsDraggable(const AZ::Entity::ComponentArrayType& components) const
+ {
+ return AZStd::all_of(
+ components.begin(), components.end(), [](AZ::Component* component) { return IsComponentDraggable(component); });
+ }
+
bool EntityPropertyEditor::AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components) const
{
return AreComponentsCopyable(components, m_componentFilter);
@@ -3367,7 +3408,9 @@ namespace AzToolsFramework
sourceComponents.size() == m_selectedEntityIds.size() &&
targetComponents.size() == m_selectedEntityIds.size() &&
AreComponentsRemovable(sourceComponents) &&
- AreComponentsRemovable(targetComponents);
+ AreComponentsRemovable(targetComponents) &&
+ AreComponentsDraggable(sourceComponents) &&
+ AreComponentsDraggable(targetComponents);
}
bool EntityPropertyEditor::IsMoveComponentsUpAllowed() const
@@ -3681,14 +3724,38 @@ namespace AzToolsFramework
void EntityPropertyEditor::ScrollToNewComponent()
{
- //force new components to be visible, assuming they are added to the end of the list and layout
- auto componentEditor = GetComponentEditorsFromIndex(m_componentEditorsUsed - 1);
+ // force new components to be visible
+ // if no component has been explicitly set at the most recently added,
+ // assume new components are added to the end of the list and layout
+ AZ::s32 newComponentIndex = m_componentEditorsUsed - 1;
+
+ // if there is a component id explicitly set as the most recently added, try to find it and make sure it is visible
+ if (m_newComponentId.has_value() && m_newComponentId.value() != AZ::InvalidComponentId)
+ {
+ AZ::ComponentId newComponentId = m_newComponentId.value();
+ for (AZ::s32 componentIndex = 0; componentIndex < m_componentEditorsUsed; ++componentIndex)
+ {
+ if (m_componentEditors[componentIndex])
+ {
+ for (const auto component : m_componentEditors[componentIndex]->GetComponents())
+ {
+ if (component->GetId() == newComponentId)
+ {
+ newComponentIndex = componentIndex;
+ }
+ }
+ }
+ }
+ }
+
+ auto componentEditor = GetComponentEditorsFromIndex(newComponentIndex);
if (componentEditor)
{
m_gui->m_componentList->ensureWidgetVisible(componentEditor);
}
m_shouldScrollToNewComponents = false;
m_shouldScrollToNewComponentsQueued = false;
+ m_newComponentId.reset();
}
void EntityPropertyEditor::QueueScrollToNewComponent()
@@ -4073,7 +4140,8 @@ namespace AzToolsFramework
{
if (!componentEditor ||
!componentEditor->isVisible() ||
- !AreComponentsRemovable(componentEditor->GetComponents()))
+ !AreComponentsRemovable(componentEditor->GetComponents()) ||
+ !AreComponentsDraggable(componentEditor->GetComponents()))
{
return false;
}
@@ -4223,6 +4291,7 @@ namespace AzToolsFramework
while (targetComponentEditor
&& (targetComponentEditor->IsDragged()
|| !AreComponentsRemovable(targetComponentEditor->GetComponents())
+ || !AreComponentsDraggable(targetComponentEditor->GetComponents())
|| (globalRect.center().y() > GetWidgetGlobalRect(targetComponentEditor).center().y())))
{
if (targetItr == m_componentEditors.end() || targetComponentEditor == m_componentEditors.back() || !targetComponentEditor->isVisible())
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
index 677dc98277..9cd380ae06 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
@@ -211,6 +211,7 @@ namespace AzToolsFramework
// EntityPropertEditorRequestBus
void GetSelectedAndPinnedEntities(EntityIdList& selectedEntityIds) override;
void GetSelectedEntities(EntityIdList& selectedEntityIds) override;
+ void SetNewComponentId(AZ::ComponentId componentId) override;
bool IsEntitySelected(const AZ::EntityId& id) const;
bool IsSingleEntitySelected(const AZ::EntityId& id) const;
@@ -237,6 +238,9 @@ namespace AzToolsFramework
static bool DoesComponentPassFilter(const AZ::Component* component, const ComponentFilter& filter);
static bool IsComponentRemovable(const AZ::Component* component);
bool AreComponentsRemovable(const AZ::Entity::ComponentArrayType& components) const;
+ static AZStd::optional GetFixedComponentListIndex(const AZ::Component* component);
+ static bool IsComponentDraggable(const AZ::Component* component);
+ bool AreComponentsDraggable(const AZ::Entity::ComponentArrayType& components) const;
bool AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components) const;
void AddMenuOptionsForComponents(QMenu& menu, const QPoint& position);
@@ -568,6 +572,9 @@ namespace AzToolsFramework
void ConnectToEntityBuses(const AZ::EntityId& entityId);
void DisconnectFromEntityBuses(const AZ::EntityId& entityId);
+ //! Stores a component id to be focused on next time the UI updates.
+ AZStd::optional m_newComponentId;
+
private slots:
void OnPropertyRefreshRequired(); // refresh is needed for a property.
void UpdateContents();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
index 4e7a520698..ee95412376 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h
@@ -178,6 +178,24 @@ namespace AzToolsFramework
~ViewportInteractionRequests() = default;
};
+ /// Interface to return only viewport specific settings (e.g. snapping).
+ class ViewportSettings
+ {
+ public:
+ virtual ~ViewportSettings() = default;
+
+ /// Return if grid snapping is enabled.
+ virtual bool GridSnappingEnabled() const = 0;
+ /// Return the grid snapping size.
+ virtual float GridSize() const = 0;
+ /// Does the grid currently want to be displayed.
+ virtual bool ShowGrid() const = 0;
+ /// Return if angle snapping is enabled.
+ virtual bool AngleSnappingEnabled() const = 0;
+ /// Return the angle snapping/step size.
+ virtual float AngleStep() const = 0;
+ };
+
/// Type to inherit to implement ViewportInteractionRequests.
using ViewportInteractionRequestBus = AZ::EBus;
diff --git a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp
index 3017df737d..d0f93bfdf8 100644
--- a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp
+++ b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp
@@ -17,13 +17,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
#include
#include
@@ -55,7 +55,7 @@ namespace UnitTest
TEST(EntityPropertyEditorTests, PrioritySort_NonTransformAsFirstItem_TransformMovesToTopRemainderUnchanged)
{
- ComponentApplication app;
+ ToolsApplication app;
AZ::Entity::ComponentArrayType unorderedComponents;
AZ::Entity::ComponentArrayType orderedComponents;
@@ -68,12 +68,18 @@ namespace UnitTest
Entity* systemEntity = app.Create(desc, startupParams);
+ // Need to reflect the components so that edit attribute used for sorting, such as FixedComponentListIndex, get set.
+ app.RegisterComponentDescriptor(AzToolsFramework::Components::TransformComponent::CreateDescriptor());
+ app.RegisterComponentDescriptor(AzToolsFramework::Components::ScriptEditorComponent::CreateDescriptor());
+ app.RegisterComponentDescriptor(AZ::AssetManagerComponent::CreateDescriptor());
+
// Add more than 31 components, as we are testing the case where the sort fails when there are 32 or more items.
const int numFillerItems = 32;
for (int commentIndex = 0; commentIndex < numFillerItems; commentIndex++)
{
- unorderedComponents.insert(unorderedComponents.begin(), systemEntity->CreateComponent(AZ::StreamerComponent::RTTI_Type()));
+ unorderedComponents.insert(unorderedComponents.begin(), systemEntity->CreateComponent(
+ AzToolsFramework::Components::ScriptEditorComponent::RTTI_Type()));
}
// Add a TransformComponent at the end which should be sorted to the beginning by the priority sort.
diff --git a/Code/LauncherUnified/Platform/iOS/O3DEApplicationDelegate_iOS.mm b/Code/LauncherUnified/Platform/iOS/O3DEApplicationDelegate_iOS.mm
index ca7ab2def0..d78a83607b 100644
--- a/Code/LauncherUnified/Platform/iOS/O3DEApplicationDelegate_iOS.mm
+++ b/Code/LauncherUnified/Platform/iOS/O3DEApplicationDelegate_iOS.mm
@@ -19,7 +19,7 @@
#include // for AZ_MAX_PATH_LEN
-#include
+#include
#import
diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp
index d9344746a2..0b3ff87e43 100644
--- a/Code/Sandbox/Editor/EditorViewportWidget.cpp
+++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp
@@ -106,6 +106,15 @@ AZ_CVAR(
EditorViewportWidget* EditorViewportWidget::m_pPrimaryViewport = nullptr;
+namespace AzFramework
+{
+ extern InputChannelId CameraFreeLookButton;
+ extern InputChannelId CameraFreePanButton;
+ extern InputChannelId CameraOrbitLookButton;
+ extern InputChannelId CameraOrbitDollyButton;
+ extern InputChannelId CameraOrbitPanButton;
+}
+
#if AZ_TRAIT_OS_PLATFORM_APPLE
void StopFixedCursorMode();
void StartFixedCursorMode(QObject *viewport);
@@ -161,6 +170,7 @@ EditorViewportWidget::EditorViewportWidget(const QString& name, QWidget* parent)
, m_camFOV(gSettings.viewports.fDefaultFov)
, m_defaultViewName(name)
, m_renderViewport(nullptr) //m_renderViewport is initialized later, in SetViewportId
+ , m_editorViewportSettings(this)
{
// need this to be set in order to allow for language switching on Windows
setAttribute(Qt::WA_InputMethodEnabled);
@@ -1098,32 +1108,6 @@ AzFramework::CameraState EditorViewportWidget::GetCameraState()
return m_renderViewport->GetCameraState();
}
-bool EditorViewportWidget::GridSnappingEnabled()
-{
- return GetViewManager()->GetGrid()->IsEnabled();
-}
-
-float EditorViewportWidget::GridSize()
-{
- const CGrid* grid = GetViewManager()->GetGrid();
- return grid->scale * grid->size;
-}
-
-bool EditorViewportWidget::ShowGrid()
-{
- return gSettings.viewports.bShowGridGuide;
-}
-
-bool EditorViewportWidget::AngleSnappingEnabled()
-{
- return GetViewManager()->GetGrid()->IsAngleSnapEnabled();
-}
-
-float EditorViewportWidget::AngleStep()
-{
- return GetViewManager()->GetGrid()->GetAngleSnap();
-}
-
AZ::Vector3 EditorViewportWidget::PickTerrain(const AzFramework::ScreenPoint& point)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
@@ -1227,13 +1211,47 @@ void EditorViewportWidget::SetViewportId(int id)
if (ed_useNewCameraSystem)
{
AzFramework::ReloadCameraKeyBindings();
- m_renderViewport->GetControllerList()->Add(AZStd::make_shared());
+
+ auto controller = AZStd::make_shared();
+ controller->SetCameraListBuilderCallback([](AzFramework::Cameras& cameras)
+ {
+ auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::CameraFreeLookButton);
+ auto firstPersonPanCamera =
+ AZStd::make_shared(AzFramework::CameraFreePanButton, AzFramework::LookPan);
+ auto firstPersonTranslateCamera = AZStd::make_shared(AzFramework::LookTranslation);
+ auto firstPersonWheelCamera = AZStd::make_shared();
+
+ auto orbitCamera = AZStd::make_shared();
+ auto orbitRotateCamera = AZStd::make_shared(AzFramework::CameraOrbitLookButton);
+ auto orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation);
+ auto orbitDollyWheelCamera = AZStd::make_shared();
+ auto orbitDollyMoveCamera =
+ AZStd::make_shared(AzFramework::CameraOrbitDollyButton);
+ auto orbitPanCamera =
+ AZStd::make_shared(AzFramework::CameraOrbitPanButton, AzFramework::OrbitPan);
+
+ orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera);
+ orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera);
+ orbitCamera->m_orbitCameras.AddCamera(orbitDollyWheelCamera);
+ orbitCamera->m_orbitCameras.AddCamera(orbitDollyMoveCamera);
+ orbitCamera->m_orbitCameras.AddCamera(orbitPanCamera);
+
+ cameras.AddCamera(firstPersonRotateCamera);
+ cameras.AddCamera(firstPersonPanCamera);
+ cameras.AddCamera(firstPersonTranslateCamera);
+ cameras.AddCamera(firstPersonWheelCamera);
+ cameras.AddCamera(orbitCamera);
+ });
+
+ m_renderViewport->GetControllerList()->Add(controller);
}
else
{
m_renderViewport->GetControllerList()->Add(AZStd::make_shared());
}
+ m_renderViewport->SetViewportSettings(&m_editorViewportSettings);
+
UpdateScene();
if (m_pPrimaryViewport == this)
@@ -2853,4 +2871,35 @@ void EditorViewportWidget::SetAsActiveViewport()
}
}
+EditorViewportSettings::EditorViewportSettings(const EditorViewportWidget* editorViewportWidget)
+ : m_editorViewportWidget(editorViewportWidget)
+{
+}
+
+bool EditorViewportSettings::GridSnappingEnabled() const
+{
+ return m_editorViewportWidget->GetViewManager()->GetGrid()->IsEnabled();
+}
+
+float EditorViewportSettings::GridSize() const
+{
+ const CGrid* grid = m_editorViewportWidget->GetViewManager()->GetGrid();
+ return grid->scale * grid->size;
+}
+
+bool EditorViewportSettings::ShowGrid() const
+{
+ return gSettings.viewports.bShowGridGuide;
+}
+
+bool EditorViewportSettings::AngleSnappingEnabled() const
+{
+ return m_editorViewportWidget->GetViewManager()->GetGrid()->IsAngleSnapEnabled();
+}
+
+float EditorViewportSettings::AngleStep() const
+{
+ return m_editorViewportWidget->GetViewManager()->GetGrid()->GetAngleSnap();
+}
+
#include
diff --git a/Code/Sandbox/Editor/EditorViewportWidget.h b/Code/Sandbox/Editor/EditorViewportWidget.h
index 09474200f1..8675c035f6 100644
--- a/Code/Sandbox/Editor/EditorViewportWidget.h
+++ b/Code/Sandbox/Editor/EditorViewportWidget.h
@@ -65,6 +65,23 @@ namespace AzToolsFramework
class ManipulatorManager;
}
+class EditorViewportWidget;
+
+//! Viewport settings for the EditorViewportWidget
+struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::ViewportSettings
+{
+ explicit EditorViewportSettings(const EditorViewportWidget* editorViewportWidget);
+
+ bool GridSnappingEnabled() const override;
+ float GridSize() const override;
+ bool ShowGrid() const override;
+ bool AngleSnappingEnabled() const override;
+ float AngleStep() const override;
+
+private:
+ const EditorViewportWidget* m_editorViewportWidget = nullptr;
+};
+
// EditorViewportWidget window
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -189,13 +206,7 @@ public:
virtual void OnStartPlayInEditor();
virtual void OnStopPlayInEditor();
- // AzToolsFramework::ViewportInteractionRequestBus
AzFramework::CameraState GetCameraState();
- bool GridSnappingEnabled();
- float GridSize();
- bool ShowGrid();
- bool AngleSnappingEnabled();
- float AngleStep();
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition);
// AzToolsFramework::ViewportFreezeRequestBus
@@ -596,5 +607,7 @@ private:
AZ::Name m_defaultViewportContextName;
+ EditorViewportSettings m_editorViewportSettings;
+
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
diff --git a/Code/Sandbox/Editor/LegacyViewportCameraController.cpp b/Code/Sandbox/Editor/LegacyViewportCameraController.cpp
index 518b17f898..56bf986cfc 100644
--- a/Code/Sandbox/Editor/LegacyViewportCameraController.cpp
+++ b/Code/Sandbox/Editor/LegacyViewportCameraController.cpp
@@ -28,8 +28,8 @@
namespace SandboxEditor
{
-LegacyViewportCameraControllerInstance::LegacyViewportCameraControllerInstance(AzFramework::ViewportId viewportId)
- : AzFramework::MultiViewportControllerInstanceInterface(viewportId)
+LegacyViewportCameraControllerInstance::LegacyViewportCameraControllerInstance(AzFramework::ViewportId viewportId, LegacyViewportCameraController* controller)
+ : AzFramework::MultiViewportControllerInstanceInterface(viewportId, controller)
{
}
diff --git a/Code/Sandbox/Editor/LegacyViewportCameraController.h b/Code/Sandbox/Editor/LegacyViewportCameraController.h
index 129a2409da..84a8fe2301 100644
--- a/Code/Sandbox/Editor/LegacyViewportCameraController.h
+++ b/Code/Sandbox/Editor/LegacyViewportCameraController.h
@@ -28,11 +28,14 @@ namespace AzFramework
namespace SandboxEditor
{
+ class LegacyViewportCameraControllerInstance;
+ using LegacyViewportCameraController = AzFramework::MultiViewportController