Merge remote-tracking branch 'origin' into MultiplayerComponents

This commit is contained in:
karlberg
2021-05-05 20:07:49 -07:00
773 changed files with 5555 additions and 37483 deletions
@@ -330,4 +330,163 @@ namespace UnitTest
}
}
}
// The AssetManagerStreamerImmediateCompletionTests class adjusts the asset loading to force it to complete immediately,
// while still within the callstack for GetAsset(). This can be used to test various conditions in which the load thread
// completes more rapidly than expected, and can expose subtle race conditions.
// There are a few key things that this class does to make this work:
// - The file I/O streamer is mocked
// - The asset stream data is mocked to a 0-byte length for the asset so that the stream load will bypass the I/O streamer and
// just immediately return completion.
// - The number of JobManager threads is set to 0, forcing jobs to execute synchronously inline when they are started.
// With these changes, GetAssetInternal() will queue the stream, which will immediately call the callback that creates LoadAssetJob,
// which immediately executes in-place to process the asset due to the synchronous JobManager.
// Note that if we just created the asset in a Ready state, most of the asset loading code is completely bypassed, and so we
// wouldn't be able to test for race conditions in the AssetContainer.
//
// This class also unregisters the catalog and asset handler before shutting down the asset manager. This is done to catch
// any outstanding asset references that exist due to loads not completing and cleaning up successfully.
struct AssetManagerStreamerImmediateCompletionTests : public BaseAssetManagerTest,
public AZ::Data::AssetCatalogRequestBus::Handler,
public AZ::Data::AssetHandler,
public AZ::Data::AssetCatalog
{
static inline const AZ::Uuid TestAssetId{"{E970B177-5F45-44EB-A2C4-9F29D9A0B2A2}"};
static inline constexpr AZStd::string_view TestAssetPath = "test";
void SetUp() override
{
BaseAssetManagerTest::SetUp();
AssetManager::Descriptor desc;
AssetManager::Create(desc);
// Register the handler and catalog after creation, because we intend to destroy them before AssetManager destruction.
// The specific asset we load is irrelevant, so register EmptyAsset.
AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
// Intercept messages for finding assets by name so that we can mock out the asset we're loading.
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
}
void TearDown() override
{
// Unregister before destroying AssetManager.
// This will catch any assets that got stuck in a loading state without getting cleaned up.
AZ::Data::AssetManager::Instance().UnregisterCatalog(this);
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
AssetManager::Destroy();
BaseAssetManagerTest::TearDown();
}
size_t GetNumJobManagerThreads() const override
{
// Return 0 threads so that the Job Manager executes jobs synchronously inline. This lets us finish a load while still
// in the callstack that initiates the load.
return 0;
}
// Create a mock streamer instead of a real one, since we don't really want to load an asset.
IO::IStreamer* CreateStreamer() override
{
m_mockStreamer = AZStd::make_unique<StreamerWrapper>();
return &(m_mockStreamer->m_mockStreamer);
}
void DestroyStreamer([[maybe_unused]] IO::IStreamer* streamer) override
{
m_mockStreamer = nullptr;
}
// AssetHandler implementation
// Minimalist mock to create a new EmptyAsset with the desired asset ID.
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
{
return new EmptyAsset(id);
}
void DestroyAsset(AZ::Data::AssetPtr ptr) override
{
delete ptr;
}
// The mocked-out Asset Catalog handles EmptyAsset types.
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override
{
assetTypes.push_back(AZ::AzTypeInfo<EmptyAsset>::Uuid());
}
// This is a mocked-out load, so just immediately return completion without doing anything.
AZ::Data::AssetHandler::LoadResult LoadAssetData(
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
{
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
}
// AssetCatalogRequestBus implementation
// Minimalist mocks to provide our desired asset path or asset id
AZStd::string GetAssetPathById([[maybe_unused]] const AZ::Data::AssetId& id) override
{
return TestAssetPath;
}
AZ::Data::AssetId GetAssetIdByPath(
[[maybe_unused]] const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister,
[[maybe_unused]] bool autoRegisterIfNotFound) override
{
return TestAssetId;
}
// Return the mocked-out information for our test asset
AZ::Data::AssetInfo GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& id) override
{
AZ::Data::AssetInfo assetInfo;
assetInfo.m_assetId = TestAssetId;
assetInfo.m_assetType = AZ::AzTypeInfo<EmptyAsset>::Uuid();
assetInfo.m_relativePath = TestAssetPath;
return assetInfo;
}
// AssetCatalog implementation
// Set the mocked-out asset load to have a 0-byte length so that the load skips I/O and immediately returns success
AZ::Data::AssetStreamInfo GetStreamInfoForLoad(
[[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
{
EXPECT_TRUE(type == AZ::AzTypeInfo<EmptyAsset>::Uuid());
AZ::Data::AssetStreamInfo info;
info.m_dataOffset = 0;
info.m_streamName = TestAssetPath;
info.m_dataLen = 0;
info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
return info;
}
AZStd::unique_ptr<StreamerWrapper> m_mockStreamer;
};
// This test will verify that even if the asset loading stream/job returns immediately, all of the loading
// code works successfully. The test here is fairly simple - it just loads the asset and verifies that it
// loaded successfully. The bulk of the test is really in the setup class above, where the load is forced
// to complete immediately. Also, the true failure condition is caught in the setup class too, which is
// the presence of any assets at the point that the asset handler is unregistered. If they're present, then
// the immediate load wasn't truly successful, as it left around extra references to the asset that haven't
// been cleaned up.
TEST_F(AssetManagerStreamerImmediateCompletionTests, LoadAssetWithImmediateJobCompletion_WorksSuccessfully)
{
AZ::Data::AssetLoadParameters loadParams;
auto testAsset =
AssetManager::Instance().GetAsset<EmptyAsset>(TestAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams);
AZ::Data::AssetManager::Instance().DispatchEvents();
EXPECT_TRUE(testAsset.IsReady());
}
} // namespace UnitTest
@@ -24,6 +24,13 @@ namespace UnitTest
public:
AZ_CLASS_ALLOCATOR(EmptyAsset, AZ::SystemAllocator, 0);
AZ_RTTI(EmptyAsset, "{098E3F7F-13AC-414B-9B4E-49B5AD1BD7FE}", AZ::Data::AssetData);
EmptyAsset(
const AZ::Data::AssetId& assetId = AZ::Data::AssetId(),
AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
: AZ::Data::AssetData(assetId, status)
{
}
};
// EmptyAssetWithNoHandler: no data contained within, and no AssetHandler registered for this type
@@ -14,6 +14,7 @@
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AZTestShared/Math/MathTestHelpers.h>
using namespace AZ;
@@ -251,19 +252,19 @@ namespace UnitTest
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
Matrix3x3 m3 = m1 * m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
Matrix3x3 m4 = m1;
m4 *= m2;
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
EXPECT_THAT(m4.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
EXPECT_THAT(m4.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
EXPECT_THAT(m4.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
m3 = m1.TransposedMultiply(m2);
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(138.0f, 150.0f, 162.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(168.0f, 183.0f, 198.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(198.0f, 216.0f, 234.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(138.0f, 150.0f, 162.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(168.0f, 183.0f, 198.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(198.0f, 216.0f, 234.0f)));
}
TEST(MATH_Matrix3x3, TestVectorMultiplication)
@@ -277,11 +278,11 @@ namespace UnitTest
m2.SetRow(1, 10.0f, 11.0f, 12.0f);
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 32.0f, 50.0f)));
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 32.0f, 50.0f)));
Vector3 v1(1.0f, 2.0f, 3.0f);
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(30.0f, 36.0f, 42.0f)));
EXPECT_THAT((v1 * m1), IsClose(Vector3(30.0f, 36.0f, 42.0f)));
v1 *= m1;
AZ_TEST_ASSERT(v1.IsClose(Vector3(30.0f, 36.0f, 42.0f)));
EXPECT_THAT(v1, IsClose(Vector3(30.0f, 36.0f, 42.0f)));
}
TEST(MATH_Matrix3x3, TestSum)
@@ -296,15 +297,15 @@ namespace UnitTest
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
Matrix3x3 m3 = m1 + m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
m3 = m1;
m3 += m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
}
TEST(MATH_Matrix3x3, TestDifference)
@@ -319,14 +320,14 @@ namespace UnitTest
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
Matrix3x3 m3 = m1 - m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
m3 = m1;
m3 -= m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
}
TEST(MATH_Matrix3x3, TestScalarMultiplication)
@@ -341,18 +342,18 @@ namespace UnitTest
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
Matrix3x3 m3 = m1 * 2.0f;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
m3 = m1;
m3 *= 2.0f;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
m3 = 2.0f * m1;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
}
TEST(MATH_Matrix3x3, TestScalarDivision)
@@ -367,18 +368,32 @@ namespace UnitTest
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
Matrix3x3 m3 = m1 / 0.5f;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
m3 = m1;
m3 /= 0.5f;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
m3 = -m1;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
}
TEST(MATH_Matrix3x3, TestNegation)
{
Matrix3x3 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f);
m1.SetRow(1, 4.0f, 5.0f, 6.0f);
m1.SetRow(2, 7.0f, 8.0f, 9.0f);
EXPECT_THAT(-(-m1), IsClose(m1));
EXPECT_THAT(-Matrix3x3::CreateZero(), IsClose(Matrix3x3::CreateZero()));
Matrix3x3 m2 = -m1;
EXPECT_THAT(m2.GetRow(0), IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
EXPECT_THAT(m2.GetRow(1), IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
EXPECT_THAT(m2.GetRow(2), IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
Matrix3x3 m3 = m1 + (-m1);
EXPECT_THAT(m3, IsClose(Matrix3x3::CreateZero()));
}
TEST(MATH_Matrix3x3, TestTranspose)
@@ -425,11 +440,33 @@ namespace UnitTest
TEST(MATH_Matrix3x3, TestScaleAccess)
{
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
AZ_TEST_ASSERT(m1.ExtractScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3::CreateOne()));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(3.0f, 4.0f, 5.0f)));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
}
TEST(MATH_Matrix3x3, TestScaleSqAccess)
{
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
m1.ExtractScale();
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
}
TEST(MATH_Matrix3x3, TestReciprocalScaled)
{
Matrix3x3 orthogonalMatrix = Matrix3x3::CreateRotationX(DegToRad(40.0f));
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
AZ::Matrix3x3 scaledMatrix = orthogonalMatrix;
scaledMatrix.MultiplyByScale(scale);
AZ::Matrix3x3 reciprocalScaledMatrix = orthogonalMatrix;
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
}
TEST(MATH_Matrix3x3, TestPolarDecomposition)
@@ -467,21 +467,136 @@ namespace UnitTest
EXPECT_THAT(matrix.Multiply3x3(axisDirection), IsClose(forwardDirection));
}
TEST(MATH_Matrix3x4, MultiplyByMatrix3x4)
TEST(MATH_Matrix3x4, TestMatrixMultiplication)
{
const AZ::Matrix3x4 matrix1 = AZ::Matrix3x4::CreateFromValue(1.2f);
const AZ::Matrix3x4 matrix2 = AZ::Matrix3x4::CreateDiagonal(AZ::Vector3(1.3f, 1.5f, 0.4f));
const AZ::Matrix3x4 matrix3 = AZ::Matrix3x4::CreateFromQuaternionAndTranslation(
AZ::Quaternion(0.42f, 0.46f, -0.66f, 0.42f), AZ::Vector3(2.8f, -3.7f, 1.6f));
const AZ::Matrix3x4 matrix4 = AZ::Matrix3x4::CreateRotationX(-0.7f) * AZ::Matrix3x4::CreateScale(AZ::Vector3(0.6f, 1.3f, 0.7f));
AZ::Matrix3x4 matrix5 = matrix1;
matrix5 *= matrix4;
const AZ::Vector3 vector(1.9f, 2.3f, 0.2f);
EXPECT_TRUE((matrix1 * (matrix2 * matrix3)).IsClose((matrix1 * matrix2) * matrix3));
EXPECT_THAT((matrix3 * matrix4) * vector, IsClose(matrix3 * (matrix4 * vector)));
EXPECT_TRUE((matrix2 * AZ::Matrix3x4::Identity()).IsClose(matrix2));
EXPECT_TRUE((matrix3 * AZ::Matrix3x4::Identity()).IsClose(AZ::Matrix3x4::Identity() * matrix3));
EXPECT_TRUE(matrix5.IsClose(matrix1 * matrix4));
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
AZ::Matrix3x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
AZ::Matrix3x4 m3 = m1 * m2;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
AZ::Matrix3x4 m4 = m1;
m4 *= m2;
EXPECT_THAT(m4.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
EXPECT_THAT(m4.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
EXPECT_THAT(m4.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
}
TEST(MATH_Matrix3x4, TestSum)
{
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
AZ::Matrix3x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
AZ::Matrix3x4 m3 = m1 + m2;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
m3 = m1;
m3 += m2;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
}
TEST(MATH_Matrix3x4, TestDifference)
{
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
AZ::Matrix3x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
AZ::Matrix3x4 m3 = m1 - m2;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
m3 = m1;
m3 -= m2;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
}
TEST(MATH_Matrix3x4, TestScalarMultiplication)
{
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
AZ::Matrix3x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
AZ::Matrix3x4 m3 = m1 * 2.0f;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
m3 = m1;
m3 *= 2.0f;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
m3 = 2.0f * m1;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
}
TEST(MATH_Matrix3x4, TestScalarDivision)
{
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
AZ::Matrix3x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
AZ::Matrix3x4 m3 = m1 / 0.5f;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
m3 = m1;
m3 /= 0.5f;
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
}
TEST(MATH_Matrix3x4, TestNegation)
{
AZ::Matrix3x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
EXPECT_THAT(-(-m1), IsClose(m1));
EXPECT_THAT(-AZ::Matrix3x4::CreateZero(), IsClose(AZ::Matrix3x4::CreateZero()));
AZ::Matrix3x4 m2 = -m1;
EXPECT_THAT(m2.GetRow(0), IsClose(AZ::Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
EXPECT_THAT(m2.GetRow(1), IsClose(AZ::Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
EXPECT_THAT(m2.GetRow(2), IsClose(AZ::Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
AZ::Matrix3x4 m3 = m1 + (-m1);
EXPECT_THAT(m3, IsClose(AZ::Matrix3x4::CreateZero()));
}
TEST(MATH_Matrix3x4, MultiplyByVector3)
@@ -652,6 +767,34 @@ namespace UnitTest
EXPECT_THAT(scaledMatrix.RetrieveScale(), IsClose(AZ::Vector3::CreateOne()));
}
TEST_P(Matrix3x4ScaleFixture, ScaleSq)
{
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
EXPECT_THAT(orthogonalMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
AZ::Matrix3x4 unscaledMatrix = orthogonalMatrix;
unscaledMatrix.ExtractScale();
EXPECT_THAT(unscaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
scaledMatrix.MultiplyByScale(scale);
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scale * scale));
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scaledMatrix.RetrieveScale() * scaledMatrix.RetrieveScale()));
scaledMatrix.ExtractScale();
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
}
TEST_P(Matrix3x4ScaleFixture, GetReciprocalScaled)
{
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
scaledMatrix.MultiplyByScale(scale);
AZ::Matrix3x4 reciprocalScaledMatrix = orthogonalMatrix;
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
}
INSTANTIATE_TEST_CASE_P(MATH_Matrix3x4, Matrix3x4ScaleFixture, ::testing::ValuesIn(MathTestData::OrthogonalMatrix3x4s));
TEST(MATH_Matrix3x4, IsOrthogonal)
@@ -246,16 +246,16 @@ namespace UnitTest
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
Matrix4x4 m3 = m1 * m2;
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
AZ_TEST_ASSERT(m3.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
Matrix4x4 m4 = m1;
m4 *= m2;
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
AZ_TEST_ASSERT(m4.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
EXPECT_THAT(m4.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
EXPECT_THAT(m4.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
EXPECT_THAT(m4.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
EXPECT_THAT(m4.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
}
TEST(MATH_Matrix4x4, TestVectorMultiplication)
@@ -265,18 +265,148 @@ namespace UnitTest
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(18.0f, 46.0f, 74.0f)));
AZ_TEST_ASSERT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)).IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
AZ_TEST_ASSERT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(38.0f, 44.0f, 50.0f)));
AZ_TEST_ASSERT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 38.0f, 62.0f)));
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(18.0f, 46.0f, 74.0f)));
EXPECT_THAT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)), IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
EXPECT_THAT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(38.0f, 44.0f, 50.0f)));
EXPECT_THAT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 38.0f, 62.0f)));
Vector3 v1(1.0f, 2.0f, 3.0f);
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(51.0f, 58.0f, 65.0f)));
EXPECT_THAT((v1 * m1), IsClose(Vector3(51.0f, 58.0f, 65.0f)));
v1 *= m1;
AZ_TEST_ASSERT(v1.IsClose(Vector3(51.0f, 58.0f, 65.0f)));
EXPECT_THAT(v1, IsClose(Vector3(51.0f, 58.0f, 65.0f)));
Vector4 v2(1.0f, 2.0f, 3.0f, 4.0f);
AZ_TEST_ASSERT((v2 * m1).IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
EXPECT_THAT((v2 * m1), IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
v2 *= m1;
AZ_TEST_ASSERT(v2.IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
EXPECT_THAT(v2, IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
}
TEST(MATH_Matrix4x4, TestSum)
{
Matrix4x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
Matrix4x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
Matrix4x4 m3 = m1 + m2;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
m3 = m1;
m3 += m2;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
}
TEST(MATH_Matrix4x4, TestDifference)
{
Matrix4x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
Matrix4x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
Matrix4x4 m3 = m1 - m2;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
m3 = m1;
m3 -= m2;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
}
TEST(MATH_Matrix4x4, TestScalarMultiplication)
{
Matrix4x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
Matrix4x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
Matrix4x4 m3 = m1 * 2.0f;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
m3 = m1;
m3 *= 2.0f;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
m3 = 2.0f * m1;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
}
TEST(MATH_Matrix4x4, TestScalarDivision)
{
Matrix4x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
Matrix4x4 m2;
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
Matrix4x4 m3 = m1 / 0.5f;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
m3 = m1;
m3 /= 0.5f;
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
}
TEST(MATH_Matrix4x4, TestNegation)
{
Matrix4x4 m1;
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
EXPECT_THAT(-(-m1), IsClose(m1));
EXPECT_THAT(-Matrix4x4::CreateZero(), IsClose(Matrix4x4::CreateZero()));
Matrix4x4 m2 = -m1;
EXPECT_THAT(m2.GetRow(0), IsClose(Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
EXPECT_THAT(m2.GetRow(1), IsClose(Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
EXPECT_THAT(m2.GetRow(2), IsClose(Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
EXPECT_THAT(m2.GetRow(3), IsClose(Vector4(-13.0f, -14.0f, -15.0f, -16.0f)));
Matrix4x4 m3 = m1 + (-m1);
EXPECT_THAT(m3, IsClose(Matrix4x4::CreateZero()));
}
TEST(MATH_Matrix4x4, TestTranspose)
@@ -368,4 +498,36 @@ namespace UnitTest
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
AZ_TEST_ASSERT(m1.GetDiagonal() == Vector4(1.0f, 6.0f, 11.0f, 16.0f));
}
TEST(MATH_Matrix4x4, TestScaleAccess)
{
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
}
TEST(MATH_Matrix4x4, TestScaleSqAccess)
{
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
m1.ExtractScale();
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
}
TEST(MATH_Matrix4x4, TestReciprocalScaled)
{
Matrix4x4 orthogonalMatrix = Matrix4x4::CreateRotationX(DegToRad(40.0f));
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
AZ::Matrix4x4 scaledMatrix = orthogonalMatrix;
scaledMatrix.MultiplyByScale(scale);
AZ::Matrix4x4 reciprocalScaledMatrix = orthogonalMatrix;
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
}
}
@@ -110,7 +110,7 @@ namespace JsonSerializationTests
EXPECT_EQ(42, value);
}
TEST_F(BaseJsonSerializerTests, ContinueLoading_PointerInstance_ValueLoadedCorrectly)
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToPointerInstance_ValueLoadedCorrectly)
{
using namespace AZ::JsonSerializationResult;
@@ -126,6 +126,51 @@ namespace JsonSerializationTests
EXPECT_EQ(42, value);
}
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToNullPointer_ValueLoadedCorrectly)
{
using namespace AZ::JsonSerializationResult;
rapidjson::Value json;
json.Set(42);
int* ptrValue = nullptr;
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_NE(nullptr, ptrValue);
EXPECT_EQ(42, *ptrValue);
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
}
TEST_F(BaseJsonSerializerTests, ContinueLoading_DefaultToNullPointer_ValueLoadedCorrectly)
{
using namespace AZ::JsonSerializationResult;
rapidjson::Value json(rapidjson::kObjectType);
int* ptrValue = nullptr;
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_NE(nullptr, ptrValue);
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
}
TEST_F(BaseJsonSerializerTests, ContinueLoading_NullDeletesObject_ValueLoadedCorrectly)
{
using namespace AZ::JsonSerializationResult;
rapidjson::Value json(rapidjson::kNullType);
int* ptrValue = reinterpret_cast<int*>(azmalloc(sizeof(int), alignof(int), AZ::SystemAllocator));
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
ASSERT_EQ(nullptr, ptrValue);
}
//
// ContinueStoring
//
@@ -156,6 +201,64 @@ namespace JsonSerializationTests
Expect_DocStrEq("42");
}
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToFullDefaultedInstance_ValueStoredCorrectly)
{
using namespace AZ::JsonSerializationResult;
int value = 42;
int* ptrValue = &value;
int value2 = 42;
int* defaultPtrValue = &value2;
ResultCode result =
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("{}");
}
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptr_ValueStoredCorrectly)
{
using namespace AZ::JsonSerializationResult;
int* ptrValue = nullptr;
ResultCode result = ContinueStoring(
*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
}
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithValueDefault_ValueStoredCorrectly)
{
using namespace AZ::JsonSerializationResult;
int* ptrValue = nullptr;
int value2 = 42;
int* defaultPtrValue = &value2;
ResultCode result =
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
}
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithNullPtrDefault_NullPtrIsStored)
{
using namespace AZ::JsonSerializationResult;
int* ptrValue = nullptr;
int* defaultPtrValue = nullptr;
ResultCode result =
ContinueStoring(*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext, Flags::ResolvePointer);
EXPECT_EQ(Processing::Completed, result.GetProcessing());
Expect_DocStrEq("null");
}
TEST_F(BaseJsonSerializerTests, ContinueStoring_ReplaceDefault_ValueStoredCorrectly)
{
using namespace AZ::JsonSerializationResult;
@@ -32,11 +32,6 @@ namespace JsonSerializationTests
return AZStd::make_shared<AZ::JsonSmartPointerSerializer>();
}
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
{
return AZStd::make_shared<SmartPointer>();
}
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
{
context->RegisterGenericType<SmartPointer>();
@@ -51,6 +46,13 @@ namespace JsonSerializationTests
using SmartPointer = T<SimpleClass>;
using Base = SmartPointerBaseTestDescription<SmartPointer>;
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
{
auto result = AZStd::make_shared<SmartPointer>();
*result = SmartPointer(aznew SimpleClass());
return result;
}
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
{
auto result = AZStd::make_shared<SmartPointer>();
@@ -106,21 +108,6 @@ namespace JsonSerializationTests
}
};
template<template<typename...> class T>
class SmartPointerSimpleClassWithInstanceTestDescription :
public SmartPointerSimpleClassTestDescription<T>
{
public:
using SmartPointer = typename SmartPointerSimpleClassTestDescription<T>::SmartPointer;
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
{
auto result = AZStd::make_shared<SmartPointer>();
*result = SmartPointer(aznew SimpleClass());
return result;
}
};
template<template<typename...> class T>
class SmartPointerSimpleDerivedClassTestDescription :
public SmartPointerBaseTestDescription<T<BaseClass>>
@@ -129,6 +116,13 @@ namespace JsonSerializationTests
using SmartPointer = T<BaseClass>;
using Base = SmartPointerBaseTestDescription<SmartPointer>;
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
{
auto result = AZStd::make_shared<SmartPointer>();
*result = SmartPointer(aznew BaseClass());
return result;
}
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
{
auto* instance = aznew SimpleInheritence();
@@ -272,6 +266,13 @@ namespace JsonSerializationTests
using SmartPointer = T<BaseClass2>;
using Base = SmartPointerBaseTestDescription<SmartPointer>;
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
{
auto result = AZStd::make_shared<SmartPointer>();
*result = SmartPointer(aznew BaseClass2());
return result;
}
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
{
auto* instance = aznew MultipleInheritence();
@@ -424,9 +425,6 @@ namespace JsonSerializationTests
SmartPointerSimpleClassTestDescription<AZStd::unique_ptr>,
SmartPointerSimpleClassTestDescription<AZStd::shared_ptr>,
SmartPointerSimpleClassTestDescription<AZStd::intrusive_ptr>,
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::unique_ptr>,
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::shared_ptr>,
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::intrusive_ptr>,
// Simple derived class, include single inheritance.
SmartPointerSimpleDerivedClassTestDescription<AZStd::unique_ptr>,
SmartPointerSimpleDerivedClassTestDescription<AZStd::shared_ptr>,
@@ -551,6 +549,37 @@ namespace JsonSerializationTests
EXPECT_EQ(nullptr, *instance);
}
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultInstanceToNullptr_ReturnsSuccess)
{
namespace JSR = AZ::JsonSerializationResult;
SmartPointer instance;
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateDefaultInstance();
m_jsonDocument->SetObject();
JSR::ResultCode result =
m_serializer.Load(&instance, azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
EXPECT_NE(nullptr, instance);
EXPECT_TRUE(m_description.AreEqual(instance, *compare));
}
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultObjectDoesNotUpdateInstance_ReturnsSuccess)
{
namespace JSR = AZ::JsonSerializationResult;
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateFullySetInstance();
m_jsonDocument->SetObject();
JSR::ResultCode result =
m_serializer.Load(instance.get(), azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
EXPECT_TRUE(m_description.AreEqual(*instance, *compare));
}
TEST_F(JsonSmartPointerSerializerTests, Load_InstanceBeingReplacedWithDifferentType_ReturnsSuccess)
{
namespace JSR = AZ::JsonSerializationResult;
@@ -720,13 +749,66 @@ namespace JsonSerializationTests
namespace JSR = AZ::JsonSerializationResult;
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
SmartPointer nullPtr;
JSR::ResultCode result = m_serializer.Store(*m_jsonDocument, instance.get(), &nullPtr,
SmartPointer defaultInstance;
JSR::ResultCode result = m_serializer.Store(
*m_jsonDocument, instance.get(), &defaultInstance,
azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
}
TEST_F(JsonSmartPointerSerializerTests, Store_ValuePointerIsNullPtr_ReturnsSuccessAndStoresNull)
{
namespace JSR = AZ::JsonSerializationResult;
SmartPointer instance;
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateFullySetInstance();
JSR::ResultCode result = m_serializer.Store(
*m_jsonDocument, &instance, defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
EXPECT_TRUE(m_jsonDocument->IsNull());
}
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreNullPtr_ReturnsSuccessAndStoresNull)
{
namespace JSR = AZ::JsonSerializationResult;
SmartPointer instance;
SmartPointer defaultInstance;
JSR::ResultCode result =
m_serializer.Store(*m_jsonDocument, &instance, &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
EXPECT_TRUE(m_jsonDocument->IsNull());
}
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreBothDefault_ReturnsSuccess)
{
namespace JSR = AZ::JsonSerializationResult;
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateDefaultInstance();
JSR::ResultCode result =
m_serializer.Store(*m_jsonDocument, instance.get(), defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
Expect_ExplicitDefault(*m_jsonDocument);
}
TEST_F(JsonSmartPointerSerializerTests, Store_ValueHasDefaultValuesAndDefaultHasNullPointer_ReturnsSuccess)
{
namespace JSR = AZ::JsonSerializationResult;
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
SmartPointer defaultInstance;
JSR::ResultCode result = m_serializer.Store(
*m_jsonDocument, instance.get(), &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
Expect_ExplicitDefault(*m_jsonDocument);
}
TEST_F(JsonSmartPointerSerializerTests, Store_DefaultPointerIsOtherClass_CompletesButDoesNotReturnDefaults)
{
namespace JSR = AZ::JsonSerializationResult;
@@ -749,7 +831,7 @@ namespace JsonSerializationTests
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
}
TEST_F(JsonSmartPointerSerializerTests, Store_SaveAnClassThatIsNotReflected_ReturnsUnknown)
TEST_F(JsonSmartPointerSerializerTests, Store_ClassThatIsNotReflected_ReturnsUnknown)
{
namespace JSR = AZ::JsonSerializationResult;