From da916a734670bb6452622849ff4eb2a0707ccef1 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sat, 19 Feb 2022 12:16:57 +0100 Subject: [PATCH] Added node ordering code and tests. --- src/AnimGraphEditor.cc | 4 +- src/AnimGraphResource.cc | 35 ++++++++ src/AnimGraphResource.h | 31 ++++++- tests/AnimGraphResourceTests.cc | 144 +++++++++++++++++++++++++++----- 4 files changed, 189 insertions(+), 25 deletions(-) diff --git a/src/AnimGraphEditor.cc b/src/AnimGraphEditor.cc index 1a8bcc9..9679161 100644 --- a/src/AnimGraphEditor.cc +++ b/src/AnimGraphEditor.cc @@ -185,7 +185,7 @@ void AnimGraphEditorUpdate() { GenerateInputAttributeId(i, j), sGetSocketShapeFromSocketType(socket.m_type), socket_color); - ImGui::Text(socket.m_name.c_str()); + ImGui::TextUnformatted(socket.m_name.c_str()); ImNodes::PushAttributeFlag( ImNodesAttributeFlags_EnableLinkDetachWithDragClick); @@ -201,7 +201,7 @@ void AnimGraphEditorUpdate() { GenerateOutputAttributeId(i, j), sGetSocketShapeFromSocketType(socket.m_type), ImColor(255, 255, 255, 255)); - ImGui::Text(socket.m_name.c_str()); + ImGui::TextUnformatted(socket.m_name.c_str()); ImNodes::PushAttributeFlag( ImNodesAttributeFlags_EnableLinkDetachWithDragClick); ImNodes::EndInputAttribute(); diff --git a/src/AnimGraphResource.cc b/src/AnimGraphResource.cc index 7864282..c591fdf 100644 --- a/src/AnimGraphResource.cc +++ b/src/AnimGraphResource.cc @@ -351,6 +351,41 @@ bool AnimGraphResource::loadFromFile(const char* filename) { return true; } +void AnimGraph::UpdateOrderedNodes() { + std::vector node_index_stack; + node_index_stack.push_back(0); + + m_ordered_nodes.clear(); + + while (node_index_stack.size() > 0) { + std::vector& node_inputs = m_node_inputs[node_index_stack.back()]; + node_index_stack.pop_back(); + + for (size_t i = 0, n = node_inputs.size(); i < n; i++) { + AnimNode* input_node = node_inputs[i].m_node; + if (input_node == nullptr) { + continue; + } + + int input_node_index = getAnimNodeIndex(input_node); + bool is_node_processed = false; + for (size_t j = 0, m = m_ordered_nodes.size(); j < m; j++) { + if (m_ordered_nodes[j] == input_node) { + is_node_processed = true; + break; + } + } + + if (is_node_processed) { + continue; + } + + m_ordered_nodes.push_back(input_node); + node_index_stack.push_back(input_node_index); + } + } +} + void AnimGraph::MarkActiveNodes() { m_frame_counter++; diff --git a/src/AnimGraphResource.h b/src/AnimGraphResource.h index 4a40399..7af8f63 100644 --- a/src/AnimGraphResource.h +++ b/src/AnimGraphResource.h @@ -81,9 +81,23 @@ struct AnimNodeResource { float m_position[2] = {0.f, 0.f}; }; + +struct AnimNodeInput { + AnimNode* m_node; + std::string m_input_name; +}; + struct AnimNode { virtual ~AnimNode(){}; + virtual void UpdateActiveInputFrameCounters (const std::vector& inputs) { + for (size_t i = 0, n = inputs.size(); i < n; i++) { + if (inputs[i].m_node != nullptr) { + inputs[i].m_node->m_frame_counter = m_frame_counter; + } + } + } + std::string m_name; std::string m_node_type_name; bool m_is_time_synced; @@ -93,10 +107,6 @@ struct AnimNode { SyncTrack m_sync_track; }; -struct AnimNodeInput { - AnimNode* m_node; - std::string m_input_name; -}; struct NodeSocketAccessorBase { NodeSocketAccessorBase() {} @@ -521,6 +531,7 @@ struct AnimGraph { delete m_socket_accessor; } + void UpdateOrderedNodes(); void MarkActiveNodes(); bool CheckNodeActive(int node_index) { assert(node_index < m_nodes.size()); @@ -533,6 +544,7 @@ struct AnimGraph { AnimData m_local_transforms; std::vector m_nodes; + std::vector m_ordered_nodes; std::vector > m_node_inputs; NodeSocketAccessorBase* m_socket_accessor; char* m_input_buffer = nullptr; @@ -544,6 +556,15 @@ struct AnimGraph { void* GetOutput(const std::string& name) const; void* GetInput(const std::string& name) const; + int getAnimNodeOrderIndex(const AnimNode* node) { + for (size_t i = 0, n = m_ordered_nodes.size(); i < n; i++) { + if (m_ordered_nodes[i] == node) { + return i; + } + } + + return -1; + } AnimNode* getAnimNodeForInput( size_t node_index, const std::string& input_name) { @@ -749,6 +770,8 @@ struct AnimGraph { } } + result.UpdateOrderedNodes(); + return result; } }; diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 919667f..30db462 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -269,7 +269,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); - THEN ("Writing to the input pointer changes the value of the output.") { + THEN("Writing to the input pointer changes the value of the output.") { float* float_input_ptr = (float*)anim_graph.GetInput("GraphFloatInput"); REQUIRE(float_input_ptr != nullptr); *float_input_ptr = 23.123f; @@ -282,8 +282,10 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { } WHEN("Connecting adding a Blend2 node") { - size_t blend2_node_index = graph_resource.addNode(AnimNodeResourceFactory("Blend2")); - AnimNodeResource& blend2_node_resource = graph_resource.m_nodes[blend2_node_index]; + size_t blend2_node_index = + graph_resource.addNode(AnimNodeResourceFactory("Blend2")); + AnimNodeResource& blend2_node_resource = + graph_resource.m_nodes[blend2_node_index]; REQUIRE(graph_resource.connectSockets( graph_resource.getGraphInputNode(), @@ -291,17 +293,21 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { blend2_node_resource, "Weight")); - THEN ("Connected float input points to the blend weight.") { + THEN("Connected float input points to the blend weight.") { AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); - Blend2Node* blend2_node = dynamic_cast(anim_graph.m_nodes[blend2_node_index]); + Blend2Node* blend2_node = + dynamic_cast(anim_graph.m_nodes[blend2_node_index]); - REQUIRE (*anim_graph.m_socket_accessor->m_outputs[0].m_value.ptr_ptr == &blend2_node->m_blend_weight); + REQUIRE( + *anim_graph.m_socket_accessor->m_outputs[0].m_value.ptr_ptr + == &blend2_node->m_blend_weight); float* float_input_ptr = (float*)anim_graph.GetInput("GraphFloatInput"); - REQUIRE (float_input_ptr == &blend2_node->m_blend_weight); + REQUIRE(float_input_ptr == &blend2_node->m_blend_weight); } - - WHEN ("Connecting AnimData inputs to blend2 node and blend2 output to graph output.") { + WHEN( + "Connecting AnimData inputs to blend2 node and blend2 output to graph " + "output.") { REQUIRE(graph_resource.connectSockets( graph_resource.getGraphInputNode(), "GraphAnimInput0", @@ -318,25 +324,125 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { blend2_node_resource, "Output", graph_resource.getGraphOutputNode(), - "GraphAnimOutput" - )); + "GraphAnimOutput")); - THEN("AnimData from output gets blended and result is written to Output.") { + THEN( + "AnimData from output gets blended and result is written to " + "Output.") { AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); - Blend2Node* blend2_node = dynamic_cast(anim_graph.m_nodes[blend2_node_index]); + Blend2Node* blend2_node = + dynamic_cast(anim_graph.m_nodes[blend2_node_index]); - AnimData* graph_input0 = (AnimData*) anim_graph.GetInput("GraphAnimInput0"); + AnimData* graph_input0 = + (AnimData*)anim_graph.GetInput("GraphAnimInput0"); REQUIRE(graph_input0 == &blend2_node->m_input0); - REQUIRE(anim_graph.m_nodes[1] == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0")); + REQUIRE( + anim_graph.m_nodes[1] + == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0")); - AnimData* graph_input1 = (AnimData*) anim_graph.GetInput("GraphAnimInput1"); + AnimData* graph_input1 = + (AnimData*)anim_graph.GetInput("GraphAnimInput1"); REQUIRE(graph_input1 == &blend2_node->m_input1); - REQUIRE(anim_graph.m_nodes[1] == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1")); + REQUIRE( + anim_graph.m_nodes[1] + == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1")); - AnimData* graph_output = (AnimData*) anim_graph.GetOutput("GraphAnimOutput"); + AnimData* graph_output = + (AnimData*)anim_graph.GetOutput("GraphAnimOutput"); REQUIRE(graph_output == blend2_node->m_output); - REQUIRE(anim_graph.m_nodes[blend2_node_index] == anim_graph.getAnimNodeForInput(0, "GraphAnimOutput")); + REQUIRE( + anim_graph.m_nodes[blend2_node_index] + == anim_graph.getAnimNodeForInput(0, "GraphAnimOutput")); } } } + + WHEN("Adding AnimSampler Nodes") { + size_t blend2_node_index = + graph_resource.addNode(AnimNodeResourceFactory("Blend2")); + size_t sampler_node_index = + graph_resource.addNode(AnimNodeResourceFactory("AnimSampler")); + size_t speed_scale_node_index = + graph_resource.addNode(AnimNodeResourceFactory("SpeedScale")); + + AnimNodeResource& blend2_node_resource = + graph_resource.m_nodes[blend2_node_index]; + AnimNodeResource& sampler_node_resource = + graph_resource.m_nodes[sampler_node_index]; + AnimNodeResource& speed_scale_node_resource = + graph_resource.m_nodes[speed_scale_node_index]; + + REQUIRE(graph_resource.connectSockets( + graph_resource.getGraphInputNode(), + "GraphFloatInput", + blend2_node_resource, + "Weight")); + + REQUIRE(graph_resource.connectSockets( + graph_resource.getGraphInputNode(), + "GraphAnimInput0", + blend2_node_resource, + "Input0")); + + REQUIRE(graph_resource.connectSockets( + sampler_node_resource, + "Output", + speed_scale_node_resource, + "Input")); + + REQUIRE(graph_resource.connectSockets( + speed_scale_node_resource, + "Output", + blend2_node_resource, + "Input1")); + + REQUIRE(graph_resource.connectSockets( + blend2_node_resource, + "Output", + graph_resource.getGraphOutputNode(), + "GraphAnimOutput")); + + THEN("Data flow and node ordering must be correct.") { + AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); + Blend2Node* blend2_node = + dynamic_cast(anim_graph.m_nodes[blend2_node_index]); + SpeedScaleNode* speed_scale_node = dynamic_cast( + anim_graph.m_nodes[speed_scale_node_index]); + AnimSamplerNode* sampler_node = dynamic_cast( + anim_graph.m_nodes[sampler_node_index]); + + AnimData* graph_input0 = + (AnimData*)anim_graph.GetInput("GraphAnimInput0"); + REQUIRE(graph_input0 == &blend2_node->m_input0); + REQUIRE( + anim_graph.m_nodes[1] + == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0")); + + AnimData* graph_input1 = + (AnimData*)anim_graph.GetInput("GraphAnimInput1"); + REQUIRE(graph_input1 == nullptr); + + REQUIRE(sampler_node->m_output == &speed_scale_node->m_input); + REQUIRE( + sampler_node + == anim_graph.getAnimNodeForInput(speed_scale_node_index, "Input")); + + REQUIRE(speed_scale_node->m_output == &blend2_node->m_input1); + REQUIRE( + speed_scale_node + == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1")); + + AnimData* graph_output = + (AnimData*)anim_graph.GetOutput("GraphAnimOutput"); + REQUIRE(graph_output == blend2_node->m_output); + REQUIRE( + anim_graph.m_nodes[blend2_node_index] + == anim_graph.getAnimNodeForInput(0, "GraphAnimOutput")); + + // Check ordering + REQUIRE (anim_graph.getAnimNodeOrderIndex(blend2_node) < anim_graph.getAnimNodeOrderIndex(sampler_node)); + REQUIRE (anim_graph.getAnimNodeOrderIndex(blend2_node) < anim_graph.getAnimNodeOrderIndex(speed_scale_node)); + REQUIRE (anim_graph.getAnimNodeOrderIndex(speed_scale_node) < anim_graph.getAnimNodeOrderIndex(sampler_node)); + } + } } \ No newline at end of file