Made BlendTreeResource::m_nodes and ::m_connections private.

This is a prerequisite to properly track Node input/output connections and to compute eval order in the BlendTreeResources.
RefactorUnifiedBlendTreeStateMachineHandling
Martin Felis 2024-04-16 22:11:59 +02:00
parent 2d5337ed1d
commit d95bc9fb9c
3 changed files with 220 additions and 276 deletions

View File

@ -222,16 +222,16 @@ AnimNodeResource* sAnimGraphNodeFromJson(
// //
// AnimGraphConnectionResource <-> Json // AnimGraphConnectionResource <-> Json
// //
json sAnimGraphConnectionToJson(const BlendTreeConnectionResource& connection) { json sAnimGraphConnectionToJson(const BlendTreeConnectionResource* connection) {
json result; json result;
result["type"] = "AnimGraphConnectionResource"; result["type"] = "AnimGraphConnectionResource";
result["source_node_index"] = connection.source_node_index; result["source_node_index"] = connection->source_node_index;
result["source_socket_name"] = connection.source_socket_name; result["source_socket_name"] = connection->source_socket_name;
result["target_node_index"] = connection.target_node_index; result["target_node_index"] = connection->target_node_index;
result["target_socket_name"] = connection.target_socket_name; result["target_socket_name"] = connection->target_socket_name;
return result; return result;
} }
@ -260,8 +260,8 @@ static json sAnimGraphResourceBlendTreeToJson(
const BlendTreeResource& blend_tree_resource = const BlendTreeResource& blend_tree_resource =
anim_graph_resource.m_blend_tree_resource; anim_graph_resource.m_blend_tree_resource;
for (size_t i = 0; i < blend_tree_resource.m_nodes.size(); i++) { for (size_t i = 0; i < blend_tree_resource.GetNumNodes(); i++) {
const AnimNodeResource* node = blend_tree_resource.m_nodes[i]; const AnimNodeResource* node = blend_tree_resource.GetNode(i);
if (node->m_node_type_name == "BlendTree") { if (node->m_node_type_name == "BlendTree") {
const AnimGraphResource* graph_resource = const AnimGraphResource* graph_resource =
@ -269,26 +269,26 @@ static json sAnimGraphResourceBlendTreeToJson(
result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource); result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource);
} else { } else {
result["nodes"][i] = result["nodes"][i] =
sAnimGraphNodeToJson(node, i, blend_tree_resource.m_connections); sAnimGraphNodeToJson(node, i, blend_tree_resource.GetConnections());
} }
} }
for (size_t i = 0; i < blend_tree_resource.m_connections.size(); i++) { for (size_t i = 0; i < blend_tree_resource.GetNumConnections(); i++) {
const BlendTreeConnectionResource& connection = const BlendTreeConnectionResource* connection =
blend_tree_resource.m_connections[i]; blend_tree_resource.GetConnection(i);
result["connections"][i] = sAnimGraphConnectionToJson(connection); result["connections"][i] = sAnimGraphConnectionToJson(connection);
} }
// Graph inputs and outputs // Graph inputs and outputs
{ {
const AnimNodeResource* graph_output_node = blend_tree_resource.m_nodes[0]; const AnimNodeResource* graph_output_node = blend_tree_resource.GetNode(0);
const std::vector<Socket> graph_inputs = const std::vector<Socket> graph_inputs =
graph_output_node->m_socket_accessor->m_inputs; graph_output_node->m_socket_accessor->m_inputs;
for (size_t i = 0; i < graph_inputs.size(); i++) { for (size_t i = 0; i < graph_inputs.size(); i++) {
result["nodes"][0]["inputs"][i] = sSocketToJson(graph_inputs[i]); result["nodes"][0]["inputs"][i] = sSocketToJson(graph_inputs[i]);
} }
const AnimNodeResource* graph_input_node = blend_tree_resource.m_nodes[1]; const AnimNodeResource* graph_input_node = blend_tree_resource.GetNode(1);
const std::vector<Socket> graph_outputs = const std::vector<Socket> graph_outputs =
graph_input_node->m_socket_accessor->m_outputs; graph_input_node->m_socket_accessor->m_outputs;
for (size_t i = 0; i < graph_outputs.size(); i++) { for (size_t i = 0; i < graph_outputs.size(); i++) {
@ -319,13 +319,13 @@ static bool sAnimGraphResourceBlendTreeFromJson(
} }
AnimNodeResource* node = sAnimGraphNodeFromJson(json_node, i); AnimNodeResource* node = sAnimGraphNodeFromJson(json_node, i);
blend_tree_resource.m_nodes.push_back(node); blend_tree_resource.AddNode(node);
} }
// Graph outputs // Graph outputs
const json& graph_outputs = json_data["nodes"][0]["inputs"]; const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (const auto& graph_output : graph_outputs) { for (const auto& graph_output : graph_outputs) {
AnimNodeResource* graph_node = blend_tree_resource.m_nodes[0]; AnimNodeResource* graph_node = blend_tree_resource.GetNode(0);
graph_node->m_socket_accessor->m_inputs.push_back( graph_node->m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_output)); sJsonToSocket(graph_output));
} }
@ -334,7 +334,7 @@ static bool sAnimGraphResourceBlendTreeFromJson(
if (json_data["nodes"][1].contains("outputs")) { if (json_data["nodes"][1].contains("outputs")) {
const json& graph_inputs = json_data["nodes"][1]["outputs"]; const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (const auto& graph_input : graph_inputs) { for (const auto& graph_input : graph_inputs) {
AnimNodeResource* graph_node = blend_tree_resource.m_nodes[1]; AnimNodeResource* graph_node = blend_tree_resource.GetNode(1);
graph_node->m_socket_accessor->m_outputs.push_back( graph_node->m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_input)); sJsonToSocket(graph_input));
} }
@ -352,7 +352,12 @@ static bool sAnimGraphResourceBlendTreeFromJson(
BlendTreeConnectionResource connection = BlendTreeConnectionResource connection =
sAnimGraphConnectionFromJson(json_connection); sAnimGraphConnectionFromJson(json_connection);
blend_tree_resource.m_connections.push_back(connection);
blend_tree_resource.ConnectSockets(
blend_tree_resource.GetNode(connection.source_node_index),
connection.source_socket_name,
blend_tree_resource.GetNode(connection.target_node_index),
connection.target_socket_name);
} }
return true; return true;
@ -420,6 +425,11 @@ bool BlendTreeResource::ConnectSockets(
connection.target_socket_name = target_socket_name; connection.target_socket_name = target_socket_name;
m_connections.push_back(connection); m_connections.push_back(connection);
m_node_input_connection_indices[target_node_index].emplace_back(
m_connections.size() - 1);
m_node_output_connection_indices[source_node_index].emplace_back(
m_connections.size() - 1);
return true; return true;
} }
@ -509,12 +519,13 @@ void AnimGraphResource::CreateBlendTreeInstance(
void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances( void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances(
AnimGraphBlendTree& result) const { AnimGraphBlendTree& result) const {
for (auto node_resource : m_blend_tree_resource.m_nodes) { for (const AnimNodeResource* node_resource :
m_blend_tree_resource.GetNodes()) {
AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name); AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name);
if (node_resource->m_node_type_name == "BlendTree") { if (node_resource->m_node_type_name == "BlendTree") {
AnimGraphResource* embedded_blend_tree_resource = const AnimGraphResource* embedded_blend_tree_resource =
dynamic_cast<AnimGraphResource*>(node_resource); dynamic_cast<const AnimGraphResource*>(node_resource);
assert(embedded_blend_tree_resource != nullptr); assert(embedded_blend_tree_resource != nullptr);
AnimGraphBlendTree* embedded_blend_tree = AnimGraphBlendTree* embedded_blend_tree =
dynamic_cast<AnimGraphBlendTree*>(node); dynamic_cast<AnimGraphBlendTree*>(node);
@ -545,9 +556,9 @@ void AnimGraphResource::PrepareBlendTreeIOData(
AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]); AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]);
instance.m_node_descriptor->m_outputs = instance.m_node_descriptor->m_outputs =
m_blend_tree_resource.m_nodes[1]->m_socket_accessor->m_outputs; m_blend_tree_resource.GetNode(1)->m_socket_accessor->m_outputs;
instance.m_node_descriptor->m_inputs = instance.m_node_descriptor->m_inputs =
m_blend_tree_resource.m_nodes[0]->m_socket_accessor->m_inputs; m_blend_tree_resource.GetNode(0)->m_socket_accessor->m_inputs;
// //
// graph inputs // graph inputs
@ -597,9 +608,10 @@ void AnimGraphResource::PrepareBlendTreeIOData(
// connecton data storage // connecton data storage
// //
size_t connection_data_storage_size = 0; size_t connection_data_storage_size = 0;
for (const auto& connection : m_blend_tree_resource.m_connections) { for (const BlendTreeConnectionResource& connection :
m_blend_tree_resource.GetConnections()) {
const AnimNodeResource* source_node = const AnimNodeResource* source_node =
m_blend_tree_resource.m_nodes[connection.source_node_index]; m_blend_tree_resource.GetNode(connection.source_node_index);
Socket* source_socket = source_node->m_socket_accessor->GetOutputSocket( Socket* source_socket = source_node->m_socket_accessor->GetOutputSocket(
connection.source_socket_name.c_str()); connection.source_socket_name.c_str());
@ -622,19 +634,19 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
AnimGraphBlendTree& instance, AnimGraphBlendTree& instance,
NodeSocketDataOffsetMap& node_offset_map) const { NodeSocketDataOffsetMap& node_offset_map) const {
std::vector<NodeDescriptorBase*> instance_node_descriptors( std::vector<NodeDescriptorBase*> instance_node_descriptors(
m_blend_tree_resource.m_nodes.size(), m_blend_tree_resource.GetNumNodes(),
nullptr); nullptr);
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) { for (int i = 0; i < m_blend_tree_resource.GetNumNodes(); i++) {
instance_node_descriptors[i] = AnimNodeDescriptorFactory( instance_node_descriptors[i] = AnimNodeDescriptorFactory(
m_blend_tree_resource.m_nodes[i]->m_node_type_name, m_blend_tree_resource.GetNode(i)->m_node_type_name,
instance.m_nodes[i]); instance.m_nodes[i]);
if (i > 1 if (i > 1
&& m_blend_tree_resource.m_nodes[i]->m_node_type_name == "BlendTree") { && m_blend_tree_resource.GetNode(i)->m_node_type_name == "BlendTree") {
instance_node_descriptors[i]->m_inputs = instance_node_descriptors[i]->m_inputs =
m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_inputs; m_blend_tree_resource.GetNode(i)->m_socket_accessor->m_inputs;
instance_node_descriptors[i]->m_outputs = instance_node_descriptors[i]->m_outputs =
m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_outputs; m_blend_tree_resource.GetNode(i)->m_socket_accessor->m_outputs;
} }
} }
@ -642,7 +654,9 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
instance_node_descriptors[1]->m_outputs = instance_node_descriptors[1]->m_outputs =
instance.m_node_descriptor->m_outputs; instance.m_node_descriptor->m_outputs;
for (const auto& connection : m_blend_tree_resource.m_connections) { size_t connection_data_offset = 0;
for (const BlendTreeConnectionResource& connection :
m_blend_tree_resource.GetConnections()) {
NodeDescriptorBase* source_node_descriptor = NodeDescriptorBase* source_node_descriptor =
instance_node_descriptors[connection.source_node_index]; instance_node_descriptors[connection.source_node_index];
NodeDescriptorBase* target_node_descriptor = NodeDescriptorBase* target_node_descriptor =
@ -684,9 +698,9 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
instance.m_node_output_connections[connection.source_node_index] instance.m_node_output_connections[connection.source_node_index]
.push_back(embedded_graph_activation_connection); .push_back(embedded_graph_activation_connection);
AnimGraphResource* source_blend_tree_resource = const AnimGraphResource* source_blend_tree_resource =
dynamic_cast<AnimGraphResource*>( dynamic_cast<const AnimGraphResource*>(
m_blend_tree_resource.m_nodes[connection.source_node_index]); m_blend_tree_resource.GetNode(connection.source_node_index));
AnimGraphBlendTree* source_blend_tree = AnimGraphBlendTree* source_blend_tree =
dynamic_cast<AnimGraphBlendTree*>(source_node); dynamic_cast<AnimGraphBlendTree*>(source_node);
@ -701,9 +715,9 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
// that the embedded node knows about its connection partner in the parent // that the embedded node knows about its connection partner in the parent
// tree. This allows the embedded node to properly activate the node in // tree. This allows the embedded node to properly activate the node in
// the parent graph. // the parent graph.
AnimGraphResource* target_blend_tree_resource = const AnimGraphResource* target_blend_tree_resource =
dynamic_cast<AnimGraphResource*>( dynamic_cast<const AnimGraphResource*>(
m_blend_tree_resource.m_nodes[connection.target_node_index]); m_blend_tree_resource.GetNode(connection.target_node_index));
AnimGraphBlendTree* target_blend_tree = AnimGraphBlendTree* target_blend_tree =
dynamic_cast<AnimGraphBlendTree*>(target_node); dynamic_cast<AnimGraphBlendTree*>(target_node);
@ -750,7 +764,7 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
} }
NodeSocketPair node_socket_pair{ NodeSocketPair node_socket_pair{
m_blend_tree_resource.m_nodes[connection.source_node_index], m_blend_tree_resource.GetNode(connection.source_node_index),
source_socket->m_name}; source_socket->m_name};
NodeSocketDataOffsetMap::const_iterator socket_data_offset_iter = NodeSocketDataOffsetMap::const_iterator socket_data_offset_iter =
@ -822,15 +836,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
const_input_buffer_offset += i->m_type_size; const_input_buffer_offset += i->m_type_size;
} }
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) { for (int i = 0; i < m_blend_tree_resource.GetNumNodes(); i++) {
delete instance_node_descriptors[i]; delete instance_node_descriptors[i];
} }
} }
void AnimGraphResource::SetRuntimeNodeProperties( void AnimGraphResource::SetRuntimeNodeProperties(
AnimGraphBlendTree& result) const { AnimGraphBlendTree& result) const {
for (int i = 2; i < m_blend_tree_resource.m_nodes.size(); i++) { for (int i = 2; i < m_blend_tree_resource.GetNumNodes(); i++) {
const AnimNodeResource* node_resource = m_blend_tree_resource.m_nodes[i]; const AnimNodeResource* node_resource = m_blend_tree_resource.GetNode(i);
NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory( NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory(
node_resource->m_node_type_name, node_resource->m_node_type_name,

View File

@ -32,8 +32,8 @@ struct BlendTreeConnectionResource {
}; };
struct BlendTreeResource { struct BlendTreeResource {
std::vector<AnimNodeResource*> m_nodes; std::vector<std::vector<size_t> > m_node_input_connection_indices;
std::vector<BlendTreeConnectionResource> m_connections; std::vector<std::vector<size_t> > m_node_output_connection_indices;
~BlendTreeResource() { CleanupNodes(); } ~BlendTreeResource() { CleanupNodes(); }
@ -41,6 +41,9 @@ struct BlendTreeResource {
CleanupNodes(); CleanupNodes();
m_connections.clear(); m_connections.clear();
m_node_input_connection_indices.clear();
m_node_output_connection_indices.clear();
} }
void CleanupNodes() { void CleanupNodes() {
@ -54,10 +57,13 @@ struct BlendTreeResource {
} }
void InitGraphConnectors() { void InitGraphConnectors() {
m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets")); AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
m_nodes[0]->m_name = "Outputs"; AnimNodeResource* output_node = GetGraphOutputNode();
m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets")); output_node->m_name = "Outputs";
m_nodes[1]->m_name = "Inputs";
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* input_node = GetGraphInputNode();
output_node->m_name = "Inputs";
} }
[[nodiscard]] AnimNodeResource* GetGraphOutputNode() const { [[nodiscard]] AnimNodeResource* GetGraphOutputNode() const {
@ -77,6 +83,40 @@ struct BlendTreeResource {
return -1; return -1;
} }
[[maybe_unused]] size_t AddNode(AnimNodeResource* node_resource) {
m_nodes.push_back(node_resource);
m_node_input_connection_indices.emplace_back();
m_node_output_connection_indices.emplace_back();
return m_nodes.size() - 1;
}
[[nodiscard]] size_t GetNumNodes() const { return m_nodes.size(); }
[[nodiscard]] AnimNodeResource* GetNode(size_t i) { return m_nodes[i]; }
[[nodiscard]] const AnimNodeResource* GetNode(size_t i) const {
return m_nodes[i];
}
[[nodiscard]] const std::vector<AnimNodeResource*>& GetNodes() const {
return m_nodes;
}
[[nodiscard]] size_t GetNumConnections() const {
return m_connections.size();
}
[[nodiscard]] BlendTreeConnectionResource* GetConnection(size_t i) {
return &m_connections[i];
}
[[nodiscard]] const BlendTreeConnectionResource* GetConnection(
size_t i) const {
return &m_connections[i];
}
[[nodiscard]] const std::vector<BlendTreeConnectionResource>& GetConnections()
const {
return m_connections;
}
bool ConnectSockets( bool ConnectSockets(
const AnimNodeResource* source_node, const AnimNodeResource* source_node,
const std::string& source_socket_name, const std::string& source_socket_name,
@ -143,6 +183,10 @@ struct BlendTreeResource {
return -1; return -1;
} }
private:
std::vector<AnimNodeResource*> m_nodes;
std::vector<BlendTreeConnectionResource> m_connections;
}; };
struct StateMachineTransitionResources { struct StateMachineTransitionResources {

View File

@ -28,11 +28,9 @@ class SimpleAnimSamplerGraphResource {
blend_tree_resource->InitGraphConnectors(); blend_tree_resource->InitGraphConnectors();
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
blend_tree_resource->m_nodes.push_back( walk_node_index =
AnimNodeResourceFactory("AnimSampler")); blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler"));
walk_node_index = blend_tree_resource->m_nodes.size() - 1; walk_node = blend_tree_resource->GetNode(walk_node_index);
walk_node = blend_tree_resource->m_nodes[walk_node_index];
walk_node->m_name = "WalkAnim"; walk_node->m_name = "WalkAnim";
walk_node->m_socket_accessor->SetPropertyValue( walk_node->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
@ -72,28 +70,26 @@ class Blend2GraphResource {
blend_tree_resource->InitGraphConnectors(); blend_tree_resource->InitGraphConnectors();
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
blend_tree_resource->m_nodes.push_back( walk_node_index =
AnimNodeResourceFactory("AnimSampler")); blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler"));
walk_node_index = blend_tree_resource->m_nodes.size() - 1;
blend_tree_resource->m_nodes.push_back( run_node_index =
AnimNodeResourceFactory("AnimSampler")); blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler"));
run_node_index = blend_tree_resource->m_nodes.size() - 1;
blend_tree_resource->m_nodes.push_back(AnimNodeResourceFactory("Blend2")); blend_node_index =
blend_node_index = blend_tree_resource->m_nodes.size() - 1; blend_tree_resource->AddNode(AnimNodeResourceFactory("Blend2"));
walk_node = blend_tree_resource->m_nodes[walk_node_index]; walk_node = blend_tree_resource->GetNode(walk_node_index);
walk_node->m_name = "WalkAnim"; walk_node->m_name = "WalkAnim";
walk_node->m_socket_accessor->SetPropertyValue( walk_node->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
std::string("media/Walking-loop.ozz")); std::string("media/Walking-loop.ozz"));
run_node = blend_tree_resource->m_nodes[run_node_index]; run_node = blend_tree_resource->GetNode(run_node_index);
run_node->m_socket_accessor->SetPropertyValue( run_node->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
std::string("media/Running0-loop.ozz")); std::string("media/Running0-loop.ozz"));
run_node->m_name = "RunAnim"; run_node->m_name = "RunAnim";
blend_node = blend_tree_resource->m_nodes[blend_node_index]; blend_node = blend_tree_resource->GetNode(blend_node_index);
blend_node->m_name = "BlendWalkRun"; blend_node->m_name = "BlendWalkRun";
AnimNodeResource* graph_node = blend_tree_resource->GetGraphOutputNode(); AnimNodeResource* graph_node = blend_tree_resource->GetGraphOutputNode();
@ -161,11 +157,10 @@ class EmbeddedBlendTreeGraphResource {
nullptr); nullptr);
// Parent AnimSampler // Parent AnimSampler
parent_blend_tree_resource->m_nodes.push_back( walk_node_index = parent_blend_tree_resource->AddNode(
AnimNodeResourceFactory("AnimSampler")); AnimNodeResourceFactory("AnimSampler"));
walk_node_index = parent_blend_tree_resource->m_nodes.size() - 1;
walk_node_resource = parent_blend_tree_resource->m_nodes[walk_node_index]; walk_node_resource = parent_blend_tree_resource->GetNode(walk_node_index);
walk_node_resource->m_name = "WalkAnim"; walk_node_resource->m_name = "WalkAnim";
walk_node_resource->m_socket_accessor->SetPropertyValue( walk_node_resource->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
@ -174,12 +169,10 @@ class EmbeddedBlendTreeGraphResource {
// //
// Embedded Tree // Embedded Tree
// //
parent_blend_tree_resource->m_nodes.push_back( embedded_blend_tree_node_index = parent_blend_tree_resource->AddNode(
AnimNodeResourceFactory("BlendTree")); AnimNodeResourceFactory("BlendTree"));
embedded_blend_tree_node_index =
parent_blend_tree_resource->m_nodes.size() - 1;
embedded_graph = dynamic_cast<AnimGraphResource*>( embedded_graph = dynamic_cast<AnimGraphResource*>(
parent_blend_tree_resource->m_nodes.back()); parent_blend_tree_resource->GetNode(embedded_blend_tree_node_index));
embedded_graph->m_name = "EmbeddedBlendTree"; embedded_graph->m_name = "EmbeddedBlendTree";
embedded_graph->m_node_type_name = "BlendTree"; embedded_graph->m_node_type_name = "BlendTree";
embedded_graph->m_graph_type_name = "BlendTree"; embedded_graph->m_graph_type_name = "BlendTree";
@ -200,12 +193,10 @@ class EmbeddedBlendTreeGraphResource {
nullptr); nullptr);
// Embedded: SpeedScale node // Embedded: SpeedScale node
embedded_blend_tree_resource->m_nodes.push_back( embedded_speed_scale_index = embedded_blend_tree_resource->AddNode(
AnimNodeResourceFactory("SpeedScale")); AnimNodeResourceFactory("SpeedScale"));
embedded_speed_scale_index =
embedded_blend_tree_resource->m_nodes.size() - 1;
AnimNodeResource* embedded_speed_scale_resource = AnimNodeResource* embedded_speed_scale_resource =
embedded_blend_tree_resource->m_nodes[embedded_speed_scale_index]; embedded_blend_tree_resource->GetNode(embedded_speed_scale_index);
embedded_speed_scale_resource->m_socket_accessor->SetInputValue( embedded_speed_scale_resource->m_socket_accessor->SetInputValue(
"SpeedScale", "SpeedScale",
0.1f); 0.1f);
@ -291,11 +282,10 @@ class EmbeddedTreeBlend2GraphResource {
nullptr); nullptr);
// Parent AnimSampler // Parent AnimSampler
parent_blend_tree_resource->m_nodes.push_back( walk_node_index = parent_blend_tree_resource->AddNode(
AnimNodeResourceFactory("AnimSampler")); AnimNodeResourceFactory("AnimSampler"));
walk_node_index = parent_blend_tree_resource->m_nodes.size() - 1;
walk_node_resource = parent_blend_tree_resource->m_nodes[walk_node_index]; walk_node_resource = parent_blend_tree_resource->GetNode(walk_node_index);
walk_node_resource->m_name = "WalkAnim"; walk_node_resource->m_name = "WalkAnim";
walk_node_resource->m_socket_accessor->SetPropertyValue( walk_node_resource->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
@ -304,12 +294,10 @@ class EmbeddedTreeBlend2GraphResource {
// //
// Embedded Tree // Embedded Tree
// //
parent_blend_tree_resource->m_nodes.push_back( embedded_blend_tree_node_index = parent_blend_tree_resource->AddNode(
AnimNodeResourceFactory("BlendTree")); AnimNodeResourceFactory("BlendTree"));
embedded_blend_tree_node_index =
parent_blend_tree_resource->m_nodes.size() - 1;
embedded_graph = dynamic_cast<AnimGraphResource*>( embedded_graph = dynamic_cast<AnimGraphResource*>(
parent_blend_tree_resource->m_nodes.back()); parent_blend_tree_resource->GetNode(embedded_blend_tree_node_index));
embedded_graph->m_name = "EmbeddedTreeBlend2GraphResource"; embedded_graph->m_name = "EmbeddedTreeBlend2GraphResource";
embedded_graph->m_node_type_name = "BlendTree"; embedded_graph->m_node_type_name = "BlendTree";
embedded_graph->m_graph_type_name = "BlendTree"; embedded_graph->m_graph_type_name = "BlendTree";
@ -333,24 +321,21 @@ class EmbeddedTreeBlend2GraphResource {
nullptr); nullptr);
// Embedded nodes // Embedded nodes
embedded_blend_tree_resource->m_nodes.push_back( embedded_blend2_node_index = embedded_blend_tree_resource->AddNode(
AnimNodeResourceFactory("Blend2")); AnimNodeResourceFactory("Blend2"));
embedded_blend2_node_index =
embedded_blend_tree_resource->m_nodes.size() - 1;
embedded_blend_tree_resource->m_nodes.push_back( embedded_run_node_index = embedded_blend_tree_resource->AddNode(
AnimNodeResourceFactory("AnimSampler")); AnimNodeResourceFactory("AnimSampler"));
embedded_run_node_index = embedded_blend_tree_resource->m_nodes.size() - 1;
// Configure node resources // Configure node resources
embedded_blend2_node_resource = embedded_blend2_node_resource =
embedded_blend_tree_resource->m_nodes[embedded_blend2_node_index]; embedded_blend_tree_resource->GetNode(embedded_blend2_node_index);
embedded_blend2_node_resource->m_socket_accessor->SetInputValue( embedded_blend2_node_resource->m_socket_accessor->SetInputValue(
"Weight", "Weight",
0.1f); 0.1f);
embedded_run_node_resource = embedded_run_node_resource =
embedded_blend_tree_resource->m_nodes[embedded_run_node_index]; embedded_blend_tree_resource->GetNode(embedded_run_node_index);
embedded_run_node_resource->m_name = "RunAnim"; embedded_run_node_resource->m_name = "RunAnim";
embedded_run_node_resource->m_socket_accessor->SetPropertyValue( embedded_run_node_resource->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
@ -418,6 +403,64 @@ bool load_skeleton(ozz::animation::Skeleton& skeleton, const char* filename) {
return true; return true;
} }
void CheckBlendTreeResourcesEqual(
const BlendTreeResource* blend_tree_resource_reference,
const BlendTreeResource* blend_tree_resource_rhs) {
REQUIRE(
blend_tree_resource_reference->GetNumNodes()
== blend_tree_resource_rhs->GetNumNodes());
for (size_t i = 0; i < blend_tree_resource_reference->GetNumNodes(); i++) {
const AnimNodeResource* node = blend_tree_resource_reference->GetNode(i);
const AnimNodeResource* node_loaded = blend_tree_resource_rhs->GetNode(i);
REQUIRE(node->m_name == node_loaded->m_name);
REQUIRE(node->m_node_type_name == node_loaded->m_node_type_name);
}
REQUIRE(
blend_tree_resource_reference->GetNumConnections()
== blend_tree_resource_rhs->GetNumConnections());
for (size_t i = 0; i < blend_tree_resource_reference->GetNumConnections();
i++) {
const BlendTreeConnectionResource* connection =
blend_tree_resource_reference->GetConnection(i);
const BlendTreeConnectionResource* connection_loaded =
blend_tree_resource_rhs->GetConnection(i);
REQUIRE(
connection->source_node_index == connection_loaded->source_node_index);
REQUIRE(
connection->source_socket_name
== connection_loaded->source_socket_name);
REQUIRE(
connection->target_node_index == connection_loaded->target_node_index);
REQUIRE(
connection->target_socket_name
== connection_loaded->target_socket_name);
}
}
void CheckAnimGraphResourceEqual(
const AnimGraphResource& graph_resource_reference,
const AnimGraphResource& graph_resource_rhs) {
REQUIRE(
graph_resource_reference.m_graph_type_name
== graph_resource_rhs.m_graph_type_name);
REQUIRE(graph_resource_reference.m_name == graph_resource_rhs.m_name);
REQUIRE(graph_resource_reference.m_graph_type_name == "BlendTree");
const BlendTreeResource* blend_tree_resource_reference =
&graph_resource_reference.m_blend_tree_resource;
const BlendTreeResource* blend_tree_resource_rhs =
&graph_resource_rhs.m_blend_tree_resource;
CheckBlendTreeResourcesEqual(
blend_tree_resource_reference,
blend_tree_resource_rhs);
}
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") { TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
int node_id = 3321; int node_id = 3321;
int input_index = 221; int input_index = 221;
@ -447,44 +490,7 @@ TEST_CASE_METHOD(
AnimGraphResource graph_resource_loaded; AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile("TestGraphAnimSamplerBlendTree.json"); graph_resource_loaded.LoadFromFile("TestGraphAnimSamplerBlendTree.json");
REQUIRE( CheckAnimGraphResourceEqual(graph_resource, graph_resource_loaded);
graph_resource.m_graph_type_name
== graph_resource_loaded.m_graph_type_name);
REQUIRE(graph_resource.m_name == graph_resource_loaded.m_name);
BlendTreeResource* blend_tree_resource_loaded =
&graph_resource_loaded.m_blend_tree_resource;
REQUIRE(
blend_tree_resource->m_nodes.size()
== blend_tree_resource_loaded->m_nodes.size());
for (size_t i = 0; i < blend_tree_resource->m_nodes.size(); i++) {
const AnimNodeResource* node = blend_tree_resource->m_nodes[i];
const AnimNodeResource* node_loaded =
blend_tree_resource_loaded->m_nodes[i];
REQUIRE(node->m_name == node_loaded->m_name);
REQUIRE(node->m_node_type_name == node_loaded->m_node_type_name);
}
REQUIRE(
blend_tree_resource->m_connections.size()
== blend_tree_resource_loaded->m_connections.size());
for (size_t i = 0; i < blend_tree_resource->m_connections.size(); i++) {
const BlendTreeConnectionResource& connection =
blend_tree_resource->m_connections[i];
const BlendTreeConnectionResource& connection_loaded =
blend_tree_resource_loaded->m_connections[i];
REQUIRE(
connection.source_node_index == connection_loaded.source_node_index);
REQUIRE(
connection.source_socket_name == connection_loaded.source_socket_name);
REQUIRE(
connection.target_node_index == connection_loaded.target_node_index);
REQUIRE(
connection.target_socket_name == connection_loaded.target_socket_name);
}
} }
TEST_CASE_METHOD( TEST_CASE_METHOD(
@ -558,20 +564,20 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
blend_tree_resource.InitGraphConnectors(); blend_tree_resource.InitGraphConnectors();
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
blend_tree_resource.m_nodes.push_back(AnimNodeResourceFactory("AnimSampler")); size_t walk_node_index =
size_t walk_node_index = blend_tree_resource.m_nodes.size() - 1; blend_tree_resource.AddNode(AnimNodeResourceFactory("AnimSampler"));
blend_tree_resource.m_nodes.push_back(AnimNodeResourceFactory("SpeedScale")); size_t speed_scale_node_index =
size_t speed_scale_node_index = blend_tree_resource.m_nodes.size() - 1; blend_tree_resource.AddNode(AnimNodeResourceFactory("SpeedScale"));
AnimNodeResource* walk_node = blend_tree_resource.m_nodes[walk_node_index]; AnimNodeResource* walk_node = blend_tree_resource.GetNode(walk_node_index);
walk_node->m_name = "WalkAnim"; walk_node->m_name = "WalkAnim";
walk_node->m_socket_accessor->SetPropertyValue( walk_node->m_socket_accessor->SetPropertyValue(
"Filename", "Filename",
std::string("media/Walking-loop.ozz")); std::string("media/Walking-loop.ozz"));
AnimNodeResource* speed_scale_node = AnimNodeResource* speed_scale_node =
blend_tree_resource.m_nodes[speed_scale_node_index]; blend_tree_resource.GetNode(speed_scale_node_index);
speed_scale_node->m_name = "SpeedScale"; speed_scale_node->m_name = "SpeedScale";
float speed_scale_value = 1.35f; float speed_scale_value = 1.35f;
speed_scale_node->m_socket_accessor->SetInputValue( speed_scale_node->m_socket_accessor->SetInputValue(
@ -602,7 +608,7 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
graph_resource_loaded.m_blend_tree_resource; graph_resource_loaded.m_blend_tree_resource;
Socket* speed_scale_resource_loaded_input = Socket* speed_scale_resource_loaded_input =
blend_tree_resource_loaded.m_nodes[speed_scale_node_index] blend_tree_resource_loaded.GetNode(speed_scale_node_index)
->m_socket_accessor->GetInputSocket("SpeedScale"); ->m_socket_accessor->GetInputSocket("SpeedScale");
REQUIRE(speed_scale_resource_loaded_input != nullptr); REQUIRE(speed_scale_resource_loaded_input != nullptr);
@ -628,50 +634,16 @@ TEST_CASE_METHOD(
AnimGraphResource graph_resource_loaded; AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile("TestGraphBlend2Graph.animgraph.json"); graph_resource_loaded.LoadFromFile("TestGraphBlend2Graph.animgraph.json");
REQUIRE( CheckAnimGraphResourceEqual(graph_resource, graph_resource_loaded);
graph_resource.m_graph_type_name
== graph_resource_loaded.m_graph_type_name);
REQUIRE(graph_resource.m_name == graph_resource_loaded.m_name);
BlendTreeResource* blend_tree_resource_loaded = BlendTreeResource* blend_tree_resource_loaded =
&graph_resource_loaded.m_blend_tree_resource; &graph_resource_loaded.m_blend_tree_resource;
REQUIRE(
blend_tree_resource->m_nodes.size()
== blend_tree_resource_loaded->m_nodes.size());
for (size_t i = 0; i < blend_tree_resource->m_nodes.size(); i++) {
const AnimNodeResource* node = blend_tree_resource->m_nodes[i];
const AnimNodeResource* node_loaded =
blend_tree_resource_loaded->m_nodes[i];
REQUIRE(node->m_name == node_loaded->m_name);
REQUIRE(node->m_node_type_name == node_loaded->m_node_type_name);
}
REQUIRE(
blend_tree_resource->m_connections.size()
== blend_tree_resource_loaded->m_connections.size());
for (size_t i = 0; i < blend_tree_resource->m_connections.size(); i++) {
const BlendTreeConnectionResource& connection =
blend_tree_resource->m_connections[i];
const BlendTreeConnectionResource& connection_loaded =
blend_tree_resource_loaded->m_connections[i];
REQUIRE(
connection.source_node_index == connection_loaded.source_node_index);
REQUIRE(
connection.source_socket_name == connection_loaded.source_socket_name);
REQUIRE(
connection.target_node_index == connection_loaded.target_node_index);
REQUIRE(
connection.target_socket_name == connection_loaded.target_socket_name);
}
// Check that the constant weight of the Blend2 node was properly applied when // Check that the constant weight of the Blend2 node was properly applied when
// loading the resource. // loading the resource.
const NodeDescriptor<Blend2Node>* blend2_node_descriptor_loaded = const NodeDescriptor<Blend2Node>* blend2_node_descriptor_loaded =
dynamic_cast<NodeDescriptor<Blend2Node>*>( dynamic_cast<NodeDescriptor<Blend2Node>*>(
blend_tree_resource_loaded->m_nodes[blend_node_index] blend_tree_resource_loaded->GetNode(blend_node_index)
->m_socket_accessor); ->m_socket_accessor);
REQUIRE_THAT( REQUIRE_THAT(
@ -794,9 +766,8 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
blend_tree_resource.InitGraphConnectors(); blend_tree_resource.InitGraphConnectors();
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
blend_tree_resource.m_nodes.push_back( size_t float_to_vec3_node_index = blend_tree_resource.AddNode(
AnimNodeResourceFactory("MathFloatToVec3Node")); AnimNodeResourceFactory("MathFloatToVec3Node"));
size_t float_to_vec3_node_index = blend_tree_resource.m_nodes.size() - 1;
AnimNodeResource* graph_output_node = AnimNodeResource* graph_output_node =
blend_tree_resource.GetGraphOutputNode(); blend_tree_resource.GetGraphOutputNode();
@ -815,7 +786,7 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
AnimNodeResource* float_to_vec3_node_resource = AnimNodeResource* float_to_vec3_node_resource =
blend_tree_resource.m_nodes[float_to_vec3_node_index]; blend_tree_resource.GetNode(float_to_vec3_node_index);
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
graph_input_node_resource, graph_input_node_resource,
@ -856,9 +827,9 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
graph_resource_loaded.m_blend_tree_resource; graph_resource_loaded.m_blend_tree_resource;
const AnimNodeResource* graph_loaded_output_node = const AnimNodeResource* graph_loaded_output_node =
graph_blend_tree_loaded.m_nodes[0]; graph_blend_tree_loaded.GetGraphOutputNode();
const AnimNodeResource* graph_loaded_input_node = const AnimNodeResource* graph_loaded_input_node =
graph_blend_tree_loaded.m_nodes[1]; graph_blend_tree_loaded.GetGraphInputNode();
THEN("Graph inputs and outputs must be in loaded resource as well.") { THEN("Graph inputs and outputs must be in loaded resource as well.") {
REQUIRE( REQUIRE(
@ -952,11 +923,10 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
blend_tree_resource.InitGraphConnectors(); blend_tree_resource.InitGraphConnectors();
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
blend_tree_resource.m_nodes.push_back(AnimNodeResourceFactory("MathAddNode")); size_t math_add0_node_index =
size_t math_add0_node_index = blend_tree_resource.m_nodes.size() - 1; blend_tree_resource.AddNode(AnimNodeResourceFactory("MathAddNode"));
size_t math_add1_node_index =
blend_tree_resource.m_nodes.push_back(AnimNodeResourceFactory("MathAddNode")); blend_tree_resource.AddNode(AnimNodeResourceFactory("MathAddNode"));
size_t math_add1_node_index = blend_tree_resource.m_nodes.size() - 1;
AnimNodeResource* graph_output_node = AnimNodeResource* graph_output_node =
blend_tree_resource.GetGraphOutputNode(); blend_tree_resource.GetGraphOutputNode();
@ -978,9 +948,9 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
AnimNodeResource* math_add0_node = AnimNodeResource* math_add0_node =
blend_tree_resource.m_nodes[math_add0_node_index]; blend_tree_resource.GetNode(math_add0_node_index);
AnimNodeResource* math_add1_node = AnimNodeResource* math_add1_node =
blend_tree_resource.m_nodes[math_add1_node_index]; blend_tree_resource.GetNode(math_add1_node_index);
// direct output // direct output
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
@ -1095,112 +1065,28 @@ TEST_CASE_METHOD(
AnimGraphResource parent_graph_resource_loaded; AnimGraphResource parent_graph_resource_loaded;
parent_graph_resource_loaded.LoadFromFile("TestGraphEmbeddedBlendTree.json"); parent_graph_resource_loaded.LoadFromFile("TestGraphEmbeddedBlendTree.json");
//
// Check the loaded parent graph // Check the loaded parent graph
// CheckAnimGraphResourceEqual(
CHECK(parent_graph_resource.m_name == parent_graph_resource_loaded.m_name); parent_graph_resource,
CHECK( parent_graph_resource_loaded);
parent_graph_resource.m_graph_type_name
== parent_graph_resource_loaded.m_graph_type_name);
CHECK(
parent_graph_resource.m_node_type_name
== parent_graph_resource_loaded.m_node_type_name);
const BlendTreeResource& parent_blend_tree_resource_loaded = const BlendTreeResource& parent_blend_tree_resource_loaded =
parent_graph_resource_loaded.m_blend_tree_resource; parent_graph_resource_loaded.m_blend_tree_resource;
CHECK(
parent_blend_tree_resource->m_nodes.size()
== parent_blend_tree_resource_loaded.m_nodes.size());
for (size_t i = 0; i < parent_blend_tree_resource->m_nodes.size(); i++) {
const AnimNodeResource* parent_node =
parent_blend_tree_resource->m_nodes[i];
const AnimNodeResource* parent_node_loaded =
parent_blend_tree_resource_loaded.m_nodes[i];
CHECK(parent_node->m_name == parent_node_loaded->m_name);
CHECK(
parent_node->m_node_type_name == parent_node_loaded->m_node_type_name);
}
CHECK(
parent_blend_tree_resource->m_connections.size()
== parent_blend_tree_resource_loaded.m_connections.size());
for (size_t i = 0; i < parent_blend_tree_resource->m_connections.size();
i++) {
const BlendTreeConnectionResource& parent_connection =
parent_blend_tree_resource->m_connections[i];
const BlendTreeConnectionResource& parent_connection_loaded =
parent_blend_tree_resource_loaded.m_connections[i];
CHECK(
parent_connection.source_node_index
== parent_connection_loaded.source_node_index);
CHECK(
parent_connection.source_socket_name
== parent_connection_loaded.source_socket_name);
CHECK(
parent_connection.target_node_index
== parent_connection_loaded.target_node_index);
CHECK(
parent_connection.target_socket_name
== parent_connection_loaded.target_socket_name);
}
//
// Check the loaded embedded graph // Check the loaded embedded graph
//
REQUIRE( REQUIRE(
parent_blend_tree_resource_loaded.m_nodes[3]->m_node_type_name parent_blend_tree_resource_loaded.GetNode(3)->m_node_type_name
== "BlendTree"); == "BlendTree");
const AnimGraphResource* embedded_graph_loaded = const AnimGraphResource* embedded_graph_loaded =
dynamic_cast<AnimGraphResource*>( dynamic_cast<const AnimGraphResource*>(
parent_blend_tree_resource_loaded.m_nodes[3]); parent_blend_tree_resource_loaded.GetNode(3));
const BlendTreeResource& embedded_blend_tree_resource_loaded = const BlendTreeResource* embedded_blend_tree_resource_loaded =
embedded_graph_loaded->m_blend_tree_resource; &embedded_graph_loaded->m_blend_tree_resource;
CHECK( CheckBlendTreeResourcesEqual(
embedded_blend_tree_resource->m_nodes.size() embedded_blend_tree_resource,
== embedded_blend_tree_resource_loaded.m_nodes.size()); embedded_blend_tree_resource_loaded);
CHECK(
embedded_blend_tree_resource->m_connections.size()
== embedded_blend_tree_resource_loaded.m_connections.size());
for (size_t i = 0; i < embedded_blend_tree_resource->m_nodes.size(); i++) {
const AnimNodeResource* parent_node =
embedded_blend_tree_resource->m_nodes[i];
const AnimNodeResource* parent_node_loaded =
embedded_blend_tree_resource_loaded.m_nodes[i];
CHECK(parent_node->m_name == parent_node_loaded->m_name);
CHECK(
parent_node->m_node_type_name == parent_node_loaded->m_node_type_name);
}
CHECK(
embedded_blend_tree_resource->m_connections.size()
== embedded_blend_tree_resource_loaded.m_connections.size());
for (size_t i = 0; i < embedded_blend_tree_resource->m_connections.size();
i++) {
const BlendTreeConnectionResource& embedded_connection =
embedded_blend_tree_resource->m_connections[i];
const BlendTreeConnectionResource& embedded_connection_loaded =
embedded_blend_tree_resource_loaded.m_connections[i];
CHECK(
embedded_connection.source_node_index
== embedded_connection_loaded.source_node_index);
CHECK(
embedded_connection.source_socket_name
== embedded_connection_loaded.source_socket_name);
CHECK(
embedded_connection.target_node_index
== embedded_connection_loaded.target_node_index);
CHECK(
embedded_connection.target_socket_name
== embedded_connection_loaded.target_socket_name);
}
} }
TEST_CASE_METHOD( TEST_CASE_METHOD(