From 72a67195e65f2f30d27e6b7efd012153b567ade1 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Fri, 25 Mar 2022 11:23:03 +0100 Subject: [PATCH] Use socket pointers instead of indices for connections. --- src/AnimGraphResource.cc | 64 ++++++++++------- src/AnimGraphResource.h | 124 ++++++++++++++++++-------------- tests/AnimGraphResourceTests.cc | 36 +++++----- 3 files changed, 125 insertions(+), 99 deletions(-) diff --git a/src/AnimGraphResource.cc b/src/AnimGraphResource.cc index 84ce576..07a6421 100644 --- a/src/AnimGraphResource.cc +++ b/src/AnimGraphResource.cc @@ -173,28 +173,36 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) { // // AnimGraphConnection <-> Json // -json sAnimGraphConnectionToJson(const AnimGraphConnection& connection) { +json sAnimGraphConnectionToJson(const AnimGraphResource& graph_resource, const AnimGraphConnection& connection) { json result; result["type"] = "AnimGraphConnection"; - result["source_node_index"] = connection.m_source_node_index; - result["source_socket_index"] = connection.m_source_socket_index; + const AnimNodeResource* source_node = connection.m_source_node; + result["source_node_index"] = graph_resource.getNodeIndex(*source_node); + result["source_socket_index"] = source_node->m_socket_accessor->GetOutputIndex(connection.m_source_socket->m_name); - result["target_node_index"] = connection.m_target_node_index; - result["target_socket_index"] = connection.m_target_socket_index; + const AnimNodeResource* target_node = connection.m_source_node; + result["source_node_index"] = graph_resource.getNodeIndex(*target_node); + result["source_socket_index"] = target_node->m_socket_accessor->GetInputIndex(connection.m_target_node->m_name); return result; } -AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) { +AnimGraphConnection sAnimGraphConnectionFromJson(const AnimGraphResource& graph_resource, const json& json_node) { AnimGraphConnection connection; - connection.m_source_node_index = json_node["source_node_index"]; - connection.m_source_socket_index = json_node["source_socket_index"]; + int source_node_index = json_node["source_node_index"]; + connection.m_source_node = &graph_resource.m_nodes[source_node_index]; + int source_socket_index = json_node["source_socket_index"]; + connection.m_source_socket = &connection.m_source_node->m_socket_accessor->m_outputs[source_socket_index]; - connection.m_target_node_index = json_node["target_node_index"]; - connection.m_target_socket_index = json_node["target_socket_index"]; + + int target_node_index = json_node["target_node_index"]; + connection.m_target_node = &graph_resource.m_nodes[target_node_index]; + + int target_socket_index = json_node["target_socket_index"]; + connection.m_target_socket = &connection.m_target_node->m_socket_accessor->m_outputs[target_socket_index]; return connection; } @@ -238,7 +246,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const { for (size_t i = 0; i < m_connections.size(); i++) { const AnimGraphConnection& connection = m_connections[i]; - result["connections"][i] = sAnimGraphConnectionToJson(connection); + result["connections"][i] = sAnimGraphConnectionToJson(*this, connection); } // Graph inputs and outputs @@ -288,6 +296,8 @@ bool AnimGraphResource::loadFromFile(const char* filename) { clearNodes(); m_name = json_data["name"]; + + // Load nodes for (size_t i = 0; i < json_data["nodes"].size(); i++) { const json& json_node = json_data["nodes"][i]; if (json_node["type"] != "AnimNodeResource") { @@ -300,7 +310,23 @@ bool AnimGraphResource::loadFromFile(const char* filename) { AnimNodeResource node = sAnimGraphNodeFromJson(json_node); m_nodes.push_back(node); } + + // Setup graph inputs and outputs + const json& graph_outputs = json_data["nodes"][0]["inputs"]; + for (size_t i = 0; i < graph_outputs.size(); i++) { + AnimNodeResource& graph_node = m_nodes[0]; + graph_node.m_socket_accessor->m_inputs.push_back( + sJsonToSocket(graph_outputs[i])); + } + + const json& graph_inputs = json_data["nodes"][1]["outputs"]; + for (size_t i = 0; i < graph_inputs.size(); i++) { + AnimNodeResource& graph_node = m_nodes[1]; + graph_node.m_socket_accessor->m_outputs.push_back( + sJsonToSocket(graph_inputs[i])); + } + // Load connections for (size_t i = 0; i < json_data["connections"].size(); i++) { const json& json_connection = json_data["connections"][i]; if (json_connection["type"] != "AnimGraphConnection") { @@ -311,24 +337,10 @@ bool AnimGraphResource::loadFromFile(const char* filename) { } AnimGraphConnection connection = - sAnimGraphConnectionFromJson(json_connection); + sAnimGraphConnectionFromJson(*this, json_connection); m_connections.push_back(connection); } - const json& graph_outputs = json_data["nodes"][0]["inputs"]; - for (size_t i = 0; i < graph_outputs.size(); i++) { - AnimNodeResource& graph_node = m_nodes[0]; - graph_node.m_socket_accessor->m_inputs.push_back( - sJsonToSocket(graph_outputs[i])); - } - - const json& graph_inputs = json_data["nodes"][1]["outputs"]; - for (size_t i = 0; i < graph_inputs.size(); i++) { - AnimNodeResource& graph_node = m_nodes[1]; - graph_node.m_socket_accessor->m_outputs.push_back( - sJsonToSocket(graph_inputs[i])); - } - return true; } diff --git a/src/AnimGraphResource.h b/src/AnimGraphResource.h index b93ddbc..5bd4620 100644 --- a/src/AnimGraphResource.h +++ b/src/AnimGraphResource.h @@ -47,7 +47,6 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) { *output_index = (attribute_id >> 23) - 1; } - enum class SocketType { SocketTypeUndefined = 0, SocketTypeBool, @@ -59,9 +58,8 @@ enum class SocketType { SocketTypeLast }; -static const char* SocketTypeNames[] = { - "", "Bool", "Animation", "Float", "Vec3", "Quat", "String" -}; +static const char* SocketTypeNames[] = + {"", "Bool", "Animation", "Float", "Vec3", "Quat", "String"}; enum SocketFlags { SocketFlagAffectsTime = 1 }; @@ -88,7 +86,6 @@ struct AnimNodeResource { float m_position[2] = {0.f, 0.f}; }; - struct NodeInput { AnimNode* m_node; SocketType m_type = SocketType::SocketTypeUndefined; @@ -142,10 +139,9 @@ struct AnimNode { m_state = AnimNodeEvalState::TimeUpdated; } - virtual void Evaluate() {}; + virtual void Evaluate(){}; }; - struct NodeSocketAccessorBase { std::vector m_properties; std::vector m_inputs; @@ -484,10 +480,10 @@ struct NodeSocketAccessor : public NodeSocketAccessorBase { // AnimGraphResource // struct AnimGraphConnection { - int m_source_node_index; - int m_source_socket_index; - int m_target_node_index; - int m_target_socket_index; + const AnimNodeResource* m_source_node = nullptr; + const Socket* m_source_socket = nullptr; + const AnimNodeResource* m_target_node = nullptr; + const Socket* m_target_socket = nullptr; }; struct AnimGraphResource { @@ -516,7 +512,7 @@ struct AnimGraphResource { const AnimNodeResource& getGraphOutputNode() const { return m_nodes[0]; } const AnimNodeResource& getGraphInputNode() const { return m_nodes[1]; } - size_t getNodeIndex (const AnimNodeResource& node_resource) const { + size_t getNodeIndex(const AnimNodeResource& node_resource) const { for (size_t i = 0, n = m_nodes.size(); i < n; i++) { if (&m_nodes[i] == &node_resource) { return i; @@ -533,9 +529,9 @@ struct AnimGraphResource { bool connectSockets( const AnimNodeResource& source_node, - const std::string& source_socket, + const std::string& source_socket_name, const AnimNodeResource& target_node, - const std::string& target_socket) { + const std::string& target_socket_name) { size_t source_index = -1; size_t target_index = -1; for (size_t i = 0, n = m_nodes.size(); i < n; i++) { @@ -557,23 +553,21 @@ struct AnimGraphResource { return false; } - size_t source_socket_index = - source_node.m_socket_accessor->GetOutputIndex(source_socket); - size_t target_socket_index = - target_node.m_socket_accessor->GetInputIndex(target_socket); + Socket* source_socket = + source_node.m_socket_accessor->FindOutputSocket(source_socket_name); + Socket* target_socket = + target_node.m_socket_accessor->FindInputSocket(target_socket_name); - if (source_socket_index >= source_node.m_socket_accessor->m_outputs.size() - || target_socket_index - >= target_node.m_socket_accessor->m_inputs.size()) { + if (source_socket == nullptr || target_socket == nullptr) { std::cerr << "Cannot connect nodes: could not find sockets." << std::endl; return false; } AnimGraphConnection connection; - connection.m_source_node_index = source_index; - connection.m_source_socket_index = source_socket_index; - connection.m_target_node_index = target_index; - connection.m_target_socket_index = target_socket_index; + connection.m_source_node = &source_node; + connection.m_source_socket = source_socket; + connection.m_target_node = &target_node; + connection.m_target_socket = target_socket; m_connections.push_back(connection); return true; @@ -672,7 +666,6 @@ struct AnimGraph { } } - void* getOutput(const std::string& name) const; void* getInput(const std::string& name) const; @@ -799,12 +792,19 @@ struct AnimGraph { NodeSocketAccessorBase* target_node_accessor = nullptr; SocketType source_type; SocketType target_type; + size_t source_socket_index = -1; + size_t target_socket_index = -1; - if (connection.m_source_node_index >= 0) { - source_node = result.m_nodes[connection.m_source_node_index]; + if (connection.m_source_node != nullptr) { + size_t node_index = resource.getNodeIndex(*connection.m_source_node); + if (node_index == -1) { + std::cerr << "Could not find source node index." << std::endl; + continue; + } + source_node = result.m_nodes[node_index]; source_node_name = source_node->m_name; source_node_type = source_node->m_node_type_name; - if (connection.m_source_node_index == 1) { + if (node_index == 1) { source_node_accessor = result.m_socket_accessor; } else { source_node_accessor = @@ -812,11 +812,16 @@ struct AnimGraph { } } - if (connection.m_target_node_index >= 0) { - target_node = result.m_nodes[connection.m_target_node_index]; + if (connection.m_target_node != nullptr) { + size_t node_index = resource.getNodeIndex(*connection.m_target_node); + if (node_index == -1) { + std::cerr << "Could not find source node index." << std::endl; + continue; + } + target_node = result.m_nodes[node_index]; target_node_name = target_node->m_name; target_node_type = target_node->m_node_type_name; - if (connection.m_target_node_index == 0) { + if (node_index == 0) { target_node_accessor = result.m_socket_accessor; } else { target_node_accessor = @@ -827,41 +832,50 @@ struct AnimGraph { assert(source_node != nullptr); assert(target_node != nullptr); - if (connection.m_source_socket_index - > source_node_accessor->m_outputs.size()) { - std::cerr << "Invalid source socket index " - << connection.m_source_socket_index << ". Only " - << source_node_accessor->m_outputs.size() - << " output sockets found." << std::endl; + // + // Map resource node sockets to graph instance node sockets + // + if (connection.m_source_socket == nullptr) { + std::cerr << "Invalid source socket for connection " << i << "." + << std::endl; continue; } - if (connection.m_target_socket_index - > target_node_accessor->m_inputs.size()) { - std::cerr << "Invalid source socket index " - << connection.m_target_socket_index << ". Only " - << source_node_accessor->m_inputs.size() - << " input sockets found." << std::endl; + if (connection.m_target_socket == nullptr) { + std::cerr << "Invalid source socket for connection " << i << "." + << std::endl; continue; } - if (source_node_accessor->m_outputs[connection.m_source_socket_index] - .m_type - != target_node_accessor->m_inputs[connection.m_target_socket_index] - .m_type) { - std::cerr << "Invalid connection connecting nodes '" << source_node_name - << "' and '" << target_node_name << "'." << std::endl; - return result; + source_socket_index = source_node_accessor->GetOutputIndex( + connection.m_source_socket->m_name); + if (source_socket_index == -1) { + std::cerr << "Invalid source socket " + << connection.m_source_socket->m_name << " for node " + << connection.m_source_node->m_name << "." << std::endl; + continue; } + const Socket* source_socket = + &source_node_accessor->m_outputs[source_socket_index]; + + target_socket_index = target_node_accessor->GetInputIndex( + connection.m_target_socket->m_name); + if (target_socket_index == -1) { + std::cerr << "Invalid target socket " + << connection.m_target_socket->m_name << " for node " + << connection.m_target_node->m_name << "." << std::endl; + continue; + } + const Socket* target_socket = + &target_node_accessor->m_inputs[target_socket_index]; - Socket* source_socket = - &source_node_accessor->m_outputs[connection.m_source_socket_index]; - Socket* target_socket = - &target_node_accessor->m_inputs[connection.m_target_socket_index]; if (source_socket->m_type != target_socket->m_type) { std::cerr << "Cannot connect sockets: invalid types!" << std::endl; } + // + // Wire up outputs to inputs. + // (*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr; size_t target_node_index = target_node->m_index; diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 9ea8003..918580e 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -36,30 +36,30 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input1") == 1); AnimGraphConnection walk_to_blend; - walk_to_blend.m_source_node_index = walk_node_index; - walk_to_blend.m_source_socket_index = - walk_node.m_socket_accessor->GetOutputIndex("Output"); - walk_to_blend.m_target_node_index = blend_node_index; - walk_to_blend.m_target_socket_index = - blend_node.m_socket_accessor->GetInputIndex("Input0"); + walk_to_blend.m_source_node = &walk_node; + walk_to_blend.m_source_socket = + walk_node.m_socket_accessor->FindOutputSocket("Output"); + walk_to_blend.m_target_node = &blend_node; + walk_to_blend.m_target_socket = + blend_node.m_socket_accessor->FindInputSocket("Input0"); graph_resource.m_connections.push_back(walk_to_blend); AnimGraphConnection run_to_blend; - run_to_blend.m_source_node_index = run_node_index; - run_to_blend.m_source_socket_index = - run_node.m_socket_accessor->GetOutputIndex("Output"); - run_to_blend.m_target_node_index = blend_node_index; - run_to_blend.m_target_socket_index = - blend_node.m_socket_accessor->GetInputIndex("Input1"); + run_to_blend.m_source_node = &run_node; + run_to_blend.m_source_socket = + run_node.m_socket_accessor->FindOutputSocket("Output"); + run_to_blend.m_target_node = &blend_node; + run_to_blend.m_target_socket = + blend_node.m_socket_accessor->FindInputSocket("Input1"); graph_resource.m_connections.push_back(run_to_blend); AnimGraphConnection blend_to_output; - blend_to_output.m_source_node_index = blend_node_index; - blend_to_output.m_source_socket_index = - 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("GraphOutput"); + blend_to_output.m_source_node = &blend_node; + blend_to_output.m_source_socket = + blend_node.m_socket_accessor->FindOutputSocket("Output"); + blend_to_output.m_target_node = &graph_resource.m_nodes[0]; + blend_to_output.m_target_socket = + graph_node.m_socket_accessor->FindInputSocket("GraphOutput"); graph_resource.m_connections.push_back(blend_to_output); graph_resource.saveToFile("WalkGraph.animgraph.json");