/* * 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 // SimulatedObjectSetup.h includes #include #include #include #include #include // SimulatedObjectSetup.cpp includes #include #include #include #include #include #include #include #include #include #include namespace SimulatedObjectSetupTests { namespace AZStd { using namespace ::AZStd; } // namespace AZStd namespace AZ { using namespace ::AZ; } // namespace AZ // Import real implementations namespace EMotionFX { using ::EMotionFX::ActorAllocator; } // namespace EMotionFX #include #include #include #include #include using namespace EMotionFX; class SimulatedObjectSetupTestsFixture : public UnitTest::AllocatorsTestFixture { public: void SetUp() override { UnitTest::AllocatorsTestFixture::SetUp(); AZ::AllocatorInstance::Create(); } void TearDown() override { AZ::AllocatorInstance::Destroy(); UnitTest::AllocatorsTestFixture::TearDown(); } }; TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_AddSimulatedObject) { Actor actor; SimulatedObjectSetup setup(&actor); const SimulatedObject* object = setup.AddSimulatedObject(); EXPECT_EQ(setup.GetSimulatedObject(0), object); } TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_InsertSimulatedObjectAt) { Actor actor; SimulatedObjectSetup setup(&actor); for (int i = 0; i < 5; ++i) { setup.AddSimulatedObject(); } const size_t objectIndex = 3; const SimulatedObject* object = setup.InsertSimulatedObjectAt(objectIndex); EXPECT_EQ(setup.GetSimulatedObject(objectIndex), object); } TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_RemoveSimulatedObject) { Actor actor; SimulatedObjectSetup setup(&actor); AZStd::vector objects { setup.AddSimulatedObject(), setup.AddSimulatedObject(), setup.AddSimulatedObject(), setup.AddSimulatedObject(), setup.AddSimulatedObject(), }; const size_t objectIndex = 3; setup.RemoveSimulatedObject(objectIndex); objects.erase(AZStd::next(objects.begin(), objectIndex)); EXPECT_EQ(setup.GetSimulatedObjects(), objects); } /////////////////////////////////////////////////////////////////////////// using SimulatedObjectTestsFixture = SimulatedObjectSetupTestsFixture; TEST_F(SimulatedObjectTestsFixture, TestSimulatedObject_FindSimulatedJointBySkeletonJointIndex) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); const AZ::u32 jointIndex = PrefabLeftArmSkeleton::leftThumb1Index; const SimulatedJoint* joint = object->AddSimulatedJoint(jointIndex); EXPECT_EQ(object->FindSimulatedJointBySkeletonJointIndex(jointIndex), joint); } TEST_F(SimulatedObjectTestsFixture, TestSimulatedObject_ContainsSimulatedJoint) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object1 = setup.AddSimulatedObject(); SimulatedObject* object2 = setup.AddSimulatedObject(); const SimulatedJoint* joint1 = object1->AddSimulatedJoint(PrefabLeftArmSkeleton::leftElbowIndex); const SimulatedJoint* joint2 = object2->AddSimulatedJoint(PrefabLeftArmSkeleton::leftElbowIndex); EXPECT_TRUE(object1->ContainsSimulatedJoint(joint1)); EXPECT_FALSE(object1->ContainsSimulatedJoint(joint2)); EXPECT_FALSE(object2->ContainsSimulatedJoint(joint1)); EXPECT_TRUE(object2->ContainsSimulatedJoint(joint2)); } struct AddSimulatedJointAndChildrenParams { AZ::u32 jointIndex; size_t expectedSimulatedJointCount; }; class AddSimulatedJointAndChildrenFixture : public SimulatedObjectTestsFixture , public testing::WithParamInterface { }; TEST_P(AddSimulatedJointAndChildrenFixture, TestSimulatedObject_AddSimulatedJointAndChildren) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); object->AddSimulatedJointAndChildren(GetParam().jointIndex); EXPECT_EQ(object->GetSimulatedJoints().size(), GetParam().expectedSimulatedJointCount); } INSTANTIATE_TEST_CASE_P(Test, AddSimulatedJointAndChildrenFixture, testing::ValuesIn(std::vector { {PrefabLeftArmSkeleton::leftShoulderIndex, 13}, // leftShoulder is a root joint {PrefabLeftArmSkeleton::leftElbowIndex, 12}, {PrefabLeftArmSkeleton::leftWristIndex, 11}, {PrefabLeftArmSkeleton::leftHandIndex, 10}, {PrefabLeftArmSkeleton::leftThumb1Index, 3}, {PrefabLeftArmSkeleton::leftThumb2Index, 2}, {PrefabLeftArmSkeleton::leftThumb3Index, 1}, // leftThumb is a leaf joint }) ); class GetSimulatedRootJointFixture : public SimulatedObjectTestsFixture , public testing::WithParamInterface> { }; // Determine if left is a parent of right, if right is a parent of left, or // if neither of the two joints are a parent of the other // Returns: -1 if left is a parent of right, // 1 if right is a parent of left, // 0 if neither is a parent of the other int NodeHasCommonParentImpl(const Node* left, const Node* right, const Node* initialLeft, const Node* initialRight) { if (left == right || (!left && !right)) { return 0; } if (left == initialRight) { // right is a parent of left return 1; } if (right == initialLeft) { // left is a parent of right return -1; } const Node* leftParent = left ? left->GetParentNode() : nullptr; const Node* rightParent = right ? right->GetParentNode() : nullptr; return NodeHasCommonParentImpl(leftParent, rightParent, initialLeft, initialRight); } int NodeHasCommonParent(const Node* left, const Node* right) { return NodeHasCommonParentImpl(left, right, left, right); } // This test verifies that when any two joint indexes are added to a // simulated object, it results in the correct root joints. It is // parameterized on tuple, where the two ints are the joint // indexes of the PrefabLeftArmSkeleton to add. Index 2 may be -1, in which // case only joint index 1 will be added to the object. // For any two joints, it is possible that one joint is in the parent list // of another joint. In this case, the number of root joints that should be // in the simulated object is 1. If the two joints are siblings of each // other, or in some other way unrelated (like not having any common // parents), then the expected number of root joints is 2. TEST_P(GetSimulatedRootJointFixture, TestSimulatedObject_GetSimulatedRootJoint) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); const int jointIndex1 = testing::get<0>(GetParam()); const int jointIndex2 = testing::get<1>(GetParam()); object->AddSimulatedJointAndChildren(jointIndex1); if (jointIndex2 >= 0) { object->AddSimulatedJointAndChildren(jointIndex2); } const SimulatedJoint* simulatedJoint1 = object->FindSimulatedJointBySkeletonJointIndex(jointIndex1); EXPECT_TRUE(simulatedJoint1); if (jointIndex2 >= 0 && jointIndex2 != jointIndex1) { const SimulatedJoint* simulatedJoint2 = object->FindSimulatedJointBySkeletonJointIndex(jointIndex2); EXPECT_TRUE(simulatedJoint2); const Skeleton& skeleton = leftArmSkeleton.m_skeleton; const int hasCommonParent = NodeHasCommonParent(skeleton.GetNode(jointIndex1), skeleton.GetNode(jointIndex2)); if (hasCommonParent == 0) { // simulatedJoint1 and simulatedJoint2 are not in each other's // parent list EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1); EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint2)), simulatedJoint2); EXPECT_EQ(object->GetNumSimulatedRootJoints(), 2); } else if (hasCommonParent < 0) { // simulatedJoint1 is a parent of simulatedJoint2 EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1); EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1); } else { // simulatedJoint2 is a parent of simulatedJoint1 EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint2)), simulatedJoint2); EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1); } } else { EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1); EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1); } } INSTANTIATE_TEST_CASE_P(Test, GetSimulatedRootJointFixture, ::testing::Combine( ::testing::Values( PrefabLeftArmSkeleton::leftShoulderIndex, PrefabLeftArmSkeleton::leftElbowIndex, PrefabLeftArmSkeleton::leftWristIndex, PrefabLeftArmSkeleton::leftHandIndex, PrefabLeftArmSkeleton::leftThumb1Index, PrefabLeftArmSkeleton::leftThumb2Index, PrefabLeftArmSkeleton::leftThumb3Index, PrefabLeftArmSkeleton::leftIndex1Index, PrefabLeftArmSkeleton::leftIndex2Index, PrefabLeftArmSkeleton::leftIndex3Index, PrefabLeftArmSkeleton::leftPinky1Index, PrefabLeftArmSkeleton::leftPinky2Index, PrefabLeftArmSkeleton::leftPinky3Index ), ::testing::Values( -1, PrefabLeftArmSkeleton::leftThumb1Index, PrefabLeftArmSkeleton::leftThumb2Index, PrefabLeftArmSkeleton::leftThumb3Index, PrefabLeftArmSkeleton::leftIndex1Index, PrefabLeftArmSkeleton::leftIndex2Index, PrefabLeftArmSkeleton::leftIndex3Index, PrefabLeftArmSkeleton::leftPinky1Index, PrefabLeftArmSkeleton::leftPinky2Index, PrefabLeftArmSkeleton::leftPinky3Index ) ), [](const ::testing::TestParamInfo<::testing::tuple>& info) { const auto getJointName = [](const int jointIndex) -> std::string { switch (jointIndex) { case PrefabLeftArmSkeleton::leftShoulderIndex: return "leftShoulder"; break; case PrefabLeftArmSkeleton::leftElbowIndex: return "leftElbow"; break; case PrefabLeftArmSkeleton::leftWristIndex: return "leftWrist"; break; case PrefabLeftArmSkeleton::leftHandIndex: return "leftHand"; break; case PrefabLeftArmSkeleton::leftThumb1Index: return "leftThumb1"; break; case PrefabLeftArmSkeleton::leftThumb2Index: return "leftThumb2"; break; case PrefabLeftArmSkeleton::leftThumb3Index: return "leftThumb3"; break; case PrefabLeftArmSkeleton::leftIndex1Index: return "leftIndex1"; break; case PrefabLeftArmSkeleton::leftIndex2Index: return "leftIndex2"; break; case PrefabLeftArmSkeleton::leftIndex3Index: return "leftIndex3"; break; case PrefabLeftArmSkeleton::leftPinky1Index: return "leftPinky1"; break; case PrefabLeftArmSkeleton::leftPinky2Index: return "leftPinky2"; break; case PrefabLeftArmSkeleton::leftPinky3Index: return "leftPinky3"; break; default: return "None"; }; }; return "WithJoints_" + getJointName(testing::get<0>(info.param)) + "_and_" + getJointName(testing::get<1>(info.param)); } ); /////////////////////////////////////////////////////////////////////////// using SimulatedJointTestsFixture = SimulatedObjectSetupTestsFixture; TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_GettersSetters) { SimulatedJoint joint; EXPECT_EQ(joint.GetConeAngleLimit(), 60.0f); EXPECT_EQ(joint.GetMass(), 1.0f); EXPECT_EQ(joint.GetStiffness(), 0.0f); EXPECT_EQ(joint.GetDamping(), 0.001f); EXPECT_EQ(joint.GetGravityFactor(), 1.0f); EXPECT_EQ(joint.GetFriction(), 0.0f); EXPECT_EQ(joint.IsPinned(), false); const float newConeAngleLimit = 90.0f; const float newMass = 3.0f; const float newStiffness = 0.5f; const float newDamping = 0.1f; const float newGravityFactor = 1.2f; const float newFriction = 0.3f; const bool newPinned = true; const bool newStretchable = true; joint.SetConeAngleLimit(newConeAngleLimit); joint.SetMass(newMass); joint.SetStiffness(newStiffness); joint.SetDamping(newDamping); joint.SetGravityFactor(newGravityFactor); joint.SetFriction(newFriction); joint.SetPinned(newPinned); EXPECT_EQ(joint.GetConeAngleLimit(), newConeAngleLimit); EXPECT_EQ(joint.GetMass(), newMass); EXPECT_EQ(joint.GetStiffness(), newStiffness); EXPECT_EQ(joint.GetDamping(), newDamping); EXPECT_EQ(joint.GetGravityFactor(), newGravityFactor); EXPECT_EQ(joint.GetFriction(), newFriction); EXPECT_EQ(joint.IsPinned(), newPinned); } TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_FindParentSimulatedJoint) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index); SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index); EXPECT_EQ(simulatedThumb2->FindParentSimulatedJoint(), simulatedThumb1); EXPECT_EQ(simulatedThumb1->FindParentSimulatedJoint(), nullptr); } TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_FindChildSimulatedJoint) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); SimulatedJoint* simulatedHand = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftHandIndex); SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index); SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index); SimulatedJoint* simulatedThumb3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb3Index); SimulatedJoint* simulatedIndex1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex1Index); SimulatedJoint* simulatedIndex2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex2Index); SimulatedJoint* simulatedIndex3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex3Index); EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(0), simulatedThumb1); EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(1), simulatedIndex1); EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(2), nullptr); EXPECT_EQ(simulatedThumb1->FindChildSimulatedJoint(0), simulatedThumb2); EXPECT_EQ(simulatedThumb1->FindChildSimulatedJoint(1), nullptr); EXPECT_EQ(simulatedThumb2->FindChildSimulatedJoint(0), simulatedThumb3); EXPECT_EQ(simulatedThumb2->FindChildSimulatedJoint(1), nullptr); EXPECT_EQ(simulatedThumb3->FindChildSimulatedJoint(0), nullptr); EXPECT_EQ(simulatedIndex1->FindChildSimulatedJoint(0), simulatedIndex2); EXPECT_EQ(simulatedIndex1->FindChildSimulatedJoint(1), nullptr); EXPECT_EQ(simulatedIndex2->FindChildSimulatedJoint(0), simulatedIndex3); EXPECT_EQ(simulatedIndex2->FindChildSimulatedJoint(1), nullptr); EXPECT_EQ(simulatedIndex3->FindChildSimulatedJoint(0), nullptr); } TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_CalculateSimulatedJointIndex) { PrefabLeftArmSkeleton leftArmSkeleton; Actor actor; EXPECT_CALL(actor, GetSkeleton()) .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton)); SimulatedObjectSetup setup(&actor); SimulatedObject* object = setup.AddSimulatedObject(); SimulatedJoint* simulatedIndex3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex3Index); SimulatedJoint* simulatedIndex2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex2Index); SimulatedJoint* simulatedIndex1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex1Index); SimulatedJoint* simulatedThumb3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb3Index); SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index); SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index); SimulatedJoint* simulatedHand = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftHandIndex); // Joints get sorted based on their skeletal joint index. Even though // these joints were added in reverse order, they are stored in a // sorted array internally. EXPECT_EQ(simulatedHand->CalculateSimulatedJointIndex().GetValue(), 0); EXPECT_EQ(simulatedThumb1->CalculateSimulatedJointIndex().GetValue(), 1); EXPECT_EQ(simulatedThumb2->CalculateSimulatedJointIndex().GetValue(), 2); EXPECT_EQ(simulatedThumb3->CalculateSimulatedJointIndex().GetValue(), 3); EXPECT_EQ(simulatedIndex1->CalculateSimulatedJointIndex().GetValue(), 4); EXPECT_EQ(simulatedIndex2->CalculateSimulatedJointIndex().GetValue(), 5); EXPECT_EQ(simulatedIndex3->CalculateSimulatedJointIndex().GetValue(), 6); } } // namespace SimulatedObjectSetupTests