3
0

BoolLogicNodeTests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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 "AnimGraphFixture.h"
  9. #include <EMotionFX/Source/AnimGraph.h>
  10. #include <EMotionFX/Source/AnimGraphMotionNode.h>
  11. #include <EMotionFX/Source/AnimGraphStateMachine.h>
  12. #include <EMotionFX/Source/BlendTree.h>
  13. #include <EMotionFX/Source/BlendTreeBlendNNode.h>
  14. #include <EMotionFX/Source/BlendTreeBoolLogicNode.h>
  15. #include <EMotionFX/Source/BlendTreeParameterNode.h>
  16. #include <EMotionFX/Source/EMotionFXManager.h>
  17. #include <EMotionFX/Source/Motion.h>
  18. #include <EMotionFX/Source/MotionInstance.h>
  19. #include <EMotionFX/Source/MotionSet.h>
  20. #include <EMotionFX/Source/Parameter/BoolParameter.h>
  21. #include <EMotionFX/Source/Parameter/ParameterFactory.h>
  22. #include <EMotionFX/Source/MotionData/NonUniformMotionData.h>
  23. #include <AzCore/std/containers/vector.h>
  24. namespace EMotionFX
  25. {
  26. class BoolLogicNodeTests : public AnimGraphFixture
  27. {
  28. public:
  29. void TearDown() override
  30. {
  31. if (m_motionNodes)
  32. {
  33. delete m_motionNodes;
  34. }
  35. AnimGraphFixture::TearDown();
  36. }
  37. void ConstructGraph() override
  38. {
  39. AnimGraphFixture::ConstructGraph();
  40. m_blendTreeAnimGraph = AnimGraphFactory::Create<OneBlendTreeNodeAnimGraph>();
  41. m_rootStateMachine = m_blendTreeAnimGraph->GetRootStateMachine();
  42. m_blendTree = m_blendTreeAnimGraph->GetBlendTreeNode();
  43. m_blendNNode = aznew BlendTreeBlendNNode();
  44. BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
  45. m_blendTree->AddChildNode(m_blendNNode);
  46. m_blendTree->AddChildNode(finalNode);
  47. finalNode->AddConnection(m_blendNNode, BlendTreeBlendNNode::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
  48. const uint16 motionNodeCount = 2;
  49. for (uint16 i = 0; i < motionNodeCount; ++i)
  50. {
  51. AnimGraphMotionNode* motionNode = aznew AnimGraphMotionNode();
  52. m_blendTree->AddChildNode(motionNode);
  53. m_blendNNode->AddConnection(motionNode, AnimGraphMotionNode::PORTID_OUTPUT_POSE, i);
  54. m_motionNodes->push_back(motionNode);
  55. }
  56. m_blendTreeAnimGraph->InitAfterLoading();
  57. }
  58. void SetUp() override
  59. {
  60. m_motionNodes = new AZStd::vector<AnimGraphMotionNode*>();
  61. AnimGraphFixture::SetUp();
  62. m_animGraphInstance->Destroy();
  63. m_animGraphInstance = m_blendTreeAnimGraph->GetAnimGraphInstance(m_actorInstance, m_motionSet);
  64. for (size_t i = 0; i < m_motionNodes->size(); ++i)
  65. {
  66. // The motion set keeps track of motions by their name. Each motion
  67. // within the motion set must have a unique name.
  68. AZStd::string motionId = AZStd::string::format("testSkeletalMotion%zu", i);
  69. Motion* motion = aznew Motion(motionId.c_str());
  70. motion->SetMotionData(aznew NonUniformMotionData());
  71. motion->GetMotionData()->SetDuration(1.0f);
  72. MotionSet::MotionEntry* motionEntry = aznew MotionSet::MotionEntry(motion->GetName(), motion->GetName(), motion);
  73. m_motionSet->AddMotionEntry(motionEntry);
  74. (*m_motionNodes)[i]->AddMotionId(motionId.c_str());
  75. }
  76. }
  77. void AddValueParameter(const AZ::TypeId& typeId, const AZStd::string& name)
  78. {
  79. Parameter* parameter = ParameterFactory::Create(typeId);
  80. parameter->SetName(name);
  81. m_blendTreeAnimGraph->AddParameter(parameter);
  82. m_animGraphInstance->AddMissingParameterValues();
  83. }
  84. bool CalculateExpectedResult(BlendTreeBoolLogicNode::EFunction functionEnum, bool x, bool y, bool& error)
  85. {
  86. bool result = false;
  87. switch (functionEnum)
  88. {
  89. case BlendTreeBoolLogicNode::EFunction::FUNCTION_AND:
  90. result = x && y;
  91. break;
  92. case BlendTreeBoolLogicNode::EFunction::FUNCTION_OR:
  93. result = x || y;
  94. break;
  95. case BlendTreeBoolLogicNode::EFunction::FUNCTION_XOR:
  96. result = x ^ y;
  97. break;
  98. case BlendTreeBoolLogicNode::EFunction::FUNCTION_NAND:
  99. result = !(x && y);
  100. break;
  101. case BlendTreeBoolLogicNode::EFunction::FUNCTION_NOR:
  102. result = !(x || y);
  103. break;
  104. case BlendTreeBoolLogicNode::EFunction::FUNCTION_XNOR:
  105. result = !(x ^ y);
  106. break;
  107. case BlendTreeBoolLogicNode::EFunction::FUNCTION_NOT_X:
  108. result = !x;
  109. break;
  110. case BlendTreeBoolLogicNode::EFunction::FUNCTION_NOT_Y:
  111. result = !y;
  112. break;
  113. default:
  114. error = true;
  115. break;
  116. }
  117. return result;
  118. }
  119. AZStd::vector<AnimGraphMotionNode*>* m_motionNodes = nullptr;
  120. BlendTreeBlendNNode* m_blendNNode = nullptr;
  121. BlendTree* m_blendTree = nullptr;
  122. };
  123. TEST_F(BoolLogicNodeTests, TestBoolLogic)
  124. {
  125. bool success = true;
  126. const AZStd::string nameBoolX("parameter_bool_x_test");
  127. const AZStd::string nameBoolY("parameter_bool_y_test");
  128. AddValueParameter(azrtti_typeid<BoolParameter>(), nameBoolX);
  129. AddValueParameter(azrtti_typeid<BoolParameter>(), nameBoolY);
  130. BlendTreeParameterNode* parameterNode = aznew BlendTreeParameterNode();
  131. m_blendTree->AddChildNode(parameterNode);
  132. parameterNode->InitAfterLoading(m_blendTreeAnimGraph.get());
  133. parameterNode->InvalidateUniqueData(m_animGraphInstance);
  134. BlendTreeBoolLogicNode* boolLogicNode = aznew BlendTreeBoolLogicNode();
  135. m_blendTree->AddChildNode(boolLogicNode);
  136. boolLogicNode->InitAfterLoading(m_blendTreeAnimGraph.get());
  137. boolLogicNode->InvalidateUniqueData(m_animGraphInstance);
  138. const AZ::Outcome<size_t> boolXParamIndexOutcome = m_animGraphInstance->FindParameterIndex(nameBoolX);
  139. const AZ::Outcome<size_t> boolYParamIndexOutcome = m_animGraphInstance->FindParameterIndex(nameBoolY);
  140. success = boolXParamIndexOutcome.IsSuccess() && boolYParamIndexOutcome.IsSuccess();
  141. uint32 boolXOutputPortIndex = InvalidIndex32;
  142. uint32 boolYOutputPortIndex = InvalidIndex32;
  143. const int portIndicesTosetCount = 2;
  144. int portIndicesFound = 0;
  145. const AZStd::vector<EMotionFX::AnimGraphNode::Port>& parameterNodeOutputPorts = parameterNode->GetOutputPorts();
  146. for (const EMotionFX::AnimGraphNode::Port& port : parameterNodeOutputPorts)
  147. {
  148. uint32 paramIndex = parameterNode->GetParameterIndex(port.m_portId);
  149. if (paramIndex == boolXParamIndexOutcome.GetValue())
  150. {
  151. boolXOutputPortIndex = port.m_portId;
  152. portIndicesFound++;
  153. }
  154. else if (paramIndex == boolYParamIndexOutcome.GetValue())
  155. {
  156. boolYOutputPortIndex = port.m_portId;
  157. portIndicesFound++;
  158. }
  159. }
  160. success = success && (portIndicesFound == portIndicesTosetCount);
  161. bool expectedResultSuccessful = true;
  162. if (success)
  163. {
  164. boolLogicNode->AddConnection(parameterNode, static_cast<uint16>(boolXOutputPortIndex), BlendTreeBoolLogicNode::INPUTPORT_X);
  165. boolLogicNode->AddConnection(parameterNode, static_cast<uint16>(boolYOutputPortIndex), BlendTreeBoolLogicNode::INPUTPORT_Y);
  166. m_blendNNode->AddConnection(boolLogicNode, BlendTreeBoolLogicNode::OUTPUTPORT_BOOL, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  167. m_blendTreeAnimGraph->RecursiveReinit();
  168. MCore::AttributeBool* testBoolXParameter = static_cast<MCore::AttributeBool*>(m_animGraphInstance->FindParameter(nameBoolX));
  169. testBoolXParameter->SetValue(false);
  170. MCore::AttributeBool* testBoolYParameter = static_cast<MCore::AttributeBool*>(m_animGraphInstance->FindParameter(nameBoolY));
  171. testBoolYParameter->SetValue(false);
  172. Evaluate();
  173. MCore::Attribute* attribute = m_blendNNode->GetInputAttribute(m_animGraphInstance, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  174. if (!attribute)
  175. {
  176. success = false;
  177. }
  178. else
  179. {
  180. // Odds are X even are Y
  181. const bool tableOfTruthInput[8] = { false, false, false, true, true, false, true, true };
  182. BlendTreeBoolLogicNode::EFunction functions[8] = {
  183. BlendTreeBoolLogicNode::EFunction::FUNCTION_AND, BlendTreeBoolLogicNode::EFunction::FUNCTION_OR,
  184. BlendTreeBoolLogicNode::EFunction::FUNCTION_XOR, BlendTreeBoolLogicNode::EFunction::FUNCTION_NAND,
  185. BlendTreeBoolLogicNode::EFunction::FUNCTION_NOR, BlendTreeBoolLogicNode::EFunction::FUNCTION_XNOR,
  186. BlendTreeBoolLogicNode::EFunction::FUNCTION_NOT_X, BlendTreeBoolLogicNode::EFunction::FUNCTION_NOT_Y
  187. };
  188. for (int functionIndex = 0; functionIndex < 8; ++functionIndex)
  189. {
  190. boolLogicNode->SetFunction(functions[functionIndex]);
  191. for (int inputIndex = 0; inputIndex < 8; inputIndex += 2)
  192. {
  193. testBoolXParameter->SetValue(tableOfTruthInput[inputIndex]);
  194. testBoolYParameter->SetValue(tableOfTruthInput[inputIndex + 1]);
  195. Evaluate();
  196. bool error = false;
  197. const bool expectedResult = CalculateExpectedResult(boolLogicNode->GetFunction(), testBoolXParameter->GetValue(), testBoolYParameter->GetValue(), error);
  198. const bool result = m_blendNNode->GetInputNumberAsBool(m_animGraphInstance, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
  199. EXPECT_FALSE(error) << "Boolean logic node: CalculateExpectedResult returned error";
  200. EXPECT_EQ(result, expectedResult) << "Boolean logic node: function " << functions[functionIndex] << " did not return the expected result";
  201. expectedResultSuccessful = expectedResultSuccessful && !error && (result == expectedResult);
  202. }
  203. }
  204. }
  205. }
  206. ASSERT_TRUE(success && expectedResultSuccessful);
  207. }
  208. } // end namespace EMotionFX