8884227fe6
This translates all usages of MCore::Array to AZStd::vector. It is designed to be as minimal of a change as possible (no changing to range-for loops or other C++11 stuff). We can decide to submit this wholesale, or submit it to a separate branch that we can then integrate individual files from once we're ready to do a specific class's transition. It does not completely solve the `uint32`->`size_t` transition. One important finding from doing this: `MCore::Array` uses a `memcpy` when it reallocates. `AZStd::vector` will use the contained type's copy or move constructor, per element. This is a significant change in behavior. If you have type, `SomeStruct` that defines a destructor, that type is copyable and not movable. So if you have a `MCore::Array<SomeStruct>`, and you call `Add(); Add(); Add()`, that reallocates 3 times, copying the contents using `memcpy`, and never invokes `SomeStruct`'s copy constructor or destructor. Translating that to `AZStd::vector<SomeStruct>` and calling `push_back(); push_back(); push_back();` will still reallocate 3 times, but it sees that `SomeStruct` is non-movable, and uses the copy constructor to make the copies, and then the destructor on the previous values. This call to the destructor wasn't there before, and can cause things to be deleted that weren't before. The solution to this is to make that struct be a move-only type. Where possible, this was done by changing that type to use `AZStd::unique_ptr` instead of a raw pointer, to get the proper move behavior. Where that is not possible (types that inherit from `MCore::MemoryObject`), a hand-written move constructor was created. In general: GetLength() becomes size() GetMaxLength() becomes capacity() GetIsEmpty() becomes empty() Reserve() becomes reserve() ReserveExact() becomes reserve() Resize() becomes resize() ResizeFast() becomes resize_no_construct() Add() becomes emplace_back() AddExact() becomes emplace_back() AddEmpty() becomes emplace_back() AddEmptyExact() becomes emplace_back() GetPtr() becomes data() GetItem() becomes at() Shrink() becomes shrink_to_fit() GetFirst() becomes front() GetLast() becomes back() Remove() becomes erase() RemoveFirst() becomes erase() RemoveLast() becomes pop_back() RemoveByValue() becomes if (const auto it = AZStd::find(...); it != end(container)) container.erase(it); Insert() becomes emplace() Swap() becomes swap() Clear(true) becomes clear(); shrink_to_fit() Clear() becomes clear(); shrink_to_fit() Clear(false) becomes clear() Swap() becomes swap() Find() becomes AZStd::find MoveElements() becomes AZStd::move SetMemoryCategory() is removed Signed-off-by: Chris Burel <burelc@amazon.com>
161 lines
8.4 KiB
C++
161 lines
8.4 KiB
C++
|
|
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include "AnimGraphFixture.h"
|
|
#include <EMotionFX/Source/AnimGraph.h>
|
|
#include <EMotionFX/Source/AnimGraphStateMachine.h>
|
|
#include <EMotionFX/Source/AnimGraphMotionNode.h>
|
|
#include <EMotionFX/Source/BlendTree.h>
|
|
#include <EMotionFX/Source/BlendTreeBlendNNode.h>
|
|
#include <EMotionFX/Source/BlendTreeVector3DecomposeNode.h>
|
|
#include <EMotionFX/Source/BlendTreeVector2DecomposeNode.h>
|
|
#include <EMotionFX/Source/EMotionFXManager.h>
|
|
#include <EMotionFX/Source/MotionData/NonUniformMotionData.h>
|
|
#include <EMotionFX/Source/MotionSet.h>
|
|
#include <EMotionFX/Source/MotionInstance.h>
|
|
#include <EMotionFX/Source/Motion.h>
|
|
#include <EMotionFX/Source/Parameter/ParameterFactory.h>
|
|
#include <EMotionFX/Source/Parameter/Vector2Parameter.h>
|
|
#include <EMotionFX/Source/Parameter/Vector3Parameter.h>
|
|
#include <EMotionFX/Source/Parameter/ValueParameter.h>
|
|
#include <EMotionFX/Source/BlendTreeParameterNode.h>
|
|
#include <AzCore/std/containers/vector.h>
|
|
|
|
namespace EMotionFX
|
|
{
|
|
|
|
class Vector2ToVector3CompatibilityTests : public AnimGraphFixture
|
|
{
|
|
public:
|
|
void ConstructGraph() override
|
|
{
|
|
AnimGraphFixture::ConstructGraph();
|
|
m_blendTreeAnimGraph = AnimGraphFactory::Create<OneBlendTreeNodeAnimGraph>();
|
|
m_rootStateMachine = m_blendTreeAnimGraph->GetRootStateMachine();
|
|
m_blendTree = m_blendTreeAnimGraph->GetBlendTreeNode();
|
|
|
|
m_blendNNode = aznew BlendTreeBlendNNode();
|
|
m_blendTree->AddChildNode(m_blendNNode);
|
|
BlendTreeFinalNode* finalNode = aznew BlendTreeFinalNode();
|
|
m_blendTree->AddChildNode(finalNode);
|
|
finalNode->AddUnitializedConnection(m_blendNNode, BlendTreeBlendNNode::PORTID_OUTPUT_POSE, BlendTreeFinalNode::PORTID_INPUT_POSE);
|
|
|
|
const int motionNodeCount = 3;
|
|
for (int i = 0; i < motionNodeCount; ++i)
|
|
{
|
|
AnimGraphMotionNode* motionNode = aznew AnimGraphMotionNode();
|
|
m_blendTree->AddChildNode(motionNode);
|
|
m_blendNNode->AddUnitializedConnection(motionNode, AnimGraphMotionNode::PORTID_OUTPUT_POSE, i);
|
|
|
|
// The motion set keeps track of motions by their name. Each motion
|
|
// within the motion set must have a unique name.
|
|
const AZStd::string motionId = AZStd::string::format("testSkeletalMotion%i", i);
|
|
Motion* motion = aznew Motion(motionId.c_str());
|
|
motion->SetMotionData(aznew NonUniformMotionData());
|
|
motion->GetMotionData()->SetDuration(1.0f);
|
|
MotionSet::MotionEntry* motionEntry = aznew MotionSet::MotionEntry(motion->GetName(), motion->GetName(), motion);
|
|
m_motionSet->AddMotionEntry(motionEntry);
|
|
|
|
motionNode->AddMotionId(motionId.c_str());
|
|
}
|
|
|
|
{
|
|
Parameter* parameter = ParameterFactory::Create(azrtti_typeid<Vector3Parameter>());
|
|
parameter->SetName("parameter_vector3_test");
|
|
m_blendTreeAnimGraph->AddParameter(parameter);
|
|
}
|
|
{
|
|
Parameter* parameter = ParameterFactory::Create(azrtti_typeid<Vector2Parameter>());
|
|
parameter->SetName("parameter_vector2_test");
|
|
m_blendTreeAnimGraph->AddParameter(parameter);
|
|
}
|
|
|
|
BlendTreeParameterNode* parameterNode = aznew BlendTreeParameterNode();
|
|
m_blendTree->AddChildNode(parameterNode);
|
|
|
|
m_vector2DecomposeNode = aznew BlendTreeVector2DecomposeNode();
|
|
m_blendTree->AddChildNode(m_vector2DecomposeNode);
|
|
m_vector2DecomposeNode->AddUnitializedConnection(parameterNode, 0, BlendTreeVector2DecomposeNode::INPUTPORT_VECTOR);
|
|
|
|
m_vector3DecomposeNode = aznew BlendTreeVector3DecomposeNode();
|
|
m_blendTree->AddChildNode(m_vector3DecomposeNode);
|
|
m_vector3DecomposeNode->AddUnitializedConnection(parameterNode, 1, BlendTreeVector3DecomposeNode::INPUTPORT_VECTOR);
|
|
|
|
m_blendNNode->AddUnitializedConnection(m_vector3DecomposeNode, BlendTreeVector3DecomposeNode::OUTPUTPORT_X, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
|
|
m_blendTreeAnimGraph->InitAfterLoading();
|
|
}
|
|
|
|
void SetUp() override
|
|
{
|
|
AnimGraphFixture::SetUp();
|
|
m_animGraphInstance->Destroy();
|
|
m_animGraphInstance = m_blendTreeAnimGraph->GetAnimGraphInstance(m_actorInstance, m_motionSet);
|
|
}
|
|
|
|
AZStd::unique_ptr<OneBlendTreeNodeAnimGraph> m_blendTreeAnimGraph;
|
|
BlendTreeBlendNNode* m_blendNNode = nullptr;
|
|
BlendTree* m_blendTree = nullptr;
|
|
BlendTreeVector3DecomposeNode* m_vector3DecomposeNode = nullptr;
|
|
BlendTreeVector2DecomposeNode* m_vector2DecomposeNode = nullptr;
|
|
};
|
|
|
|
TEST_F(Vector2ToVector3CompatibilityTests, Evaluation)
|
|
{
|
|
AZ::Outcome<size_t> vector2ParamIndexOutcome = m_blendTreeAnimGraph->FindValueParameterIndexByName("parameter_vector2_test");
|
|
ASSERT_TRUE(vector2ParamIndexOutcome.IsSuccess());
|
|
AZ::Outcome<size_t> vector3ParamIndexOutcome = m_blendTreeAnimGraph->FindValueParameterIndexByName("parameter_vector3_test");
|
|
ASSERT_TRUE(vector3ParamIndexOutcome.IsSuccess());
|
|
|
|
MCore::AttributeVector2* testVector2Parameter = static_cast<MCore::AttributeVector2*>(m_animGraphInstance->GetParameterValue(static_cast<uint32>(vector2ParamIndexOutcome.GetValue())));
|
|
testVector2Parameter->SetValue(AZ::Vector2(-1.0f, 0.5f));
|
|
|
|
MCore::AttributeVector3* testVector3Parameter = static_cast<MCore::AttributeVector3*>(m_animGraphInstance->GetParameterValue(static_cast<uint32>(vector3ParamIndexOutcome.GetValue())));
|
|
testVector3Parameter->SetValue(AZ::Vector3(1.0f, 2.5f, 3.5f));
|
|
|
|
Evaluate();
|
|
|
|
MCore::AttributeFloat* attributeFloatX = m_vector3DecomposeNode->GetOutputFloat(m_animGraphInstance, BlendTreeVector3DecomposeNode::OUTPUTPORT_X);
|
|
ASSERT_TRUE(attributeFloatX);
|
|
MCore::AttributeFloat* attributeFloatY = m_vector3DecomposeNode->GetOutputFloat(m_animGraphInstance, BlendTreeVector3DecomposeNode::OUTPUTPORT_Y);
|
|
ASSERT_TRUE(attributeFloatY);
|
|
MCore::AttributeFloat* attributeFloatZ = m_vector3DecomposeNode->GetOutputFloat(m_animGraphInstance, BlendTreeVector3DecomposeNode::OUTPUTPORT_Z);
|
|
ASSERT_TRUE(attributeFloatZ);
|
|
|
|
MCore::AttributeFloat* attributeFloatX1 = m_vector2DecomposeNode->GetOutputFloat(m_animGraphInstance, BlendTreeVector2DecomposeNode::OUTPUTPORT_X);
|
|
ASSERT_TRUE(attributeFloatX1);
|
|
MCore::AttributeFloat* attributeFloatY1 = m_vector2DecomposeNode->GetOutputFloat(m_animGraphInstance, BlendTreeVector2DecomposeNode::OUTPUTPORT_Y);
|
|
ASSERT_TRUE(attributeFloatY1);
|
|
|
|
const AZ::Vector2& testParameterVector2Value = testVector2Parameter->GetValue();
|
|
const AZ::Vector3 testParameterVector3Value(testVector3Parameter->GetValue());
|
|
const float tolerance = 0.001f;
|
|
float outX = attributeFloatX->GetValue();
|
|
float outY = attributeFloatY->GetValue();
|
|
float outZ = attributeFloatZ->GetValue();
|
|
AZ::Vector3 decomposedValuesVector3(outX, outY, outZ);
|
|
AZ::Vector3 expectedDecomposedValuesVector3(testParameterVector2Value.GetX(), testParameterVector2Value.GetY(), 0.0f);
|
|
float differenceLength = static_cast<float>((expectedDecomposedValuesVector3 - decomposedValuesVector3).GetLength());
|
|
ASSERT_TRUE(AZ::IsClose(0, differenceLength, tolerance));
|
|
|
|
m_blendNNode->RemoveConnection(m_vector3DecomposeNode, BlendTreeVector3DecomposeNode::OUTPUTPORT_X, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
|
|
m_blendNNode->AddConnection(m_vector2DecomposeNode, BlendTreeVector3DecomposeNode::OUTPUTPORT_X, BlendTreeBlendNNode::INPUTPORT_WEIGHT);
|
|
|
|
Evaluate();
|
|
|
|
outX = attributeFloatX1->GetValue();
|
|
outY = attributeFloatY1->GetValue();
|
|
|
|
AZ::Vector2 decomposedValuesVector2(outX, outY);
|
|
AZ::Vector2 expectedDecomposedValuesVector2(testParameterVector3Value.GetX(), testParameterVector3Value.GetY());
|
|
differenceLength = static_cast<float>((expectedDecomposedValuesVector2 - decomposedValuesVector2).GetLength());
|
|
ASSERT_TRUE(AZ::IsClose(0, differenceLength, tolerance));
|
|
}
|
|
|
|
} // end namespace EMotionFX
|