From 2b7cbe9d4c6d81450eef8384a71b57146db9b129 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sat, 12 Feb 2022 11:46:50 +0100 Subject: [PATCH] Simple graph output connection working. --- src/AnimGraphResource.h | 172 ++++++++------------------------ tests/AnimGraphResourceTests.cc | 21 ++-- 2 files changed, 58 insertions(+), 135 deletions(-) diff --git a/src/AnimGraphResource.h b/src/AnimGraphResource.h index 1a9b914..53fad95 100644 --- a/src/AnimGraphResource.h +++ b/src/AnimGraphResource.h @@ -5,6 +5,7 @@ #ifndef ANIMTESTBED_ANIMGRAPHRESOURCE_H #define ANIMTESTBED_ANIMGRAPHRESOURCE_H +#include #include #include #include @@ -54,24 +55,13 @@ struct AnimNodeResource; struct Socket { std::string m_name; - SocketType m_type; - union Value { - bool* flag; - AnimData* anim_data; - float* real; - Vec3* vec3; - Quat* quat; - std::string* str; + SocketType m_type = SocketType::SocketTypeUndefined; + union SocketValue { void* ptr; - bool** flag_ptr; - AnimData** anim_data_ptr; - float** real_ptr; - float** vec3_ptr; - float** quat_ptr; - std::string** str_ptr; void** ptr_ptr; }; - Value m_value; + SocketValue m_value = {nullptr}; + size_t m_type_size = 0; }; struct AnimNode; @@ -98,7 +88,7 @@ struct AnimNode { }; struct NodeSocketAccessorBase { - NodeSocketAccessorBase(AnimNode* node) {} + NodeSocketAccessorBase() {} virtual ~NodeSocketAccessorBase() {} Socket* FindSocket(std::vector& sockets, const std::string& name) { @@ -164,137 +154,41 @@ struct NodeSocketAccessorBase { sockets.push_back(Socket()); socket = &sockets[sockets.size() - 1]; socket->m_name = name; + socket->m_type_size = sizeof(T); if constexpr (std::is_same::value) { - socket->m_value.real = value_ptr; socket->m_type = SocketType::SocketTypeFloat; } else if constexpr (std::is_same::value) { - socket->m_value.flag = value_ptr; socket->m_type = SocketType::SocketTypeBool; } else if constexpr (std::is_same::value) { - socket->m_value.vec3 = value_ptr; socket->m_type = SocketType::SocketTypeVec3; } else if constexpr (std::is_same::value) { - socket->m_value.quat = value_ptr; socket->m_type = SocketType::SocketTypeQuat; } else if constexpr (std::is_same::value) { - socket->m_value.anim_data = value_ptr; socket->m_type = SocketType::SocketTypeAnimation; } else if constexpr (std::is_same::value) { - socket->m_value.str = value_ptr; socket->m_type = SocketType::SocketTypeString; } else if constexpr (std::is_same::value) { - socket->m_value.real_ptr = value_ptr; socket->m_type = SocketType::SocketTypeFloat; } else if constexpr (std::is_same::value) { - socket->m_value.flag_ptr = value_ptr; socket->m_type = SocketType::SocketTypeBool; } else if constexpr (std::is_same::value) { - socket->m_value.vec3_ptr = value_ptr; socket->m_type = SocketType::SocketTypeVec3; } else if constexpr (std::is_same::value) { - socket->m_value.quat_ptr = value_ptr; socket->m_type = SocketType::SocketTypeQuat; } else if constexpr (std::is_same::value) { - socket->m_value.anim_data_ptr = value_ptr; socket->m_type = SocketType::SocketTypeAnimation; } else if constexpr (std::is_same::value) { - socket->m_value.str_ptr = value_ptr; socket->m_type = SocketType::SocketTypeString; } else { std::cerr << "Cannot register socket, invalid type." << std::endl; return false; } + socket->m_value.ptr = value_ptr; return true; } - template - bool SetSocketValue( - std::vector& sockets, - const std::string& name, - T value) { - Socket* socket = FindSocket(sockets, name); - if (socket == nullptr) { - return false; - } - - if constexpr (std::is_same::value) { - (*socket->m_value.real) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.flag) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.vec3) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.vec3) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.vec3) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.str) = value; - } else { - std::cerr << "Invalid type!" << std::endl; - return false; - } - - return true; - } - - template - bool SetSocketRef( - std::vector& sockets, - const std::string& name, - T* value) { - Socket* socket = FindSocket(sockets, name); - if (socket == nullptr) { - return false; - } else if constexpr (std::is_same::value) { - (*socket->m_value.real_ptr) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.flag_ptr) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.vec3_ptr) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.quat_ptr) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.anim_data_ptr) = value; - } else if constexpr (std::is_same::value) { - (*socket->m_value.str_ptr) = value; - } else { - std::cerr << "Invalid type!" << std::endl; - return false; - } - - return true; - } - - template - T* GetSocketValue( - std::vector& sockets, - const std::string& name, - T* default_value) { - Socket* socket = FindSocket(sockets, name); - if (socket == nullptr) { - return default_value; - } - - if constexpr (std::is_same::value) { - return socket->m_value.real; - } else if constexpr (std::is_same::value) { - return socket->m_value.vec3; - } else if constexpr (std::is_same::value) { - return socket->m_value.flag; - } else if constexpr (std::is_same::value) { - return socket->m_value.vec3; - } else if constexpr (std::is_same::value) { - return socket->m_value.anim_data; - } else if constexpr (std::is_same::value) { - return socket->m_value.str; - } - - std::cerr << "Invalid type!" << std::endl; - return nullptr; - } - template bool RegisterProperty(const std::string& name, T* value) { return RegisterSocket(m_properties, name, value); @@ -316,10 +210,6 @@ struct NodeSocketAccessorBase { return RegisterSocket(m_inputs, name, value); } template - bool SetInput(const std::string& name, T value) { - return SetSocketValue(m_inputs, name, value); - } - template T* GetInput(const std::string& name, T* value) { return GetSocketValue(m_inputs, name, value); } @@ -337,10 +227,6 @@ struct NodeSocketAccessorBase { bool RegisterOutput(const std::string& name, T** value) { return RegisterSocket(m_outputs, name, value); } - template - bool SetOutputRef(const std::string& name, T* value) { - return SetSocketRef(m_outputs, name, value); - } SocketType GetOutputType(const std::string& name) { return GetSocketType(m_outputs, name); } @@ -372,7 +258,7 @@ struct BlendTreeNode : public AnimNode {}; template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { - NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {} + NodeSocketAccessor(AnimNode* node_) {} }; struct Blend2Node : public AnimNode { @@ -385,7 +271,7 @@ struct Blend2Node : public AnimNode { template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { - NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) { + NodeSocketAccessor(AnimNode* node_) { Blend2Node* node = dynamic_cast(node_); RegisterInput("Input0", &node->m_input0); RegisterInput("Input1", &node->m_input1); @@ -405,7 +291,7 @@ struct SpeedScaleNode : public AnimNode { template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { - NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) { + NodeSocketAccessor(AnimNode* node_) { SpeedScaleNode* node = dynamic_cast(node_); RegisterInput("SpeedScale", &node->m_speed_scale); RegisterInput("Input", &node->m_input); @@ -421,7 +307,7 @@ struct AnimSamplerNode : public AnimNode { template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { - NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) { + NodeSocketAccessor(AnimNode* node_) { AnimSamplerNode* node = dynamic_cast(node_); RegisterOutput("Output", &node->m_output); @@ -516,6 +402,9 @@ struct AnimGraph { AnimData m_local_transforms; std::vector m_nodes; std::vector > m_node_inputs; + NodeSocketAccessorBase* m_socket_accessor; + char* m_input_buffer = nullptr; + char* m_output_buffer = nullptr; AnimNode* getAnimNode(const char* name) { for (size_t i = 0; i < m_nodes.size(); i++) { @@ -540,6 +429,8 @@ struct AnimGraph { static AnimGraph createFromResource(const AnimGraphResource& resource) { AnimGraph result; + + // create nodes for (int i = 0; i < resource.m_nodes.size(); i++) { const AnimNodeResource& node_resource = resource.m_nodes[i]; AnimNode* node = AnimNodeFactory(node_resource.m_type_name.c_str()); @@ -549,6 +440,27 @@ struct AnimGraph { result.m_node_inputs.push_back(std::vector()); } + // Prepare graph inputs + const AnimNodeResource& graph_node = resource.m_nodes[0]; + result.m_socket_accessor = AnimNodeAccessorFactory("BlendTree", result.m_nodes[0]); + + int input_block_size = 0; + const std::vector& graph_inputs = + graph_node.m_socket_accessor->m_inputs; + for (int i = 0; i < graph_inputs.size(); i++) { + input_block_size += graph_inputs[i].m_type_size; + } + result.m_input_buffer = new char[input_block_size]; + memset(result.m_input_buffer, 0, input_block_size); + int input_block_offset = 0; + for (int i = 0; i < graph_inputs.size(); i++) { + if (graph_inputs[i].m_type == SocketType::SocketTypeAnimation) { + result.m_socket_accessor->RegisterInput(graph_inputs[i].m_name, static_cast( (void*) &result.m_input_buffer[input_block_offset])); + } + input_block_offset += graph_inputs[i].m_type_size; + } + + // connect the nodes for (int i = 0; i < resource.m_connections.size(); i++) { const AnimGraphConnection& connection = resource.m_connections[i]; std::string source_node_type = ""; @@ -574,8 +486,12 @@ struct AnimGraph { target_node = result.m_nodes[connection.m_target_node_index]; target_node_name = target_node->m_name; target_node_type = target_node->m_node_type_name; - target_node_accessor = - AnimNodeAccessorFactory(target_node_type, target_node); + if (connection.m_target_node_index == 0) { + target_node_accessor = result.m_socket_accessor; + } else { + target_node_accessor = + AnimNodeAccessorFactory(target_node_type, target_node); + } } assert(source_node != nullptr); diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index adc3713..1e5028a 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -27,7 +27,7 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { walk_node.m_name = "BlendWalkRun"; AnimNodeResource& graph_node = graph_resource.m_nodes[0]; - graph_node.m_socket_accessor->RegisterInput("Output", nullptr); + graph_node.m_socket_accessor->RegisterInput("GraphOutput", nullptr); REQUIRE(graph_node.m_socket_accessor->m_inputs.size() == 1); REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input0") == 0); @@ -57,7 +57,7 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { blend_node.m_socket_accessor->GetOutputIndex("Output"); blend_to_output.m_target_node_index = 0; blend_to_output.m_target_socket_index = - graph_node.m_socket_accessor->GetInputIndex("Output"); + graph_node.m_socket_accessor->GetInputIndex("GraphOutput"); graph_resource.m_connections.push_back(blend_to_output); graph_resource.saveToFile("WalkGraph.animgraph.json"); @@ -70,12 +70,13 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { << std::endl; } - CHECK(graph.m_nodes.size() == 4); - CHECK(graph.m_nodes[0]->m_node_type_name == "Graph"); - CHECK(graph.m_nodes[1]->m_node_type_name == "AnimSampler"); - CHECK(graph.m_nodes[2]->m_node_type_name == "AnimSampler"); - CHECK(graph.m_nodes[3]->m_node_type_name == "Blend2"); + REQUIRE(graph.m_nodes.size() == 4); + REQUIRE(graph.m_nodes[0]->m_node_type_name == "BlendTree"); + REQUIRE(graph.m_nodes[1]->m_node_type_name == "AnimSampler"); + REQUIRE(graph.m_nodes[2]->m_node_type_name == "AnimSampler"); + REQUIRE(graph.m_nodes[3]->m_node_type_name == "Blend2"); + // connections within the graph AnimSamplerNode* anim_sampler_instance0 = dynamic_cast(graph.m_nodes[1]); AnimSamplerNode* anim_sampler_instance1 = @@ -84,6 +85,12 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { CHECK(anim_sampler_instance0->m_output == &blend2_instance->m_input0); CHECK(anim_sampler_instance1->m_output == &blend2_instance->m_input1); + // connections from graph to the graph node + CHECK(graph.m_socket_accessor->m_inputs.size() == 1); + CHECK(graph.m_socket_accessor->FindInputSocket("GraphOutput")); + CHECK(reinterpret_cast(blend2_instance->m_output) == graph.m_input_buffer); + + // check node input dependencies size_t anim_sampler_index0 = graph.getAnimNodeIndex(anim_sampler_instance0); size_t anim_sampler_index1 = graph.getAnimNodeIndex(anim_sampler_instance1); size_t blend_index = graph.getAnimNodeIndex(blend2_instance);