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 da0a70b9cd..280c25bcf7 100644
--- a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake
@@ -43,5 +43,6 @@ set(GEM_DEPENDENCIES
Gem::GradientSignal
Gem::Vegetation
Gem::Atom_AtomBridge
+ Gem::NvCloth
Gem::Blast
)
diff --git a/AutomatedTesting/Gem/Code/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
index f0e73e8a11..fc50707c12 100644
--- a/AutomatedTesting/Gem/Code/tool_dependencies.cmake
+++ b/AutomatedTesting/Gem/Code/tool_dependencies.cmake
@@ -53,5 +53,6 @@ set(GEM_DEPENDENCIES
Gem::EMotionFX.Editor
Gem::ImGui.Editor
Gem::Atom_AtomBridge.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/editor/test_AssetPicker.py b/AutomatedTesting/Gem/PythonTests/editor/test_AssetPicker.py
index ac499d734f..90ca3690e4 100644
--- a/AutomatedTesting/Gem/PythonTests/editor/test_AssetPicker.py
+++ b/AutomatedTesting/Gem/PythonTests/editor/test_AssetPicker.py
@@ -42,6 +42,7 @@ class TestAssetPicker(object):
@pytest.mark.test_case_id("C13751579", "C1508814")
@pytest.mark.SUITE_periodic
+ @pytest.mark.xfail # ATOM-15493
def test_AssetPicker_UI_UX(self, request, editor, level, launcher_platform):
expected_lines = [
"TestEntity Entity successfully created",
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/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/Serialization/Json/ArraySerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.cpp
index 13a25e5aa6..d5a1730364 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.cpp
@@ -74,7 +74,7 @@ namespace AZ
"Unable to retrieve the correct container information for AZStd::array instance.");
}
- Flags flags = Flags::None;
+ ContinuationFlags flags = ContinuationFlags::None;
Uuid elementTypeId = Uuid::CreateNull();
auto typeEnumCallback = [&elementTypeId, &flags](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
{
@@ -82,7 +82,7 @@ namespace AZ
elementTypeId = genericClassElement->m_typeId;
if (genericClassElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
{
- flags = Flags::ResolvePointer;
+ flags = ContinuationFlags::ResolvePointer;
}
return false;
};
@@ -161,7 +161,7 @@ namespace AZ
"Not enough entries in JSON array to load an AZStd::array from.");
}
- Flags flags = Flags::None;
+ ContinuationFlags flags = ContinuationFlags::None;
Uuid elementTypeId = Uuid::CreateNull();
auto typeEnumCallback = [&elementTypeId, &flags](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
{
@@ -169,7 +169,7 @@ namespace AZ
elementTypeId = genericClassElement->m_typeId;
if (genericClassElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
{
- flags = Flags::ResolvePointer;
+ flags = ContinuationFlags::ResolvePointer;
}
return false;
};
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp
index 6c67fd284a..9a426a1e59 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp
@@ -208,22 +208,28 @@ namespace AZ
// BaseJsonSerializer
//
- JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoading(void* object, const Uuid& typeId, const rapidjson::Value& value,
- JsonDeserializerContext& context, Flags flags)
+ BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const
{
- return flags & Flags::ResolvePointer ?
- JsonDeserializer::LoadToPointer(object, typeId, value, context) :
- JsonDeserializer::Load(object, typeId, value, context);
+ return OperationFlags::None;
}
- JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(rapidjson::Value& output, const void* object,
- const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context, Flags flags)
+ JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoading(
+ void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context, ContinuationFlags flags)
+ {
+ return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer
+ ? JsonDeserializer::LoadToPointer(object, typeId, value, context)
+ : JsonDeserializer::Load(object, typeId, value, context);
+ }
+
+ JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(
+ rapidjson::Value& output, const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context,
+ ContinuationFlags flags)
{
using namespace JsonSerializationResult;
- if (flags & Flags::ReplaceDefault && !context.ShouldKeepDefaults())
+ if ((flags & ContinuationFlags::ReplaceDefault) == ContinuationFlags::ReplaceDefault && !context.ShouldKeepDefaults())
{
- if (flags & Flags::ResolvePointer)
+ if ((flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer)
{
return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, context);
}
@@ -248,7 +254,7 @@ namespace AZ
}
}
- return flags & Flags::ResolvePointer ?
+ return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer ?
JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, context) :
JsonSerializer::Store(output, object, defaultObject, typeId, context);
}
@@ -265,8 +271,9 @@ namespace AZ
return JsonSerializer::StoreTypeName(output, typeId, context);
}
- JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoadingFromJsonObjectField(void* object, const Uuid& typeId, const rapidjson::Value& value,
- rapidjson::Value::StringRefType memberName, JsonDeserializerContext& context, Flags flags)
+ JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoadingFromJsonObjectField(
+ void* object, const Uuid& typeId, const rapidjson::Value& value, rapidjson::Value::StringRefType memberName,
+ JsonDeserializerContext& context, ContinuationFlags flags)
{
using namespace JsonSerializationResult;
@@ -291,7 +298,7 @@ namespace AZ
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoringToJsonObjectField(rapidjson::Value& output,
rapidjson::Value::StringRefType newMemberName, const void* object, const void* defaultObject,
- const Uuid& typeId, JsonSerializerContext& context, Flags flags)
+ const Uuid& typeId, JsonSerializerContext& context, ContinuationFlags flags)
{
using namespace JsonSerializationResult;
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h
index f6ced44583..06c5eda6de 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h
@@ -161,13 +161,19 @@ namespace AZ
public:
AZ_RTTI(BaseJsonSerializer, "{7291FFDC-D339-40B5-BB26-EA067A327B21}");
- enum Flags
+ enum class ContinuationFlags
{
- None = 0, //! No extra flags.
+ None = 0, //! No extra flags.
ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
ReplaceDefault = 1 << 1 //! The default value provided for storing will be replaced with a newly created one.
};
+ enum class OperationFlags
+ {
+ None = 0, //! No flags that control how the custom json serializer is used.
+ ManualDefault = 1 << 0 //! Even if an (explicit) default is found the custom json serializer will still be called.
+ };
+
virtual ~BaseJsonSerializer() = default;
//! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported.
@@ -180,6 +186,9 @@ namespace AZ
virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context) = 0;
+ //! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used.
+ virtual OperationFlags GetOperationsFlags() const;
+
protected:
//! Continues loading of a (sub)value. Use this function to load member variables for instance. This is more optimal than
//! directly calling the json serialization.
@@ -187,8 +196,9 @@ namespace AZ
//! @param typeId Type id of the object passed in.
//! @param value The value in the JSON document where the deserializer will start reading data from.
//! @param context The context used during deserialization. Use the value passed in from Load.
- JsonSerializationResult::ResultCode ContinueLoading(void* object, const Uuid& typeId, const rapidjson::Value& value,
- JsonDeserializerContext& context, Flags flags = Flags::None);
+ JsonSerializationResult::ResultCode ContinueLoading(
+ void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context,
+ ContinuationFlags flags = ContinuationFlags::None);
//! Continues storing of a (sub)value. Use this function to store member variables for instance. This is more optimal than
//! directly calling the json serialization.
@@ -200,8 +210,9 @@ namespace AZ
//! the settings.
//! @param typeId The type id of the object and default object.
//! @param context The context used during serialization. Use the value passed in from Store.
- JsonSerializationResult::ResultCode ContinueStoring(rapidjson::Value& output, const void* object, const void* defaultObject,
- const Uuid& typeId, JsonSerializerContext& context, Flags flags = Flags::None);
+ JsonSerializationResult::ResultCode ContinueStoring(
+ rapidjson::Value& output, const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context,
+ ContinuationFlags flags = ContinuationFlags::None);
//! Retrieves the type id from a json object or json string.
//! @param typeId The retrieved type id.
@@ -222,12 +233,14 @@ namespace AZ
const Uuid& typeId, JsonSerializerContext& context);
//! Helper function similar to ContinueLoading, but loads the data as a member of 'value' rather than 'value' itself, if it exists.
- JsonSerializationResult::ResultCode ContinueLoadingFromJsonObjectField(void* object, const Uuid& typeId, const rapidjson::Value& value,
- rapidjson::Value::StringRefType memberName, JsonDeserializerContext& context, Flags flags = Flags::None);
+ JsonSerializationResult::ResultCode ContinueLoadingFromJsonObjectField(
+ void* object, const Uuid& typeId, const rapidjson::Value& value, rapidjson::Value::StringRefType memberName,
+ JsonDeserializerContext& context, ContinuationFlags flags = ContinuationFlags::None);
//! Helper function similar to ContinueStoring, but stores the data as a member of 'output' rather than overwriting 'output'.
- JsonSerializationResult::ResultCode ContinueStoringToJsonObjectField(rapidjson::Value& output, rapidjson::Value::StringRefType newMemberName,
- const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context, Flags flags = Flags::None);
+ JsonSerializationResult::ResultCode ContinueStoringToJsonObjectField(
+ rapidjson::Value& output, rapidjson::Value::StringRefType newMemberName, const void* object, const void* defaultObject,
+ const Uuid& typeId, JsonSerializerContext& context, ContinuationFlags flags = ContinuationFlags::None);
//! Checks if a value is an explicit default. This useful for containers where not storing anything as a default would mean
//! a slot wouldn't be used so something has to be added to represent the fully default target.
@@ -238,6 +251,7 @@ namespace AZ
rapidjson::Value GetExplicitDefault();
};
- AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::Flags)
+ AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::ContinuationFlags)
+ AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::OperationFlags)
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp
index c15cb9ef54..400a3b7949 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp
@@ -75,9 +75,10 @@ namespace AZ
auto elementCallback = [this, &array, &retVal, &index, &context]
(void* elementPtr, const Uuid& elementId, const SerializeContext::ClassData*, const SerializeContext::ClassElement* classElement)
{
- Flags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
- Flags::ResolvePointer : Flags::None;
- flags |= Flags::ReplaceDefault;
+ ContinuationFlags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
+ ? ContinuationFlags::ResolvePointer
+ : ContinuationFlags::None;
+ flags |= ContinuationFlags::ReplaceDefault;
ScopedContextPath subPath(context, index);
index++;
@@ -161,8 +162,9 @@ namespace AZ
container->EnumTypes(typeEnumCallback);
AZ_Assert(classElement, "No class element found for the type in the basic container.");
- Flags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
- Flags::ResolvePointer : Flags::None;
+ ContinuationFlags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
+ ? ContinuationFlags::ResolvePointer
+ : ContinuationFlags::None;
const size_t capacity = container->IsFixedCapacity() ? container->Capacity(outputValue) : std::numeric_limits::max();
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp
index 8d0da9e54a..93d12acba3 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp
@@ -22,6 +22,19 @@
namespace AZ
{
+ JsonSerializationResult::ResultCode JsonDeserializer::DeserializerDefaultCheck(BaseJsonSerializer* serializer, void* object,
+ const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ bool isExplicitDefault = IsExplicitDefault(value);
+ bool manuallyDefaults = (serializer->GetOperationsFlags() & BaseJsonSerializer::OperationFlags::ManualDefault) ==
+ BaseJsonSerializer::OperationFlags::ManualDefault;
+ return !isExplicitDefault || (isExplicitDefault && manuallyDefaults)
+ ? serializer->Load(object, typeId, value, context)
+ : context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
+ }
+
JsonSerializationResult::ResultCode JsonDeserializer::Load(void* object, const Uuid& typeId, const rapidjson::Value& value,
JsonDeserializerContext& context)
{
@@ -33,17 +46,12 @@ namespace AZ
"Target object for Json Serialization is pointing to nothing during loading.");
}
- if (IsExplicitDefault(value))
- {
- return context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
- }
-
BaseJsonSerializer* serializer = context.GetRegistrationContext()->GetSerializerForType(typeId);
if (serializer)
{
- return serializer->Load(object, typeId, value, context);
+ return DeserializerDefaultCheck(serializer, object, typeId, value, context);
}
-
+
const SerializeContext::ClassData* classData = context.GetSerializeContext()->FindClassData(typeId);
if (!classData)
{
@@ -56,9 +64,14 @@ namespace AZ
serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId());
if (serializer)
{
- return serializer->Load(object, typeId, value, context);
+ return DeserializerDefaultCheck(serializer, object, typeId, value, context);
}
}
+
+ if (IsExplicitDefault(value))
+ {
+ return context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
+ }
if (classData->m_azRtti && (classData->m_azRtti->GetTypeTraits() & AZ::TypeTraits::is_enum) == AZ::TypeTraits::is_enum)
{
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h
index 89e527b9ae..5954082ee0 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h
@@ -113,5 +113,13 @@ namespace AZ
//! Checks if a value is an explicit default. This means the value is an object with no members.
static bool IsExplicitDefault(const rapidjson::Value& value);
+
+ private:
+ static JsonSerializationResult::ResultCode DeserializerDefaultCheck(
+ BaseJsonSerializer* serializer,
+ void* object,
+ const Uuid& typeId,
+ const rapidjson::Value& value,
+ JsonDeserializerContext& context);
};
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp
index fa244d3dae..437a648e1e 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp
@@ -215,10 +215,10 @@ namespace AZ
// Load key
void* keyAddress = pairContainer->GetElementByIndex(address, pairElement, 0);
AZ_Assert(keyAddress, "Element reserved for associative container, but unable to retrieve address of the key.");
- Flags keyLoadFlags = Flags::None;
+ ContinuationFlags keyLoadFlags = ContinuationFlags::None;
if (keyElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
{
- keyLoadFlags = Flags::ResolvePointer;
+ keyLoadFlags = ContinuationFlags::ResolvePointer;
*reinterpret_cast(keyAddress) = nullptr;
}
JSR::ResultCode keyResult = ContinueLoading(keyAddress, keyElement->m_typeId, key, context, keyLoadFlags);
@@ -231,10 +231,10 @@ namespace AZ
// Load value
void* valueAddress = pairContainer->GetElementByIndex(address, pairElement, 1);
AZ_Assert(valueAddress, "Element reserved for associative container, but unable to retrieve address of the value.");
- Flags valueLoadFlags = Flags::None;
+ ContinuationFlags valueLoadFlags = ContinuationFlags::None;
if (valueElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
{
- valueLoadFlags = Flags::ResolvePointer;
+ valueLoadFlags = ContinuationFlags::ResolvePointer;
*reinterpret_cast(valueAddress) = nullptr;
}
JSR::ResultCode valueResult = ContinueLoading(valueAddress, valueElement->m_typeId, value, context, valueLoadFlags);
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.cpp
index 9e707f8644..0ab32ac08d 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.cpp
@@ -82,7 +82,7 @@ namespace AZ
{
// If the target type is the same as the type already stored in the smart pointer than no new
// instance is created and the existing instance will be updated with the data in the json document.
- result = ContinueLoading(instance, elementClassId, inputValue, context, Flags::ResolvePointer);
+ result = ContinueLoading(instance, elementClassId, inputValue, context, ContinuationFlags::ResolvePointer);
return false;
}
}
@@ -93,7 +93,7 @@ namespace AZ
// the wrong address. In these cases explicitly reset the smart pointer. This will erase the existing
// data but that's fine as it's not being used.
void* element = nullptr;
- result = ContinueLoading(&element, elementClassId, inputValue, context, Flags::ResolvePointer);
+ result = ContinueLoading(&element, elementClassId, inputValue, context, ContinuationFlags::ResolvePointer);
if (result.GetProcessing() != JSR::Processing::Halted && result.GetProcessing() != JSR::Processing::Altered)
{
void* elementPtr = container->ReserveElement(instance, nullptr);
@@ -155,8 +155,14 @@ namespace AZ
container->EnumElements(const_cast(defaultValue), defaultInputCallback);
}
- JSR::ResultCode result = ContinueStoring(outputValue, inputValue, defaultValue, inputPtrType, context, Flags::ResolvePointer);
+ JSR::ResultCode result =
+ ContinueStoring(outputValue, inputValue, defaultValue, inputPtrType, context, ContinuationFlags::ResolvePointer);
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ?
"Successfully processed smart pointer." : "A problem occurred while processing a smart pointer.");
}
+
+ BaseJsonSerializer::OperationFlags JsonSmartPointerSerializer::GetOperationsFlags() const
+ {
+ return OperationFlags::ManualDefault;
+ }
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.h
index 8c550cb824..9a0cf61be9 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/SmartPointerSerializer.h
@@ -28,5 +28,7 @@ namespace AZ
JsonDeserializerContext& context) override;
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context) override;
+
+ OperationFlags GetOperationsFlags() const override;
};
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp
index 9ea22592bc..5b43cec817 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp
@@ -99,8 +99,9 @@ namespace AZ
ScopedContextPath subPath(context, i);
- Flags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
- Flags::ResolvePointer : Flags::None;
+ ContinuationFlags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
+ ? ContinuationFlags::ResolvePointer
+ : ContinuationFlags::None;
JSR::ResultCode result = ContinueStoring(elementValues[i], elementAddress, defaultElementAddress,
classElements[i]->m_typeId, context, flags);
@@ -179,8 +180,9 @@ namespace AZ
void* elementAddress = container->GetElementByIndex(outputValue, nullptr, i);
AZ_Assert(elementAddress, "Address of AZStd::pair or AZStd::tuple element %zu could not be retrieved.", i);
- Flags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
- Flags::ResolvePointer : Flags::None;
+ ContinuationFlags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
+ ? ContinuationFlags::ResolvePointer
+ : ContinuationFlags::None;
while (arrayIndex < inputValue.Size())
{
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/AssetJsonSerializerTests.cpp b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp
index a494207850..e44f77b119 100644
--- a/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp
+++ b/Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp
@@ -104,6 +104,11 @@ namespace JsonSerializationTests
AZ::AllocatorInstance::Destroy();
}
+ void Reflect(AZStd::unique_ptr& context) override
+ {
+ context->RegisterGenericType();
+ }
+
AZStd::shared_ptr CreateSerializer() override
{
return AZStd::make_shared();
diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/BaseJsonSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/BaseJsonSerializerTests.cpp
index 08de21b54f..47e05997fc 100644
--- a/Code/Framework/AzCore/Tests/Serialization/Json/BaseJsonSerializerTests.cpp
+++ b/Code/Framework/AzCore/Tests/Serialization/Json/BaseJsonSerializerTests.cpp
@@ -119,7 +119,8 @@ namespace JsonSerializationTests
int value = 0;
int* ptrValue = &value;
- ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
+ ResultCode result =
+ ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_NE(nullptr, ptrValue);
@@ -134,7 +135,8 @@ namespace JsonSerializationTests
json.Set(42);
int* ptrValue = nullptr;
- ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
+ ResultCode result =
+ ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_NE(nullptr, ptrValue);
@@ -150,7 +152,8 @@ namespace JsonSerializationTests
rapidjson::Value json(rapidjson::kObjectType);
int* ptrValue = nullptr;
- ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
+ ResultCode result =
+ ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_NE(nullptr, ptrValue);
@@ -165,7 +168,8 @@ namespace JsonSerializationTests
rapidjson::Value json(rapidjson::kNullType);
int* ptrValue = reinterpret_cast(azmalloc(sizeof(int), alignof(int), AZ::SystemAllocator));
- ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
+ ResultCode result =
+ ContinueLoading(&ptrValue, azrtti_typeid(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_EQ(nullptr, ptrValue);
@@ -194,8 +198,8 @@ namespace JsonSerializationTests
int value = 42;
int* ptrValue = &value;
- ResultCode result = ContinueStoring(*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid(), *m_jsonSerializationContext,
- Flags::ResolvePointer);
+ ResultCode result = ContinueStoring(
+ *m_jsonDocument, &ptrValue, nullptr, azrtti_typeid(), *m_jsonSerializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("42");
@@ -210,8 +214,9 @@ namespace JsonSerializationTests
int value2 = 42;
int* defaultPtrValue = &value2;
- ResultCode result =
- ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext, Flags::ResolvePointer);
+ ResultCode result = ContinueStoring(
+ *m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext,
+ ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("{}");
@@ -224,7 +229,7 @@ namespace JsonSerializationTests
int* ptrValue = nullptr;
ResultCode result = ContinueStoring(
- *m_jsonDocument, &ptrValue, nullptr, azrtti_typeid(), *m_jsonSerializationContext, Flags::ResolvePointer);
+ *m_jsonDocument, &ptrValue, nullptr, azrtti_typeid(), *m_jsonSerializationContext, ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
@@ -238,8 +243,9 @@ namespace JsonSerializationTests
int value2 = 42;
int* defaultPtrValue = &value2;
- ResultCode result =
- ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext, Flags::ResolvePointer);
+ ResultCode result = ContinueStoring(
+ *m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext,
+ ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
@@ -252,8 +258,9 @@ namespace JsonSerializationTests
int* ptrValue = nullptr;
int* defaultPtrValue = nullptr;
- ResultCode result =
- ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext, Flags::ResolvePointer);
+ ResultCode result = ContinueStoring(
+ *m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid(), *m_jsonSerializationContext,
+ ContinuationFlags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
@@ -265,8 +272,8 @@ namespace JsonSerializationTests
int value = 42;
- ResultCode result = ContinueStoring(*m_jsonDocument, &value, nullptr, azrtti_typeid(), *m_jsonSerializationContext,
- Flags::ReplaceDefault);
+ ResultCode result = ContinueStoring(
+ *m_jsonDocument, &value, nullptr, azrtti_typeid(), *m_jsonSerializationContext, ContinuationFlags::ReplaceDefault);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("42");
@@ -280,7 +287,7 @@ namespace JsonSerializationTests
int* ptrValue = &value;
ResultCode result = ContinueStoring(*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid(), *m_jsonSerializationContext,
- Flags::ResolvePointer | Flags::ReplaceDefault);
+ ContinuationFlags::ResolvePointer | ContinuationFlags::ReplaceDefault);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("42");
@@ -293,8 +300,8 @@ namespace JsonSerializationTests
int value = 42;
AZ::Uuid unknownType("{09AE3CEC-EBFC-41EC-A7F6-949721521716}");
- ResultCode result = ContinueStoring(*m_jsonDocument, &value, nullptr, unknownType, *m_jsonSerializationContext,
- Flags::ReplaceDefault);
+ ResultCode result =
+ ContinueStoring(*m_jsonDocument, &value, nullptr, unknownType, *m_jsonSerializationContext, ContinuationFlags::ReplaceDefault);
EXPECT_EQ(Processing::Halted, result.GetProcessing());
}
diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h b/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
index 4f0825ff1b..c0f470378c 100644
--- a/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
+++ b/Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
@@ -90,9 +90,14 @@ namespace JsonSerializationTests
virtual ~JsonSerializerConformityTestDescriptor() = default;
virtual AZStd::shared_ptr CreateSerializer() = 0;
-
+
//! Create an instance of the target type with all values set to default.
virtual AZStd::shared_ptr CreateDefaultInstance() = 0;
+ //! Create an instance of the target type that constructed with default constructor.
+ //! This will be the same instance that Json Serialization creates for dynamic types. Typically it's the same
+ //! as from CreateDefaultInstance(), except of types, such as pointers, that need to do minimal (de)serialization
+ //! to initialize an object.
+ virtual AZStd::shared_ptr CreateDefaultConstructedInstance() { return CreateDefaultInstance(); }
//! Create an instance of the target type with some values set and some kept on defaults.
//! If the target type doesn't support partial specialization this can be ignored and
//! tests for partial support will be skipped.
@@ -316,10 +321,10 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto original = this->m_description.CreateDefaultInstance();
- ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*original),
+ ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
if (this->m_features.m_mandatoryFields.empty())
@@ -339,6 +344,42 @@ namespace JsonSerializationTests
}
}
+ TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeEmptyObjectThroughMainLoad_SucceedsAndObjectMatchesDefaults)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ if (this->m_features.SupportsJsonType(rapidjson::kObjectType))
+ {
+ this->m_jsonDocument->Parse("{}");
+ ASSERT_FALSE(this->m_jsonDocument->HasParseError());
+
+ auto serializer = this->m_description.CreateSerializer();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
+ auto original = this->m_description.CreateDefaultInstance();
+
+ AZ::JsonDeserializerSettings settings;
+ settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
+ settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
+ ResultCode result = AZ::JsonSerialization::Load(
+ instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, settings);
+
+ if (this->m_features.m_mandatoryFields.empty())
+ {
+ EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+ EXPECT_EQ(Processing::Completed, result.GetProcessing());
+ }
+ else
+ {
+ EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome());
+ bool validProcessing =
+ result.GetProcessing() == Processing::Altered ||
+ result.GetProcessing() == Processing::PartialAlter;
+ EXPECT_TRUE(validProcessing);
+ }
+ EXPECT_TRUE(this->m_description.AreEqual(*original, *instance));
+ }
+ }
+
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeEmptyArray_SucceedsAndObjectMatchesDefaults)
{
using namespace AZ::JsonSerializationResult;
@@ -349,7 +390,7 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto original = this->m_description.CreateDefaultInstance();
this->m_deserializationSettings->m_clearContainers = false;
@@ -384,7 +425,7 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto original = this->m_description.CreateDefaultInstance();
this->m_deserializationSettings->m_clearContainers = true;
@@ -488,7 +529,7 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto compare = this->m_description.CreateFullySetInstance();
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
@@ -499,6 +540,28 @@ namespace JsonSerializationTests
EXPECT_TRUE(this->m_description.AreEqual(*instance, *compare));
}
+ TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeFullySetInstanceThroughMainLoad_SucceedsAndObjectMatchesFullySetInstance)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ AZStd::string_view json = this->m_description.GetJsonFor_Load_DeserializeFullySetInstance();
+ this->m_jsonDocument->Parse(json.data());
+ ASSERT_FALSE(this->m_jsonDocument->HasParseError());
+
+ auto serializer = this->m_description.CreateSerializer();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
+ auto compare = this->m_description.CreateFullySetInstance();
+
+ AZ::JsonDeserializerSettings settings;
+ settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
+ settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
+ ResultCode result = AZ::JsonSerialization::Load(instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, settings);
+
+ EXPECT_EQ(Outcomes::Success, result.GetOutcome());
+ EXPECT_EQ(Processing::Completed, result.GetProcessing());
+ EXPECT_TRUE(this->m_description.AreEqual(*instance, *compare));
+ }
+
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeWithMissingMandatoryField_LoadFailedAndUnsupportedReported)
{
using namespace AZ::JsonSerializationResult;
@@ -518,7 +581,7 @@ namespace JsonSerializationTests
ASSERT_NE(this->m_jsonDocument->MemberEnd(), memberToErase);
this->m_jsonDocument->RemoveMember(memberToErase);
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
@@ -546,7 +609,7 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto compare = this->m_description.CreatePartialDefaultInstance();
ASSERT_NE(nullptr, compare);
@@ -567,7 +630,7 @@ namespace JsonSerializationTests
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
AZ::ScopedContextReporter reporter(*this->m_jsonDeserializationContext,
[](AZStd::string_view message, ResultCode result, AZStd::string_view path) -> ResultCode
@@ -604,7 +667,7 @@ namespace JsonSerializationTests
}
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
auto compare = this->m_description.CreateFullySetInstance();
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
@@ -635,7 +698,7 @@ namespace JsonSerializationTests
}
auto serializer = this->m_description.CreateSerializer();
- auto instance = this->m_description.CreateDefaultInstance();
+ auto instance = this->m_description.CreateDefaultConstructedInstance();
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
@@ -693,6 +756,36 @@ namespace JsonSerializationTests
}
}
+ TYPED_TEST_P(JsonSerializerConformityTests, Store_SerializeDefaultInstanceThroughMainStore_EmptyJsonReturned)
+ {
+ using namespace AZ::JsonSerializationResult;
+
+ auto serializer = this->m_description.CreateSerializer();
+ auto instance = this->m_description.CreateDefaultInstance();
+ rapidjson::Value convertedValue = this->CreateExplicitDefault();
+
+ AZ::JsonSerializerSettings settings;
+ settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
+ settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
+ ResultCode result = AZ::JsonSerialization::Store(
+ convertedValue, this->m_jsonDocument->GetAllocator(), instance.get(), instance.get(), azrtti_typeid(*instance), settings);
+
+ EXPECT_EQ(Processing::Completed, result.GetProcessing());
+ if (convertedValue.IsObject() && !this->m_features.m_mandatoryFields.empty())
+ {
+ ASSERT_EQ(convertedValue.MemberCount(), this->m_features.m_mandatoryFields.size());
+ for (const AZStd::string& mandatoryField : this->m_features.m_mandatoryFields)
+ {
+ EXPECT_NE(convertedValue.MemberEnd(), convertedValue.FindMember(mandatoryField.c_str()));
+ }
+ }
+ else
+ {
+ EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+ this->Expect_ExplicitDefault(convertedValue);
+ }
+ }
+
TYPED_TEST_P(JsonSerializerConformityTests, Store_SerializeWithDefaultsKept_FullyWrittenJson)
{
using namespace AZ::JsonSerializationResult;
@@ -924,6 +1017,20 @@ namespace JsonSerializationTests
}
}
+ TYPED_TEST_P(JsonSerializerConformityTests, GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared)
+ {
+ if (this->m_features.SupportsJsonType(rapidjson::kObjectType))
+ {
+ if (!this->m_features.m_mandatoryFields.empty())
+ {
+ auto serializer = this->m_description.CreateSerializer();
+ bool manuallyHandlesDefaults = (serializer->GetOperationsFlags() & AZ::BaseJsonSerializer::OperationFlags::ManualDefault) ==
+ AZ::BaseJsonSerializer::OperationFlags::ManualDefault;
+ EXPECT_TRUE(manuallyHandlesDefaults);
+ }
+ }
+ }
+
REGISTER_TYPED_TEST_CASE_P(JsonSerializerConformityTests,
Registration_SerializerIsRegisteredWithContext_SerializerFound,
@@ -934,14 +1041,16 @@ namespace JsonSerializationTests
Load_InvalidTypeOfArrayType_ReturnsUnsupported,
Load_InvalidTypeOfStringType_ReturnsUnsupported,
Load_InvalidTypeOfNumberType_ReturnsUnsupported,
-
+
Load_DeserializeUnreflectedType_ReturnsUnsupported,
Load_DeserializeEmptyObject_SucceedsAndObjectMatchesDefaults,
+ Load_DeserializeEmptyObjectThroughMainLoad_SucceedsAndObjectMatchesDefaults,
Load_DeserializeEmptyArray_SucceedsAndObjectMatchesDefaults,
Load_DeserializeEmptyArrayWithClearEnabled_SucceedsAndObjectMatchesDefaults,
Load_DeserializeEmptyArrayWithClearedTarget_SucceedsAndObjectMatchesDefaults,
Load_InterruptClearingTarget_ContainerIsNotCleared,
Load_DeserializeFullySetInstance_SucceedsAndObjectMatchesFullySetInstance,
+ Load_DeserializeFullySetInstanceThroughMainLoad_SucceedsAndObjectMatchesFullySetInstance,
Load_DeserializePartialInstance_SucceedsAndObjectMatchesParialInstance,
Load_DeserializeWithMissingMandatoryField_LoadFailedAndUnsupportedReported,
Load_InsertAdditionalData_SucceedsAndObjectMatchesFullySetInstance,
@@ -950,6 +1059,7 @@ namespace JsonSerializationTests
Store_SerializeUnreflectedType_ReturnsUnsupported,
Store_SerializeDefaultInstance_EmptyJsonReturned,
+ Store_SerializeDefaultInstanceThroughMainStore_EmptyJsonReturned,
Store_SerializeWithDefaultsKept_FullyWrittenJson,
Store_SerializeFullySetInstance_StoredSuccessfullyAndJsonMatches,
Store_SerializeWithoutDefault_StoredSuccessfullyAndJsonMatches,
@@ -957,10 +1067,12 @@ namespace JsonSerializationTests
Store_SerializePartialInstance_StoredSuccessfullyAndJsonMatches,
Store_SerializeEmptyArray_StoredSuccessfullyAndJsonMatches,
Store_HaltedThroughCallback_StoreFailsAndHaltReported,
-
+
StoreLoad_RoundTripWithPartialDefault_IdenticalInstances,
StoreLoad_RoundTripWithFullSet_IdenticalInstances,
- StoreLoad_RoundTripWithDefaultsKept_IdenticalInstances);
+ StoreLoad_RoundTripWithDefaultsKept_IdenticalInstances,
+
+ GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared);
} // namespace JsonSerializationTests
namespace AZ
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/Serialization/Json/SmartPointerSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/SmartPointerSerializerTests.cpp
index 2fc131aae2..75391d81d4 100644
--- a/Code/Framework/AzCore/Tests/Serialization/Json/SmartPointerSerializerTests.cpp
+++ b/Code/Framework/AzCore/Tests/Serialization/Json/SmartPointerSerializerTests.cpp
@@ -32,6 +32,11 @@ namespace JsonSerializationTests
return AZStd::make_shared();
}
+ AZStd::shared_ptr CreateDefaultConstructedInstance() override
+ {
+ return AZStd::make_shared();
+ }
+
void Reflect(AZStd::unique_ptr& context) override
{
context->RegisterGenericType();
@@ -228,13 +233,19 @@ namespace JsonSerializationTests
public:
using SmartPointer = typename SmartPointerSimpleDerivedClassTestDescription::SmartPointer;
- AZStd::shared_ptr CreateDefaultInstance() override
+ // This test is specific for derived classes being used as a default value.
+ AZStd::shared_ptr CreateDefaultConstructedInstance() override
{
auto result = AZStd::make_shared();
*result = SmartPointer(aznew SimpleInheritence());
return result;
}
+ AZStd::shared_ptr CreateDefaultInstance() override
+ {
+ return CreateDefaultConstructedInstance();
+ }
+
AZStd::string_view GetJsonForPartialDefaultInstance() override
{
return R"(
@@ -386,13 +397,19 @@ namespace JsonSerializationTests
public:
using SmartPointer = typename SmartPointerComplexDerivedClassTestDescription::SmartPointer;
- AZStd::shared_ptr CreateDefaultInstance() override
+ // This test is specific for derived classes being used as a default value.
+ AZStd::shared_ptr CreateDefaultConstructedInstance() override
{
auto result = AZStd::make_shared();
*result = SmartPointer(aznew MultipleInheritence());
return result;
}
+ AZStd::shared_ptr CreateDefaultInstance() override
+ {
+ return CreateDefaultConstructedInstance();
+ }
+
AZStd::string_view GetJsonForPartialDefaultInstance() override
{
return R"(
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/ShapeConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp
index 52eae22fee..a535f5f65d 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp
@@ -48,6 +48,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("Radius", &SphereShapeConfiguration::m_radius)
@@ -76,6 +79,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("Configuration", &BoxShapeConfiguration::m_dimensions)
@@ -104,6 +110,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("Height", &CapsuleShapeConfiguration::m_height)
@@ -153,6 +162,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("PhysicsAsset", &PhysicsAssetShapeConfiguration::m_asset)
@@ -185,6 +197,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("Scale", &NativeShapeConfiguration::m_nativeShapeScale)
@@ -208,6 +223,9 @@ namespace Physics
{
if (auto serializeContext = azrtti_cast(context))
{
+ serializeContext
+ ->RegisterGenericType>();
+
serializeContext->Class()
->Version(1)
->Field("CookedData", &CookedMeshShapeConfiguration::m_cookedData)
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/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/Entity/EditorEntityModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp
index 9caca69b34..ef6d0fe1f8 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.cpp
@@ -117,8 +117,6 @@ namespace AzToolsFramework
{
EditorEntityModel::EditorEntityModel()
{
- AzFramework::ApplicationRequests::Bus::BroadcastResult(m_isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
-
EntityCompositionNotificationBus::Handler::BusConnect();
EditorOnlyEntityComponentNotificationBus::Handler::BusConnect();
EditorEntityRuntimeActivationChangeNotificationBus::Handler::BusConnect();
@@ -565,7 +563,7 @@ namespace AzToolsFramework
{
//retrieve or add an entity entry to the table
//the entry must exist, even if not connected, so children and other data can be assigned
- [[maybe_unused]] auto [it, inserted] = m_entityInfoTable.try_emplace(entityId, m_isPrefabEnabled);
+ [[maybe_unused]] auto [it, inserted] = m_entityInfoTable.try_emplace(entityId);
auto& entityInfo = it->second;
//the entity id defaults to invalid and must be set to match the requested id
@@ -882,11 +880,6 @@ namespace AzToolsFramework
}
}
- EditorEntityModel::EditorEntityModelEntry::EditorEntityModelEntry(bool isPrefabEnabled)
- : m_isPrefabEnabled(isPrefabEnabled)
- {
- }
-
EditorEntityModel::EditorEntityModelEntry::~EditorEntityModelEntry()
{
Disconnect();
@@ -1213,29 +1206,15 @@ namespace AzToolsFramework
auto childItr = m_childIndexCache.find(childId);
if (childItr != m_childIndexCache.end())
{
- if (m_isPrefabEnabled)
- {
- // Take the last entry and move it into the removed spot instead of deleting the entry and having to move all
- // following entries one step down.
- AZ::EntityId backEntity = m_children.back();
- m_children[childItr->second] = backEntity;
- // Update cached index for the moved id to the new index.
- m_childIndexCache[backEntity] = childItr->second;
- // Now remove the deleted id from the children and cache.
- m_childIndexCache.erase(childId);
- m_children.erase(m_children.end() - 1);
- }
- else
- {
- m_children.erase(m_children.begin() + childItr->second);
-
- // rebuild index cache for faster lookup
- m_childIndexCache.clear();
- for (auto childIdToCache : m_children)
- {
- m_childIndexCache[childIdToCache] = static_cast(m_childIndexCache.size());
- }
- }
+ // Take the last entry and move it into the removed spot instead of deleting the entry and having to move all
+ // following entries one step down.
+ AZ::EntityId backEntity = m_children.back();
+ m_children[childItr->second] = backEntity;
+ // Update cached index for the moved id to the new index.
+ m_childIndexCache[backEntity] = childItr->second;
+ // Now remove the deleted id from the children and cache.
+ m_childIndexCache.erase(childId);
+ m_children.erase(m_children.end() - 1);
}
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h
index b6cceb85fe..72965b4017 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityModel.h
@@ -171,7 +171,6 @@ namespace AzToolsFramework
, public PropertyEditorEntityChangeNotificationBus::Handler
{
public:
- explicit EditorEntityModelEntry(bool isPrefabEnabled);
~EditorEntityModelEntry();
// Separately connect to EditorEntityInfoRequestBus and refresh Entity
@@ -336,7 +335,6 @@ namespace AzToolsFramework
bool m_visible = true;
bool m_locked = false;
bool m_connected = false;
- bool m_isPrefabEnabled = false;
AZStd::string m_name;
AZStd::string m_sliceAssetName;
AZStd::unordered_map m_childIndexCache;
@@ -375,6 +373,5 @@ namespace AzToolsFramework
AZ::EntityId m_postInstantiateBeforeEntity;
AZ::EntityId m_postInstantiateSliceParent;
bool m_gotInstantiateSliceDetails = false;
- bool m_isPrefabEnabled = false;
};
}
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