Only storing single socket in AnimGraphConnections and simplified wiring logic.

RefactorUnifiedBlendTreeStateMachineHandling
Martin Felis 2024-04-01 21:18:26 +02:00
parent 28eca48a61
commit cd56efca3d
8 changed files with 156 additions and 154 deletions

View File

@ -62,7 +62,8 @@ void AnimGraphBlendTree::UpdateOrderedNodesRecursive(int node_index) {
} }
} }
void AnimGraphBlendTree::MarkActiveInputs(const std::vector<AnimGraphConnection>& input_connections) { void AnimGraphBlendTree::MarkActiveInputs(
const std::vector<AnimGraphConnection>& input_connections) {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
if (m_nodes[i]->m_tick_number != m_tick_number) { if (m_nodes[i]->m_tick_number != m_tick_number) {
m_nodes[i]->m_state = AnimNodeEvalState::Deactivated; m_nodes[i]->m_state = AnimNodeEvalState::Deactivated;
@ -93,8 +94,7 @@ void AnimGraphBlendTree::MarkActiveInputs(const std::vector<AnimGraphConnection>
const AnimGraphConnection& input = const AnimGraphConnection& input =
m_node_input_connections[node_index][j]; m_node_input_connections[node_index][j];
if (input.m_source_node != nullptr if (input.m_source_node != nullptr
&& input.m_target_socket.m_type && input.m_socket.m_type != SocketType::SocketTypeAnimation) {
!= SocketType::SocketTypeAnimation) {
input.m_source_node->m_state = AnimNodeEvalState::Activated; input.m_source_node->m_state = AnimNodeEvalState::Activated;
} }
} }
@ -102,7 +102,8 @@ void AnimGraphBlendTree::MarkActiveInputs(const std::vector<AnimGraphConnection>
} }
} }
void AnimGraphBlendTree::CalcSyncTrack(const std::vector<AnimGraphConnection>& input_connections) { void AnimGraphBlendTree::CalcSyncTrack(
const std::vector<AnimGraphConnection>& input_connections) {
for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) { for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
AnimNode* node = m_eval_ordered_nodes[i]; AnimNode* node = m_eval_ordered_nodes[i];
if (node->m_state == AnimNodeEvalState::Deactivated) { if (node->m_state == AnimNodeEvalState::Deactivated) {
@ -162,54 +163,10 @@ void AnimGraphBlendTree::PropagateTimeToNodeInputs(const AnimNode* node) {
// Only propagate time updates via animation sockets. // Only propagate time updates via animation sockets.
if (input_node != nullptr if (input_node != nullptr
&& node_input_connections[i].m_target_socket.m_type && node_input_connections[i].m_socket.m_type
== SocketType::SocketTypeAnimation == SocketType::SocketTypeAnimation
&& input_node->m_state == AnimNodeEvalState::Activated) { && input_node->m_state == AnimNodeEvalState::Activated) {
input_node->UpdateTime(node_time_last, node_time_now); input_node->UpdateTime(node_time_last, node_time_now);
} }
} }
} }
Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) {
for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) {
AnimGraphConnection& connection = m_node_output_connections[1][i];
if (connection.m_source_socket.m_name == name) {
return &connection.m_source_socket;
}
}
return nullptr;
}
Socket* AnimGraphBlendTree::GetOutputSocket(const std::string& name) {
for (size_t i = 0, n = m_node_input_connections[0].size(); i < n; i++) {
AnimGraphConnection& connection = m_node_input_connections[0][i];
if (connection.m_target_socket.m_name == name) {
return &connection.m_target_socket;
}
}
return nullptr;
}
const Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) const {
for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) {
const AnimGraphConnection& connection = m_node_output_connections[1][i];
if (connection.m_source_socket.m_name == name) {
return &connection.m_source_socket;
}
}
return nullptr;
}
const Socket* AnimGraphBlendTree::GetOutputSocket(const std::string& name) const {
for (size_t i = 0, n = m_node_input_connections[0].size(); i < n; i++) {
const AnimGraphConnection& connection = m_node_input_connections[0][i];
if (connection.m_target_socket.m_name == name) {
return &connection.m_target_socket;
}
}
return nullptr;
}

View File

@ -5,6 +5,8 @@
#ifndef ANIMTESTBED_ANIMGRAPHBLENDTREE_H #ifndef ANIMTESTBED_ANIMGRAPHBLENDTREE_H
#define ANIMTESTBED_ANIMGRAPHBLENDTREE_H #define ANIMTESTBED_ANIMGRAPHBLENDTREE_H
#include <algorithm>
#include "AnimNode.h" #include "AnimNode.h"
// //
@ -17,6 +19,17 @@ struct AnimGraphBlendTree : public AnimNode {
std::vector<AnimNode*> m_eval_ordered_nodes; std::vector<AnimNode*> m_eval_ordered_nodes;
std::vector<std::vector<AnimGraphConnection> > m_node_input_connections; std::vector<std::vector<AnimGraphConnection> > m_node_input_connections;
std::vector<std::vector<AnimGraphConnection> > m_node_output_connections; std::vector<std::vector<AnimGraphConnection> > m_node_output_connections;
[[nodiscard]] const std::vector<AnimGraphConnection>&
GetGraphInputConnections() const {
return m_node_output_connections[1];
}
[[nodiscard]] const std::vector<AnimGraphConnection>&
GetGraphOutputConnections() const {
return m_node_input_connections[0];
}
std::vector<AnimData*> m_animdata_blocks; std::vector<AnimData*> m_animdata_blocks;
NodeDescriptorBase* m_node_descriptor = nullptr; NodeDescriptorBase* m_node_descriptor = nullptr;
char* m_input_buffer = nullptr; char* m_input_buffer = nullptr;
@ -80,9 +93,6 @@ struct AnimGraphBlendTree : public AnimNode {
} }
} }
Socket* GetInputSocket(const std::string& name);
Socket* GetOutputSocket(const std::string& name);
const Socket* GetInputSocket(const std::string& name) const; const Socket* GetInputSocket(const std::string& name) const;
const Socket* GetOutputSocket(const std::string& name) const; const Socket* GetOutputSocket(const std::string& name) const;
@ -96,17 +106,22 @@ struct AnimGraphBlendTree : public AnimNode {
void SetInput(const char* name, T* value_ptr) { void SetInput(const char* name, T* value_ptr) {
m_node_descriptor->SetOutput(name, value_ptr); m_node_descriptor->SetOutput(name, value_ptr);
std::vector<size_t> connected_node_indices;
for (int i = 0; i < m_node_output_connections[1].size(); i++) { for (int i = 0; i < m_node_output_connections[1].size(); i++) {
const AnimGraphConnection& graph_input_connection = const AnimGraphConnection& graph_input_connection =
m_node_output_connections[1][i]; m_node_output_connections[1][i];
if (graph_input_connection.m_source_socket.m_name == name) { if (graph_input_connection.m_source_socket_name == name) {
*graph_input_connection.m_target_socket.m_reference.ptr_ptr = value_ptr; *graph_input_connection.m_socket.m_reference.ptr_ptr = value_ptr;
} }
} }
} }
/** Sets the address that is used for the specified AnimGraph output Socket. /** Sets the address that is used for the specified AnimGraph output Socket.
*
* We update the pointer of the outputting node. We also have to ensure that
* all usages of that output use the same pointer.
* *
* @tparam T Type of the Socket. * @tparam T Type of the Socket.
* @param name Name of the Socket. * @param name Name of the Socket.
@ -114,45 +129,41 @@ struct AnimGraphBlendTree : public AnimNode {
*/ */
template <typename T> template <typename T>
void SetOutput(const char* name, T* value_ptr) { void SetOutput(const char* name, T* value_ptr) {
m_node_descriptor->SetInput(name, value_ptr); const auto& graph_output_connection = std::find_if(
GetGraphOutputConnections().begin(),
GetGraphOutputConnections().end(),
[&name](const AnimGraphConnection& connection) {
return connection.m_target_socket_name == name;
});
for (int i = 0; i < m_node_input_connections[0].size(); i++) { if (graph_output_connection == GetGraphOutputConnections().end()) {
const AnimGraphConnection& graph_output_connection = std::cerr << "Error: could not find graph connection to output socket "
m_node_input_connections[0][i]; << name << "." << std::endl;
return;
}
if (graph_output_connection.m_target_socket.m_name == name) { if (graph_output_connection->m_source_node == m_nodes[1]
if (graph_output_connection.m_source_node == m_nodes[1] && graph_output_connection->m_target_node == m_nodes[0]) {
&& graph_output_connection.m_target_node == m_nodes[0]) { std::cerr << "Error: cannot set output for direct graph input to graph "
std::cerr "output connections. Use GetOutptPtr for output instead!"
<< "Error: cannot set output for direct graph input to graph " << std::endl;
"output connections. Use GetOutptPtr for output instead!"
<< std::endl;
return; return;
} }
*graph_output_connection.m_source_socket.m_reference.ptr_ptr = size_t output_node_index =
value_ptr; GetAnimNodeIndex(graph_output_connection->m_source_node);
// Make sure all other output connections of this pin use the same output pointer const std::vector<AnimGraphConnection>& node_output_connections =
int source_node_index = m_node_output_connections[output_node_index];
GetAnimNodeIndex(graph_output_connection.m_source_node); for (const AnimGraphConnection& connection : node_output_connections) {
for (int j = 0; j < m_node_output_connections[source_node_index].size(); if (connection.m_source_socket_name
j++) { == graph_output_connection->m_source_socket_name) {
const AnimGraphConnection& source_output_connection = *connection.m_socket.m_reference.ptr_ptr = value_ptr;
m_node_output_connections[source_node_index][j];
if (source_output_connection.m_target_node == m_nodes[0]) {
continue;
}
if (source_output_connection.m_source_socket.m_name
== graph_output_connection.m_source_socket.m_name) {
*source_output_connection.m_target_socket.m_reference.ptr_ptr =
value_ptr;
}
}
} }
} }
*graph_output_connection->m_socket.m_reference.ptr_ptr = value_ptr;
} }
/** Returns the address that is used for the specified AnimGraph output Socket. /** Returns the address that is used for the specified AnimGraph output Socket.
@ -169,9 +180,9 @@ struct AnimGraphBlendTree : public AnimNode {
for (int i = 0; i < m_node_input_connections[0].size(); i++) { for (int i = 0; i < m_node_input_connections[0].size(); i++) {
const AnimGraphConnection& graph_output_connection = const AnimGraphConnection& graph_output_connection =
m_node_input_connections[0][i]; m_node_input_connections[0][i];
if (graph_output_connection.m_target_socket.m_name == name) { if (graph_output_connection.m_target_socket_name == name) {
return static_cast<float*>( return static_cast<T*>(
*graph_output_connection.m_source_socket.m_reference.ptr_ptr); *graph_output_connection.m_socket.m_reference.ptr_ptr);
} }
} }
@ -179,18 +190,24 @@ struct AnimGraphBlendTree : public AnimNode {
} }
void* GetInputPtr(const std::string& name) const { void* GetInputPtr(const std::string& name) const {
const Socket* input_socket = GetInputSocket(name); const std::vector<AnimGraphConnection> graph_input_connections =
if (input_socket != nullptr) { GetGraphInputConnections();
return input_socket->m_reference.ptr; for (const AnimGraphConnection& connection : graph_input_connections) {
if (connection.m_source_socket_name == name) {
return connection.m_socket.m_reference.ptr;
}
} }
return nullptr; return nullptr;
} }
void* GetOutputPtr(const std::string& name) const { void* GetOutputPtr(const std::string& name) const {
const Socket* input_socket = GetOutputSocket(name); const std::vector<AnimGraphConnection> graph_output_connections =
if (input_socket != nullptr) { GetGraphOutputConnections();
return input_socket->m_reference.ptr; for (const AnimGraphConnection& connection : graph_output_connections) {
if (connection.m_source_socket_name == name) {
return connection.m_socket.m_reference.ptr;
}
} }
return nullptr; return nullptr;
@ -213,7 +230,7 @@ struct AnimGraphBlendTree : public AnimNode {
const std::vector<AnimGraphConnection>& input_connection = const std::vector<AnimGraphConnection>& input_connection =
m_node_input_connections[node_index]; m_node_input_connections[node_index];
for (size_t i = 0, n = input_connection.size(); i < n; i++) { for (size_t i = 0, n = input_connection.size(); i < n; i++) {
if (input_connection[i].m_target_socket.m_name == input_name) { if (input_connection[i].m_target_socket_name == input_name) {
return input_connection[i].m_source_node; return input_connection[i].m_source_node;
} }
} }

View File

@ -262,13 +262,13 @@ SocketType GetSocketType() {
struct AnimGraphConnection { struct AnimGraphConnection {
AnimNode* m_source_node = nullptr; AnimNode* m_source_node = nullptr;
Socket m_source_socket; std::string m_source_socket_name = "";
AnimNode* m_target_node = nullptr; AnimNode* m_target_node = nullptr;
Socket m_target_socket; std::string m_target_socket_name = "";
Socket m_socket;
bool m_crosses_hierarchy = false; bool m_crosses_hierarchy = false;
}; };
struct NodeDescriptorBase { struct NodeDescriptorBase {
std::vector<Socket> m_inputs; std::vector<Socket> m_inputs;
std::vector<Socket> m_outputs; std::vector<Socket> m_outputs;
@ -431,7 +431,8 @@ struct NodeDescriptorBase {
return nullptr; return nullptr;
} }
const Socket* FindSocket(const char* name, const std::vector<Socket>& sockets) const { const Socket* FindSocket(const char* name, const std::vector<Socket>& sockets)
const {
for (int i = 0, n = sockets.size(); i < n; i++) { for (int i = 0, n = sockets.size(); i < n; i++) {
if (sockets[i].m_name == name) { if (sockets[i].m_name == name) {
return &sockets[i]; return &sockets[i];

View File

@ -32,12 +32,12 @@ struct Blend2Node : public AnimNode {
continue; continue;
} }
if (input.m_target_socket.m_name == "Input0" && *i_blend_weight < 0.999) { if (input.m_target_socket_name == "Input0" && *i_blend_weight < 0.999) {
input_node->m_state = AnimNodeEvalState::Activated; input_node->m_state = AnimNodeEvalState::Activated;
continue; continue;
} }
if (input.m_target_socket.m_name == "Input1" && *i_blend_weight > 0.001) { if (input.m_target_socket_name == "Input1" && *i_blend_weight > 0.001) {
input_node->m_state = AnimNodeEvalState::Activated; input_node->m_state = AnimNodeEvalState::Activated;
continue; continue;
} }

View File

@ -658,9 +658,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
// subgraph. // subgraph.
AnimGraphConnection embedded_graph_activation_connection; AnimGraphConnection embedded_graph_activation_connection;
embedded_graph_activation_connection.m_source_node = source_node; embedded_graph_activation_connection.m_source_node = source_node;
embedded_graph_activation_connection.m_source_socket = *source_socket; embedded_graph_activation_connection.m_source_socket_name =
source_socket->m_name;
embedded_graph_activation_connection.m_target_node = target_node; embedded_graph_activation_connection.m_target_node = target_node;
embedded_graph_activation_connection.m_target_socket = *target_socket; embedded_graph_activation_connection.m_target_socket_name =
target_socket->m_name;
// TODO: what to set the pointer to?!?
embedded_graph_activation_connection.m_socket = *target_socket;
instance.m_node_input_connections[connection.target_node_index].push_back( instance.m_node_input_connections[connection.target_node_index].push_back(
embedded_graph_activation_connection); embedded_graph_activation_connection);
instance.m_node_output_connections[connection.source_node_index] instance.m_node_output_connections[connection.source_node_index]
@ -702,7 +708,7 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
for (size_t j = 0; j < embeded_target_node_inputs.size(); j++) { for (size_t j = 0; j < embeded_target_node_inputs.size(); j++) {
AnimGraphConnection& embedded_target_connection = AnimGraphConnection& embedded_target_connection =
embeded_target_node_inputs[j]; embeded_target_node_inputs[j];
if (embedded_target_connection.m_source_socket.m_name if (embedded_target_connection.m_source_socket_name
== target_socket->m_name) { == target_socket->m_name) {
embedded_target_connection.m_source_node = source_node; embedded_target_connection.m_source_node = source_node;
embedded_target_connection.m_crosses_hierarchy = true; embedded_target_connection.m_crosses_hierarchy = true;
@ -711,27 +717,35 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances(
// connection in the parent blend tree. That way // connection in the parent blend tree. That way
// parent_tree.SetValue<>() correctly propagates the value to the // parent_tree.SetValue<>() correctly propagates the value to the
// embedded node socket. // embedded node socket.
target_socket = &embedded_target_connection.m_target_socket; target_socket = &embedded_target_connection.m_socket;
} }
} }
} }
instance_connection.m_source_node = source_node; instance_connection.m_source_node = source_node;
instance_connection.m_source_socket = *source_socket; instance_connection.m_source_socket_name = source_socket->m_name;
instance_connection.m_target_node = target_node; instance_connection.m_target_node = target_node;
instance_connection.m_target_socket = *target_socket; instance_connection.m_target_socket_name = target_socket->m_name;
instance_connection.m_socket = *target_socket;
if (connection.source_node_index == 1) {
instance_connection.m_socket = *target_socket;
} else if (connection.target_node_index == 0) {
instance_connection.m_socket = *source_socket;
} else {
*target_socket->m_reference.ptr_ptr =
&instance.m_connection_data_storage[connection_data_offset];
*source_socket->m_reference.ptr_ptr =
&instance.m_connection_data_storage[connection_data_offset];
}
instance.m_node_input_connections[connection.target_node_index].push_back( instance.m_node_input_connections[connection.target_node_index].push_back(
instance_connection); instance_connection);
instance.m_node_output_connections[connection.source_node_index].push_back( instance.m_node_output_connections[connection.source_node_index].push_back(
instance_connection); instance_connection);
source_node_descriptor->SetOutputUnchecked( *instance_connection.m_socket.m_reference.ptr_ptr =
connection.source_socket_name.c_str(), &instance.m_connection_data_storage[connection_data_offset];
&instance.m_connection_data_storage[connection_data_offset]);
target_node_descriptor->SetInputUnchecked(
connection.target_socket_name.c_str(),
&instance.m_connection_data_storage[connection_data_offset]);
if (source_socket->m_type == SocketType::SocketTypeAnimation) { if (source_socket->m_type == SocketType::SocketTypeAnimation) {
instance.m_animdata_blocks.push_back( instance.m_animdata_blocks.push_back(

View File

@ -5,21 +5,24 @@
#include "AnimGraphStateMachine.h" #include "AnimGraphStateMachine.h"
bool AnimGraphStateMachine::Init(AnimGraphContext& context) { bool AnimGraphStateMachine::Init(AnimGraphContext& context) {
assert(false && !"Not yet implemented!");
return false;
} }
void AnimGraphStateMachine::MarkActiveInputs(const std::vector<AnimGraphConnection>& input_connections) { void AnimGraphStateMachine::MarkActiveInputs(
const std::vector<AnimGraphConnection>& input_connections) {
assert(false && !"Not yet implemented!");
} }
void AnimGraphStateMachine::CalcSyncTrack(const std::vector<AnimGraphConnection>& input_connections) { void AnimGraphStateMachine::CalcSyncTrack(
const std::vector<AnimGraphConnection>& input_connections) {
assert(false && !"Not yet implemented!");
} }
void AnimGraphStateMachine::UpdateTime(float time_last, float time_now) { void AnimGraphStateMachine::UpdateTime(float time_last, float time_now) {
assert(false && !"Not yet implemented!");
} }
void AnimGraphStateMachine::Evaluate(AnimGraphContext& context) { void AnimGraphStateMachine::Evaluate(AnimGraphContext& context) {
assert(false && !"Not yet implemented!");
} }

View File

@ -56,7 +56,7 @@ struct AnimNode {
for (const auto& input : input_connections) { for (const auto& input : input_connections) {
AnimNode* input_node = input.m_source_node; AnimNode* input_node = input.m_source_node;
if (input_node != nullptr if (input_node != nullptr
&& input.m_source_socket.m_type == SocketType::SocketTypeAnimation && input.m_socket.m_type == SocketType::SocketTypeAnimation
&& input_node->m_state != AnimNodeEvalState::Deactivated) { && input_node->m_state != AnimNodeEvalState::Deactivated) {
m_sync_track = input_node->m_sync_track; m_sync_track = input_node->m_sync_track;
return; return;

View File

@ -754,17 +754,14 @@ TEST_CASE_METHOD(
CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output); CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output);
CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output); CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output);
const Socket* graph_output_socket = AnimData* graph_output = static_cast<AnimData*>(
blend_tree_graph.GetOutputSocket("GraphOutput"); blend_tree_graph.GetOutputPtr<AnimData>("GraphOutput"));
AnimData* graph_output =
static_cast<AnimData*>(*graph_output_socket->m_reference.ptr_ptr);
CHECK( CHECK(
graph_output->m_local_matrices.size() graph_output->m_local_matrices.size()
== graph_context.m_skeleton->num_soa_joints()); == graph_context.m_skeleton->num_soa_joints());
CHECK( CHECK(blend2_instance->o_output == graph_output);
blend2_instance->o_output == *graph_output_socket->m_reference.ptr_ptr);
} }
graph_context.freeAnimations(); graph_context.freeAnimations();
@ -811,39 +808,40 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
"GraphVec3Output", "GraphVec3Output",
nullptr); nullptr);
AnimNodeResource* graph_input_node = blend_tree_resource.GetGraphInputNode(); AnimNodeResource* graph_input_node_resource =
graph_input_node->m_socket_accessor->RegisterOutput<float>( blend_tree_resource.GetGraphInputNode();
graph_input_node_resource->m_socket_accessor->RegisterOutput<float>(
"GraphFloatInput", "GraphFloatInput",
nullptr); nullptr);
// Prepare graph inputs and outputs // Prepare graph inputs and outputs
AnimNodeResource* float_to_vec3_node = AnimNodeResource* float_to_vec3_node_resource =
blend_tree_resource.m_nodes[float_to_vec3_node_index]; blend_tree_resource.m_nodes[float_to_vec3_node_index];
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
graph_input_node, graph_input_node_resource,
"GraphFloatInput", "GraphFloatInput",
graph_output_node, graph_output_node,
"GraphFloatOutput")); "GraphFloatOutput"));
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
graph_input_node, graph_input_node_resource,
"GraphFloatInput", "GraphFloatInput",
float_to_vec3_node, float_to_vec3_node_resource,
"Input0")); "Input0"));
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
graph_input_node, graph_input_node_resource,
"GraphFloatInput", "GraphFloatInput",
float_to_vec3_node, float_to_vec3_node_resource,
"Input1")); "Input1"));
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
graph_input_node, graph_input_node_resource,
"GraphFloatInput", "GraphFloatInput",
float_to_vec3_node, float_to_vec3_node_resource,
"Input2")); "Input2"));
REQUIRE(blend_tree_resource.ConnectSockets( REQUIRE(blend_tree_resource.ConnectSockets(
float_to_vec3_node, float_to_vec3_node_resource,
"Output", "Output",
graph_output_node, graph_output_node,
"GraphVec3Output")); "GraphVec3Output"));
@ -869,7 +867,7 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
== graph_loaded_output_node->m_socket_accessor->m_inputs.size()); == graph_loaded_output_node->m_socket_accessor->m_inputs.size());
REQUIRE( REQUIRE(
graph_input_node->m_socket_accessor->m_outputs.size() graph_input_node_resource->m_socket_accessor->m_outputs.size()
== graph_loaded_input_node->m_socket_accessor->m_outputs.size()); == graph_loaded_input_node->m_socket_accessor->m_outputs.size());
REQUIRE( REQUIRE(
@ -890,14 +888,17 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
AnimGraphBlendTree blend_tree_node; AnimGraphBlendTree blend_tree_node;
graph_resource_loaded.CreateBlendTreeInstance(blend_tree_node); graph_resource_loaded.CreateBlendTreeInstance(blend_tree_node);
REQUIRE(blend_tree_node.GetInputSocket("GraphFloatInput") != nullptr);
REQUIRE(
blend_tree_node.GetInputPtr("GraphFloatInput")
== blend_tree_node.m_input_buffer);
float graph_float_input = 123.456f; float graph_float_input = 123.456f;
blend_tree_node.SetInput("GraphFloatInput", &graph_float_input); blend_tree_node.SetInput("GraphFloatInput", &graph_float_input);
MathFloatToVec3Node* float_to_vec3_node =
dynamic_cast<MathFloatToVec3Node*>(
blend_tree_node.m_nodes[float_to_vec3_node_index]);
CHECK(float_to_vec3_node->i_input0 == &graph_float_input);
CHECK(float_to_vec3_node->i_input1 == &graph_float_input);
CHECK(float_to_vec3_node->i_input2 == &graph_float_input);
AND_WHEN("Evaluating Graph") { AND_WHEN("Evaluating Graph") {
AnimGraphContext context; AnimGraphContext context;
context.m_graph = nullptr; context.m_graph = nullptr;
@ -928,6 +929,19 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
} }
} }
//
// Graph:
// Input: float GraphFloatInputSingle
// Output: float GraphFloat0Output
// float GraphFloat1Output
// float GraphFloat1Output
// Nodes: 2x Add Node
// Connections:
// - Direct GraphFloatInputSingle to GraphFQloat0Output
// - Remaining wires such that
// GraphFloat1Output -> GraphFLoatInputSingle * 2
// GraphFloat1Output -> GraphFLoatInputSingle * 3
//
TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
AnimGraphResource graph_resource_origin; AnimGraphResource graph_resource_origin;
graph_resource_origin.m_name = "TestSimpleMathGraph"; graph_resource_origin.m_name = "TestSimpleMathGraph";
@ -1025,11 +1039,6 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
AnimGraphBlendTree blend_tree; AnimGraphBlendTree blend_tree;
graph_resource_loaded.CreateBlendTreeInstance(blend_tree); graph_resource_loaded.CreateBlendTreeInstance(blend_tree);
REQUIRE(blend_tree.GetInputSocket("GraphFloatInput") != nullptr);
REQUIRE(
blend_tree.GetInputPtr("GraphFloatInput")
== blend_tree.m_input_buffer);
float graph_float_input = 123.456f; float graph_float_input = 123.456f;
blend_tree.SetInput("GraphFloatInput", &graph_float_input); blend_tree.SetInput("GraphFloatInput", &graph_float_input);
@ -1037,12 +1046,13 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
AnimGraphContext context; AnimGraphContext context;
context.m_graph = nullptr; context.m_graph = nullptr;
float float1_output = -1.f;
float float2_output = -1.f;
// float0 output is directly connected to the graph input, therefore // float0 output is directly connected to the graph input, therefore
// we have to get a ptr to the input data here. // we have to get a ptr to the input data here.
float* float0_output_ptr = float* float0_output_ptr =
blend_tree.GetOutputPtr<float>("GraphFloat0Output"); blend_tree.GetOutputPtr<float>("GraphFloat0Output");
float float1_output = -1.f;
float float2_output = -1.f;
blend_tree.SetOutput("GraphFloat1Output", &float1_output); blend_tree.SetOutput("GraphFloat1Output", &float1_output);
blend_tree.SetOutput("GraphFloat2Output", &float2_output); blend_tree.SetOutput("GraphFloat2Output", &float2_output);
@ -1051,7 +1061,7 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
blend_tree.Evaluate(context); blend_tree.Evaluate(context);
THEN("output vector components equal the graph input vaulues") { THEN("output vector components equal the graph input vaulues") {
CHECK(*float0_output_ptr == Approx(graph_float_input)); CHECK(float0_output_ptr == &graph_float_input);
CHECK(float1_output == Approx(graph_float_input * 2.f)); CHECK(float1_output == Approx(graph_float_input * 2.f));
REQUIRE_THAT( REQUIRE_THAT(
float2_output, float2_output,