SimulatedObjectSetupTests.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzTest/AzTest.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. // SimulatedObjectSetup.h includes
  11. #include <AzCore/Outcome/Outcome.h>
  12. #include <AzCore/std/containers/vector.h>
  13. #include <AzCore/std/string/string.h>
  14. #include <AzCore/std/smart_ptr/shared_ptr.h>
  15. #include <AzCore/RTTI/TypeInfo.h>
  16. // SimulatedObjectSetup.cpp includes
  17. #include <AzCore/Serialization/EditContext.h>
  18. #include <AzCore/Serialization/SerializeContext.h>
  19. #include <AzCore/Serialization/ObjectStream.h>
  20. #include <AzCore/Component/ComponentApplicationBus.h>
  21. #include <AzCore/std/smart_ptr/make_shared.h>
  22. #include <AzCore/std/sort.h>
  23. #include <EMotionFX/Source/Allocators.h>
  24. #include <EMotionFX/Source/Actor.h>
  25. #include <EMotionFX/Source/Skeleton.h>
  26. #include <EMotionFX/Source/Node.h>
  27. namespace SimulatedObjectSetupTests
  28. {
  29. // Import real implementations
  30. namespace EMotionFX
  31. {
  32. using ::EMotionFX::ActorAllocator;
  33. } // namespace EMotionFX
  34. #include <Tests/Mocks/Node.h>
  35. #include <Tests/Mocks/Skeleton.h>
  36. #include <Tests/Mocks/Actor.h>
  37. #include <Tests/Prefabs/LeftArmSkeleton.h>
  38. #include <EMotionFX/Source/SimulatedObjectSetup_Interface.inl>
  39. #include <EMotionFX/Source/SimulatedObjectSetup_Impl.inl>
  40. using namespace EMotionFX;
  41. class SimulatedObjectSetupTestsFixture
  42. : public UnitTest::LeakDetectionFixture
  43. {
  44. };
  45. TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_AddSimulatedObject)
  46. {
  47. Actor actor;
  48. SimulatedObjectSetup setup(&actor);
  49. const SimulatedObject* object = setup.AddSimulatedObject();
  50. EXPECT_EQ(setup.GetSimulatedObject(0), object);
  51. }
  52. TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_InsertSimulatedObjectAt)
  53. {
  54. Actor actor;
  55. SimulatedObjectSetup setup(&actor);
  56. for (int i = 0; i < 5; ++i)
  57. {
  58. setup.AddSimulatedObject();
  59. }
  60. const size_t objectIndex = 3;
  61. const SimulatedObject* object = setup.InsertSimulatedObjectAt(objectIndex);
  62. EXPECT_EQ(setup.GetSimulatedObject(objectIndex), object);
  63. }
  64. TEST_F(SimulatedObjectSetupTestsFixture, TestSimulatedObjectSetup_RemoveSimulatedObject)
  65. {
  66. Actor actor;
  67. SimulatedObjectSetup setup(&actor);
  68. AZStd::vector<SimulatedObject*> objects
  69. {
  70. setup.AddSimulatedObject(),
  71. setup.AddSimulatedObject(),
  72. setup.AddSimulatedObject(),
  73. setup.AddSimulatedObject(),
  74. setup.AddSimulatedObject(),
  75. };
  76. const size_t objectIndex = 3;
  77. setup.RemoveSimulatedObject(objectIndex);
  78. objects.erase(AZStd::next(objects.begin(), objectIndex));
  79. EXPECT_EQ(setup.GetSimulatedObjects(), objects);
  80. }
  81. ///////////////////////////////////////////////////////////////////////////
  82. using SimulatedObjectTestsFixture = SimulatedObjectSetupTestsFixture;
  83. TEST_F(SimulatedObjectTestsFixture, TestSimulatedObject_FindSimulatedJointBySkeletonJointIndex)
  84. {
  85. PrefabLeftArmSkeleton leftArmSkeleton;
  86. Actor actor;
  87. EXPECT_CALL(actor, GetSkeleton())
  88. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  89. SimulatedObjectSetup setup(&actor);
  90. SimulatedObject* object = setup.AddSimulatedObject();
  91. const AZ::u32 jointIndex = PrefabLeftArmSkeleton::leftThumb1Index;
  92. const SimulatedJoint* joint = object->AddSimulatedJoint(jointIndex);
  93. EXPECT_EQ(object->FindSimulatedJointBySkeletonJointIndex(jointIndex), joint);
  94. }
  95. TEST_F(SimulatedObjectTestsFixture, TestSimulatedObject_ContainsSimulatedJoint)
  96. {
  97. PrefabLeftArmSkeleton leftArmSkeleton;
  98. Actor actor;
  99. EXPECT_CALL(actor, GetSkeleton())
  100. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  101. SimulatedObjectSetup setup(&actor);
  102. SimulatedObject* object1 = setup.AddSimulatedObject();
  103. SimulatedObject* object2 = setup.AddSimulatedObject();
  104. const SimulatedJoint* joint1 = object1->AddSimulatedJoint(PrefabLeftArmSkeleton::leftElbowIndex);
  105. const SimulatedJoint* joint2 = object2->AddSimulatedJoint(PrefabLeftArmSkeleton::leftElbowIndex);
  106. EXPECT_TRUE(object1->ContainsSimulatedJoint(joint1));
  107. EXPECT_FALSE(object1->ContainsSimulatedJoint(joint2));
  108. EXPECT_FALSE(object2->ContainsSimulatedJoint(joint1));
  109. EXPECT_TRUE(object2->ContainsSimulatedJoint(joint2));
  110. }
  111. struct AddSimulatedJointAndChildrenParams
  112. {
  113. AZ::u32 m_jointIndex;
  114. size_t m_expectedSimulatedJointCount;
  115. };
  116. class AddSimulatedJointAndChildrenFixture
  117. : public SimulatedObjectTestsFixture
  118. , public testing::WithParamInterface<AddSimulatedJointAndChildrenParams>
  119. {
  120. };
  121. TEST_P(AddSimulatedJointAndChildrenFixture, TestSimulatedObject_AddSimulatedJointAndChildren)
  122. {
  123. PrefabLeftArmSkeleton leftArmSkeleton;
  124. Actor actor;
  125. EXPECT_CALL(actor, GetSkeleton())
  126. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  127. SimulatedObjectSetup setup(&actor);
  128. SimulatedObject* object = setup.AddSimulatedObject();
  129. object->AddSimulatedJointAndChildren(GetParam().m_jointIndex);
  130. EXPECT_EQ(object->GetSimulatedJoints().size(), GetParam().m_expectedSimulatedJointCount);
  131. }
  132. INSTANTIATE_TEST_CASE_P(Test, AddSimulatedJointAndChildrenFixture,
  133. testing::ValuesIn(std::vector<AddSimulatedJointAndChildrenParams>
  134. {
  135. {PrefabLeftArmSkeleton::leftShoulderIndex, 13}, // leftShoulder is a root joint
  136. {PrefabLeftArmSkeleton::leftElbowIndex, 12},
  137. {PrefabLeftArmSkeleton::leftWristIndex, 11},
  138. {PrefabLeftArmSkeleton::leftHandIndex, 10},
  139. {PrefabLeftArmSkeleton::leftThumb1Index, 3},
  140. {PrefabLeftArmSkeleton::leftThumb2Index, 2},
  141. {PrefabLeftArmSkeleton::leftThumb3Index, 1}, // leftThumb is a leaf joint
  142. })
  143. );
  144. class GetSimulatedRootJointFixture
  145. : public SimulatedObjectTestsFixture
  146. , public testing::WithParamInterface<testing::tuple<int, int>>
  147. {
  148. };
  149. // Determine if left is a parent of right, if right is a parent of left, or
  150. // if neither of the two joints are a parent of the other
  151. // Returns: -1 if left is a parent of right,
  152. // 1 if right is a parent of left,
  153. // 0 if neither is a parent of the other
  154. int NodeHasCommonParentImpl(const Node* left, const Node* right, const Node* initialLeft, const Node* initialRight)
  155. {
  156. if (left == right || (!left && !right))
  157. {
  158. return 0;
  159. }
  160. if (left == initialRight)
  161. {
  162. // right is a parent of left
  163. return 1;
  164. }
  165. if (right == initialLeft)
  166. {
  167. // left is a parent of right
  168. return -1;
  169. }
  170. const Node* leftParent = left ? left->GetParentNode() : nullptr;
  171. const Node* rightParent = right ? right->GetParentNode() : nullptr;
  172. return NodeHasCommonParentImpl(leftParent, rightParent, initialLeft, initialRight);
  173. }
  174. int NodeHasCommonParent(const Node* left, const Node* right)
  175. {
  176. return NodeHasCommonParentImpl(left, right, left, right);
  177. }
  178. // This test verifies that when any two joint indexes are added to a
  179. // simulated object, it results in the correct root joints. It is
  180. // parameterized on tuple<int, int>, where the two ints are the joint
  181. // indexes of the PrefabLeftArmSkeleton to add. Index 2 may be -1, in which
  182. // case only joint index 1 will be added to the object.
  183. // For any two joints, it is possible that one joint is in the parent list
  184. // of another joint. In this case, the number of root joints that should be
  185. // in the simulated object is 1. If the two joints are siblings of each
  186. // other, or in some other way unrelated (like not having any common
  187. // parents), then the expected number of root joints is 2.
  188. TEST_P(GetSimulatedRootJointFixture, TestSimulatedObject_GetSimulatedRootJoint)
  189. {
  190. PrefabLeftArmSkeleton leftArmSkeleton;
  191. Actor actor;
  192. EXPECT_CALL(actor, GetSkeleton())
  193. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  194. SimulatedObjectSetup setup(&actor);
  195. SimulatedObject* object = setup.AddSimulatedObject();
  196. const int jointIndex1 = testing::get<0>(GetParam());
  197. const int jointIndex2 = testing::get<1>(GetParam());
  198. object->AddSimulatedJointAndChildren(jointIndex1);
  199. if (jointIndex2 >= 0)
  200. {
  201. object->AddSimulatedJointAndChildren(jointIndex2);
  202. }
  203. const SimulatedJoint* simulatedJoint1 = object->FindSimulatedJointBySkeletonJointIndex(jointIndex1);
  204. EXPECT_TRUE(simulatedJoint1);
  205. if (jointIndex2 >= 0 && jointIndex2 != jointIndex1)
  206. {
  207. const SimulatedJoint* simulatedJoint2 = object->FindSimulatedJointBySkeletonJointIndex(jointIndex2);
  208. EXPECT_TRUE(simulatedJoint2);
  209. const Skeleton& skeleton = leftArmSkeleton.m_skeleton;
  210. const int hasCommonParent = NodeHasCommonParent(skeleton.GetNode(jointIndex1), skeleton.GetNode(jointIndex2));
  211. if (hasCommonParent == 0)
  212. {
  213. // simulatedJoint1 and simulatedJoint2 are not in each other's
  214. // parent list
  215. EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1);
  216. EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint2)), simulatedJoint2);
  217. EXPECT_EQ(object->GetNumSimulatedRootJoints(), 2);
  218. }
  219. else if (hasCommonParent < 0)
  220. {
  221. // simulatedJoint1 is a parent of simulatedJoint2
  222. EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1);
  223. EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1);
  224. }
  225. else
  226. {
  227. // simulatedJoint2 is a parent of simulatedJoint1
  228. EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint2)), simulatedJoint2);
  229. EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1);
  230. }
  231. }
  232. else
  233. {
  234. EXPECT_EQ(object->GetSimulatedRootJoint(object->GetSimulatedRootJointIndex(simulatedJoint1)), simulatedJoint1);
  235. EXPECT_EQ(object->GetNumSimulatedRootJoints(), 1);
  236. }
  237. }
  238. INSTANTIATE_TEST_CASE_P(Test, GetSimulatedRootJointFixture,
  239. ::testing::Combine(
  240. ::testing::Values(
  241. PrefabLeftArmSkeleton::leftShoulderIndex,
  242. PrefabLeftArmSkeleton::leftElbowIndex,
  243. PrefabLeftArmSkeleton::leftWristIndex,
  244. PrefabLeftArmSkeleton::leftHandIndex,
  245. PrefabLeftArmSkeleton::leftThumb1Index,
  246. PrefabLeftArmSkeleton::leftThumb2Index,
  247. PrefabLeftArmSkeleton::leftThumb3Index,
  248. PrefabLeftArmSkeleton::leftIndex1Index,
  249. PrefabLeftArmSkeleton::leftIndex2Index,
  250. PrefabLeftArmSkeleton::leftIndex3Index,
  251. PrefabLeftArmSkeleton::leftPinky1Index,
  252. PrefabLeftArmSkeleton::leftPinky2Index,
  253. PrefabLeftArmSkeleton::leftPinky3Index
  254. ),
  255. ::testing::Values(
  256. -1,
  257. PrefabLeftArmSkeleton::leftThumb1Index,
  258. PrefabLeftArmSkeleton::leftThumb2Index,
  259. PrefabLeftArmSkeleton::leftThumb3Index,
  260. PrefabLeftArmSkeleton::leftIndex1Index,
  261. PrefabLeftArmSkeleton::leftIndex2Index,
  262. PrefabLeftArmSkeleton::leftIndex3Index,
  263. PrefabLeftArmSkeleton::leftPinky1Index,
  264. PrefabLeftArmSkeleton::leftPinky2Index,
  265. PrefabLeftArmSkeleton::leftPinky3Index
  266. )
  267. ),
  268. [](const ::testing::TestParamInfo<::testing::tuple<int, int>>& info)
  269. {
  270. const auto getJointName = [](const int jointIndex) -> std::string
  271. {
  272. switch (jointIndex)
  273. {
  274. case PrefabLeftArmSkeleton::leftShoulderIndex:
  275. return "leftShoulder";
  276. break;
  277. case PrefabLeftArmSkeleton::leftElbowIndex:
  278. return "leftElbow";
  279. break;
  280. case PrefabLeftArmSkeleton::leftWristIndex:
  281. return "leftWrist";
  282. break;
  283. case PrefabLeftArmSkeleton::leftHandIndex:
  284. return "leftHand";
  285. break;
  286. case PrefabLeftArmSkeleton::leftThumb1Index:
  287. return "leftThumb1";
  288. break;
  289. case PrefabLeftArmSkeleton::leftThumb2Index:
  290. return "leftThumb2";
  291. break;
  292. case PrefabLeftArmSkeleton::leftThumb3Index:
  293. return "leftThumb3";
  294. break;
  295. case PrefabLeftArmSkeleton::leftIndex1Index:
  296. return "leftIndex1";
  297. break;
  298. case PrefabLeftArmSkeleton::leftIndex2Index:
  299. return "leftIndex2";
  300. break;
  301. case PrefabLeftArmSkeleton::leftIndex3Index:
  302. return "leftIndex3";
  303. break;
  304. case PrefabLeftArmSkeleton::leftPinky1Index:
  305. return "leftPinky1";
  306. break;
  307. case PrefabLeftArmSkeleton::leftPinky2Index:
  308. return "leftPinky2";
  309. break;
  310. case PrefabLeftArmSkeleton::leftPinky3Index:
  311. return "leftPinky3";
  312. break;
  313. default:
  314. return "None";
  315. };
  316. };
  317. return "WithJoints_" + getJointName(testing::get<0>(info.param)) + "_and_" + getJointName(testing::get<1>(info.param));
  318. }
  319. );
  320. ///////////////////////////////////////////////////////////////////////////
  321. using SimulatedJointTestsFixture = SimulatedObjectSetupTestsFixture;
  322. TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_GettersSetters)
  323. {
  324. SimulatedJoint joint;
  325. EXPECT_EQ(joint.GetConeAngleLimit(), 60.0f);
  326. EXPECT_EQ(joint.GetMass(), 1.0f);
  327. EXPECT_EQ(joint.GetStiffness(), 0.0f);
  328. EXPECT_EQ(joint.GetDamping(), 0.001f);
  329. EXPECT_EQ(joint.GetGravityFactor(), 1.0f);
  330. EXPECT_EQ(joint.GetFriction(), 0.0f);
  331. EXPECT_EQ(joint.IsPinned(), false);
  332. const float newConeAngleLimit = 90.0f;
  333. const float newMass = 3.0f;
  334. const float newStiffness = 0.5f;
  335. const float newDamping = 0.1f;
  336. const float newGravityFactor = 1.2f;
  337. const float newFriction = 0.3f;
  338. const bool newPinned = true;
  339. joint.SetConeAngleLimit(newConeAngleLimit);
  340. joint.SetMass(newMass);
  341. joint.SetStiffness(newStiffness);
  342. joint.SetDamping(newDamping);
  343. joint.SetGravityFactor(newGravityFactor);
  344. joint.SetFriction(newFriction);
  345. joint.SetPinned(newPinned);
  346. EXPECT_EQ(joint.GetConeAngleLimit(), newConeAngleLimit);
  347. EXPECT_EQ(joint.GetMass(), newMass);
  348. EXPECT_EQ(joint.GetStiffness(), newStiffness);
  349. EXPECT_EQ(joint.GetDamping(), newDamping);
  350. EXPECT_EQ(joint.GetGravityFactor(), newGravityFactor);
  351. EXPECT_EQ(joint.GetFriction(), newFriction);
  352. EXPECT_EQ(joint.IsPinned(), newPinned);
  353. }
  354. TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_FindParentSimulatedJoint)
  355. {
  356. PrefabLeftArmSkeleton leftArmSkeleton;
  357. Actor actor;
  358. EXPECT_CALL(actor, GetSkeleton())
  359. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  360. SimulatedObjectSetup setup(&actor);
  361. SimulatedObject* object = setup.AddSimulatedObject();
  362. SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index);
  363. SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index);
  364. EXPECT_EQ(simulatedThumb2->FindParentSimulatedJoint(), simulatedThumb1);
  365. EXPECT_EQ(simulatedThumb1->FindParentSimulatedJoint(), nullptr);
  366. }
  367. TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_FindChildSimulatedJoint)
  368. {
  369. PrefabLeftArmSkeleton leftArmSkeleton;
  370. Actor actor;
  371. EXPECT_CALL(actor, GetSkeleton())
  372. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  373. SimulatedObjectSetup setup(&actor);
  374. SimulatedObject* object = setup.AddSimulatedObject();
  375. SimulatedJoint* simulatedHand = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftHandIndex);
  376. SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index);
  377. SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index);
  378. SimulatedJoint* simulatedThumb3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb3Index);
  379. SimulatedJoint* simulatedIndex1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex1Index);
  380. SimulatedJoint* simulatedIndex2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex2Index);
  381. SimulatedJoint* simulatedIndex3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex3Index);
  382. EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(0), simulatedThumb1);
  383. EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(1), simulatedIndex1);
  384. EXPECT_EQ(simulatedHand->FindChildSimulatedJoint(2), nullptr);
  385. EXPECT_EQ(simulatedThumb1->FindChildSimulatedJoint(0), simulatedThumb2);
  386. EXPECT_EQ(simulatedThumb1->FindChildSimulatedJoint(1), nullptr);
  387. EXPECT_EQ(simulatedThumb2->FindChildSimulatedJoint(0), simulatedThumb3);
  388. EXPECT_EQ(simulatedThumb2->FindChildSimulatedJoint(1), nullptr);
  389. EXPECT_EQ(simulatedThumb3->FindChildSimulatedJoint(0), nullptr);
  390. EXPECT_EQ(simulatedIndex1->FindChildSimulatedJoint(0), simulatedIndex2);
  391. EXPECT_EQ(simulatedIndex1->FindChildSimulatedJoint(1), nullptr);
  392. EXPECT_EQ(simulatedIndex2->FindChildSimulatedJoint(0), simulatedIndex3);
  393. EXPECT_EQ(simulatedIndex2->FindChildSimulatedJoint(1), nullptr);
  394. EXPECT_EQ(simulatedIndex3->FindChildSimulatedJoint(0), nullptr);
  395. }
  396. TEST_F(SimulatedJointTestsFixture, TestSimulatedJoint_CalculateSimulatedJointIndex)
  397. {
  398. PrefabLeftArmSkeleton leftArmSkeleton;
  399. Actor actor;
  400. EXPECT_CALL(actor, GetSkeleton())
  401. .WillRepeatedly(testing::Return(&leftArmSkeleton.m_skeleton));
  402. SimulatedObjectSetup setup(&actor);
  403. SimulatedObject* object = setup.AddSimulatedObject();
  404. SimulatedJoint* simulatedIndex3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex3Index);
  405. SimulatedJoint* simulatedIndex2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex2Index);
  406. SimulatedJoint* simulatedIndex1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftIndex1Index);
  407. SimulatedJoint* simulatedThumb3 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb3Index);
  408. SimulatedJoint* simulatedThumb2 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb2Index);
  409. SimulatedJoint* simulatedThumb1 = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftThumb1Index);
  410. SimulatedJoint* simulatedHand = object->AddSimulatedJoint(PrefabLeftArmSkeleton::leftHandIndex);
  411. // Joints get sorted based on their skeletal joint index. Even though
  412. // these joints were added in reverse order, they are stored in a
  413. // sorted array internally.
  414. EXPECT_EQ(simulatedHand->CalculateSimulatedJointIndex().GetValue(), 0);
  415. EXPECT_EQ(simulatedThumb1->CalculateSimulatedJointIndex().GetValue(), 1);
  416. EXPECT_EQ(simulatedThumb2->CalculateSimulatedJointIndex().GetValue(), 2);
  417. EXPECT_EQ(simulatedThumb3->CalculateSimulatedJointIndex().GetValue(), 3);
  418. EXPECT_EQ(simulatedIndex1->CalculateSimulatedJointIndex().GetValue(), 4);
  419. EXPECT_EQ(simulatedIndex2->CalculateSimulatedJointIndex().GetValue(), 5);
  420. EXPECT_EQ(simulatedIndex3->CalculateSimulatedJointIndex().GetValue(), 6);
  421. }
  422. } // namespace SimulatedObjectSetupTests