From e38c0b4934b3448301f095db608512f404becd76 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sun, 26 Mar 2023 23:39:11 +0200 Subject: [PATCH] Started working on graph initialization in ATP Editor. --- src/AnimGraph/AnimGraph.cc | 2 + src/AnimGraph/AnimGraph.h | 41 ++++++++------ src/AnimGraph/AnimGraphData.h | 34 +++++++----- src/AnimGraph/AnimGraphEditor.cc | 85 +++++++++++++++-------------- src/AnimGraph/AnimGraphEditor.h | 4 ++ src/AnimGraph/AnimGraphResource.cc | 42 ++++++-------- src/AnimGraph/AnimGraphResource.h | 2 +- src/main.cc | 46 ++++++++++++---- tests/AnimGraphEvalTests.cc | 4 +- tests/AnimGraphResourceTests.cc | 88 +++++++++++++++--------------- 10 files changed, 193 insertions(+), 155 deletions(-) diff --git a/src/AnimGraph/AnimGraph.cc b/src/AnimGraph/AnimGraph.cc index 46f47b3..c598d29 100644 --- a/src/AnimGraph/AnimGraph.cc +++ b/src/AnimGraph/AnimGraph.cc @@ -7,6 +7,8 @@ #include bool AnimGraph::init(AnimGraphContext& context) { + context.m_graph = this; + for (size_t i = 2; i < m_nodes.size(); i++) { if (!m_nodes[i]->Init(context)) { return false; diff --git a/src/AnimGraph/AnimGraph.h b/src/AnimGraph/AnimGraph.h index fb0a038..798ebbc 100644 --- a/src/AnimGraph/AnimGraph.h +++ b/src/AnimGraph/AnimGraph.h @@ -27,19 +27,26 @@ struct AnimGraph { AnimDataAllocator m_anim_data_allocator; - ~AnimGraph() { - std::vector& graph_outputs = m_node_input_connections[0]; + ~AnimGraph() { dealloc(); } - for (size_t i = 0, n = graph_outputs.size(); i < n; i++) { - AnimGraphConnection& connection = graph_outputs[i]; - if (connection.m_target_socket.m_type == SocketType::SocketTypeAnimation) { - AnimData* graph_anim_output = - static_cast(connection.m_target_socket.m_reference.ptr); - assert(graph_anim_output != nullptr); + bool init(AnimGraphContext& context); + void dealloc() { + if (m_node_input_connections.size() > 0) { + std::vector& graph_outputs = + m_node_input_connections[0]; - // we have to explicitly call the destructor as the AnimData* was - // initialized using a placement new operator. - graph_anim_output->m_local_matrices.vector::~vector(); + for (size_t i = 0, n = graph_outputs.size(); i < n; i++) { + AnimGraphConnection& connection = graph_outputs[i]; + if (connection.m_target_socket.m_type + == SocketType::SocketTypeAnimation) { + AnimData* graph_anim_output = static_cast( + connection.m_target_socket.m_reference.ptr); + assert(graph_anim_output != nullptr); + + // we have to explicitly call the destructor as the AnimData* was + // initialized using a placement new operator. + graph_anim_output->m_local_matrices.vector::~vector(); + } } } @@ -53,8 +60,6 @@ struct AnimGraph { delete m_socket_accessor; } - bool init(AnimGraphContext& context); - void updateOrderedNodes(); void updateOrderedNodesRecursive(int node_index); void markActiveNodes(); @@ -70,7 +75,7 @@ struct AnimGraph { void evalSyncTracks(); void updateTime(float dt); void evaluate(AnimGraphContext& context); - void reset() { + void resetNodeStates() { for (size_t i = 0, n = m_nodes.size(); i < n; i++) { m_nodes[i]->m_time_now = 0.f; m_nodes[i]->m_time_last = 0.f; @@ -102,7 +107,6 @@ struct AnimGraph { return nullptr; } - int getNodeEvalOrderIndex(const AnimNode* node) { for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) { if (m_eval_ordered_nodes[i] == node) { @@ -112,12 +116,13 @@ struct AnimGraph { return -1; } - const AnimNode* getAnimNodeForInput ( + const AnimNode* getAnimNodeForInput( size_t node_index, const std::string& input_name) const { assert(node_index < m_nodes.size()); - const std::vector& input_connection = m_node_input_connections[node_index]; + const std::vector& input_connection = + m_node_input_connections[node_index]; for (size_t i = 0, n = input_connection.size(); i < n; i++) { if (input_connection[i].m_target_socket.m_name == input_name) { return input_connection[i].m_source_node; @@ -137,7 +142,7 @@ struct AnimGraph { return nullptr; } - size_t getAnimNodeIndex (AnimNode* node) { + size_t getAnimNodeIndex(AnimNode* node) { for (size_t i = 0; i < m_nodes.size(); i++) { if (m_nodes[i] == node) { return i; diff --git a/src/AnimGraph/AnimGraphData.h b/src/AnimGraph/AnimGraphData.h index 9799b0a..39e90b0 100644 --- a/src/AnimGraph/AnimGraphData.h +++ b/src/AnimGraph/AnimGraphData.h @@ -9,10 +9,10 @@ #include #include +#include #include #include #include -#include #include "SyncTrack.h" #include "ozz/animation/runtime/animation.h" @@ -76,16 +76,15 @@ struct AnimDataAllocator { void free(AnimData* anim_data) { #ifdef ANIM_DATA_ALLOCATOR_DEBUG - std::cout << "Storing buffer with size " << anim_data->m_local_matrices.size() - << " " << anim_data << std::endl; + std::cout << "Storing buffer with size " + << anim_data->m_local_matrices.size() << " " << anim_data + << std::endl; #endif m_anim_data_list.push_front(anim_data); } - size_t size() { - return m_anim_data_list.size(); - } + size_t size() { return m_anim_data_list.size(); } }; struct AnimGraphContext { @@ -134,7 +133,7 @@ struct Socket { float float_value; float vec3[3]; float quat[4]; - char str[cSocketStringValueMaxLength]; + std::string* string_ptr; }; SocketValue m_value = {0}; union SocketReference { @@ -265,6 +264,9 @@ struct NodeSocketAccessorBase { socket->m_type = SocketType::SocketTypeAnimation; } else if constexpr (std::is_same::value) { socket->m_type = SocketType::SocketTypeString; + socket->m_value.string_ptr = value_ptr; + socket->m_reference.ptr = value_ptr; + return true; } else if constexpr (std::is_same::value) { socket->m_type = SocketType::SocketTypeFloat; } else if constexpr (std::is_same::value) { @@ -381,6 +383,13 @@ inline void NodeSocketAccessorBase::SetSocketReferenceValue( static_cast(socket->m_reference.ptr)[3] = value[3]; } +template <> +inline void NodeSocketAccessorBase::SetSocketReferenceValue( + Socket* socket, + const std::string* value) { + socket->m_value.string_ptr = const_cast(value); +} + template <> inline void NodeSocketAccessorBase::SetSocketReferenceValue( Socket* socket, @@ -433,20 +442,17 @@ inline void NodeSocketAccessorBase::SetSocketValue( } template <> -inline void NodeSocketAccessorBase::SetSocketValue( +inline void NodeSocketAccessorBase::SetSocketValue( Socket* socket, - const std::string& value) { - constexpr size_t string_max_length = sizeof(socket->m_value.str) - 1; - strncpy(socket->m_value.str, value.data(), string_max_length); - socket->m_value.str - [value.size() > string_max_length ? string_max_length : value.size()] = 0; + std::string value) { + *socket->m_value.string_ptr = value; } template <> inline void NodeSocketAccessorBase::SetSocketValue( Socket* socket, const char* value) { - SetSocketValue(socket, value); + SetSocketValue(socket, value); } template diff --git a/src/AnimGraph/AnimGraphEditor.cc b/src/AnimGraph/AnimGraphEditor.cc index 31bf307..d039a49 100644 --- a/src/AnimGraph/AnimGraphEditor.cc +++ b/src/AnimGraph/AnimGraphEditor.cc @@ -9,6 +9,8 @@ #include "imnodes.h" #include "misc/cpp/imgui_stdlib.h" +static AnimGraphResource sGraphGresource = AnimGraphResource(); + ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) { switch (socket_type) { case SocketType::SocketTypeAnimation: @@ -54,7 +56,7 @@ void RemoveConnectionsForSocket( // AnimGraphConnectionResource& connection = *iter; // if (connection.m_source_node == &node_resource // && connection.m_source_socket == &socket) { - // iter = graph_resource.m_connections.erase(iter); + // iter = sGraphGresource.m_connections.erase(iter); // } else { // iter++; // } @@ -91,19 +93,13 @@ void AnimGraphEditorRenderSidebar( property.m_name.c_str(), reinterpret_cast(property.m_reference.ptr)); } else if (property.m_type == SocketType::SocketTypeString) { - std::string* property_string = - reinterpret_cast(property.m_reference.ptr); - char string_buf[256]; - memset(string_buf, 0, sizeof(string_buf)); - strncpy( - string_buf, - property_string->c_str(), - std::min(property_string->size(), sizeof(string_buf))); + char string_buf[1024]; + memcpy (string_buf, property.m_value.string_ptr->c_str(), property.m_value.string_ptr->size() + 1); if (ImGui::InputText( property.m_name.c_str(), string_buf, sizeof(string_buf))) { - (*property_string) = string_buf; + *property.m_value.string_ptr = string_buf; } } } @@ -152,33 +148,31 @@ void AnimGraphEditorRenderSidebar( } void AnimGraphEditorUpdate() { - static AnimGraphResource graph_resource = AnimGraphResource(); - ImGui::BeginMenuBar(); if (ImGui::Button("Save")) { - graph_resource.saveToFile("editor_graph.json"); + sGraphGresource.saveToFile("editor_graph.json"); } if (ImGui::Button("Load")) { - graph_resource.loadFromFile("editor_graph.json"); + sGraphGresource.loadFromFile("editor_graph.json"); - for (size_t i = 0, n = graph_resource.m_nodes.size(); i < n; i++) { - const AnimNodeResource& node_resource = graph_resource.m_nodes[i]; + for (size_t i = 0, n = sGraphGresource.m_nodes.size(); i < n; i++) { + const AnimNodeResource& node_resource = sGraphGresource.m_nodes[i]; ImNodes::SetNodeGridSpacePos( i, ImVec2(node_resource.m_position[0], node_resource.m_position[1])); } } if (ImGui::Button("Clear")) { - graph_resource.clear(); + sGraphGresource.clear(); } char graph_name_buffer[256]; memset(graph_name_buffer, 0, sizeof(graph_name_buffer)); strncpy( graph_name_buffer, - graph_resource.m_name.c_str(), + sGraphGresource.m_name.c_str(), sizeof(graph_name_buffer)); if (ImGui::InputText("Name", graph_name_buffer, sizeof(graph_name_buffer))) { - graph_resource.m_name = graph_name_buffer; + sGraphGresource.m_name = graph_name_buffer; } ImGui::EndMenuBar(); @@ -228,9 +222,9 @@ void AnimGraphEditorUpdate() { if (node_type_name != "") { AnimNodeResource node_resource = AnimNodeResourceFactory(node_type_name); - size_t node_id = graph_resource.m_nodes.size(); + size_t node_id = sGraphGresource.m_nodes.size(); ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos()); - graph_resource.m_nodes.push_back(node_resource); + sGraphGresource.m_nodes.push_back(node_resource); } ImGui::EndPopup(); @@ -239,17 +233,17 @@ void AnimGraphEditorUpdate() { ImGui::PopStyleVar(ImGuiStyleVar_WindowPadding); } - for (size_t i = 0, n = graph_resource.m_nodes.size(); i < n; i++) { - AnimNodeResource& node_resource = graph_resource.m_nodes[i]; + for (size_t i = 0, n = sGraphGresource.m_nodes.size(); i < n; i++) { + AnimNodeResource& node_resource = sGraphGresource.m_nodes[i]; ImNodes::BeginNode(i); ImGui::PushItemWidth(110.0f); // Header ImNodes::BeginNodeTitleBar(); - if (&node_resource == &graph_resource.getGraphOutputNode()) { + if (&node_resource == &sGraphGresource.getGraphOutputNode()) { ImGui::TextUnformatted("Graph Outputs"); - } else if (&node_resource == &graph_resource.getGraphInputNode()) { + } else if (&node_resource == &sGraphGresource.getGraphInputNode()) { ImGui::TextUnformatted("Graph Inputs"); } else { ImGui::TextUnformatted(node_resource.m_type_name.c_str()); @@ -273,7 +267,8 @@ void AnimGraphEditorUpdate() { socket_color); ImGui::TextUnformatted(socket.m_name.c_str()); - bool socket_connected = graph_resource.isSocketConnected(node_resource, socket.m_name); + bool socket_connected = + sGraphGresource.isSocketConnected(node_resource, socket.m_name); if (!socket_connected && (socket.m_type == SocketType::SocketTypeFloat)) { ImGui::SameLine(); @@ -307,7 +302,7 @@ void AnimGraphEditorUpdate() { if (i == 0) { if (ImGui::Button("+Output")) { AnimNodeResource& graph_output_node = - graph_resource.getGraphOutputNode(); + sGraphGresource.getGraphOutputNode(); static float bla = 0.f; std::string socket_name = "Output"; @@ -319,7 +314,8 @@ void AnimGraphEditorUpdate() { } } else if (i == 1) { if (ImGui::Button("+Input")) { - AnimNodeResource& graph_input_node = graph_resource.getGraphInputNode(); + AnimNodeResource& graph_input_node = + sGraphGresource.getGraphInputNode(); static float bla = 0.f; std::string socket_name = "Input"; @@ -343,18 +339,18 @@ void AnimGraphEditorUpdate() { node_resource.m_socket_accessor->UpdateFlags(); } - for (size_t i = 0, n = graph_resource.m_connections.size(); i < n; i++) { + for (size_t i = 0, n = sGraphGresource.m_connections.size(); i < n; i++) { const AnimGraphConnectionResource& connection = - graph_resource.m_connections[i]; + sGraphGresource.m_connections[i]; int start_attr, end_attr; const AnimNodeResource& source_node = - graph_resource.m_nodes[connection.source_node_index]; + sGraphGresource.m_nodes[connection.source_node_index]; int source_socket_index = source_node.m_socket_accessor->GetOutputIndex( connection.source_socket_name); const AnimNodeResource& target_node = - graph_resource.m_nodes[connection.target_node_index]; + sGraphGresource.m_nodes[connection.target_node_index]; int target_socket_index = target_node.m_socket_accessor->GetInputIndex( connection.target_socket_name); @@ -386,24 +382,29 @@ void AnimGraphEditorUpdate() { AnimGraphConnectionResource connection; connection.source_node_index = node_start_id; - const AnimNodeResource& source_node = graph_resource.m_nodes[node_start_id]; + const AnimNodeResource& source_node = + sGraphGresource.m_nodes[node_start_id]; connection.source_socket_name = source_node.m_socket_accessor->m_outputs[node_start_output_index] .m_name; connection.target_node_index = node_end_id; - const AnimNodeResource& target_node = graph_resource.m_nodes[node_end_id]; + const AnimNodeResource& target_node = sGraphGresource.m_nodes[node_end_id]; connection.target_socket_name = target_node.m_socket_accessor->m_inputs[node_end_input_index].m_name; - graph_resource.m_connections.push_back(connection); + sGraphGresource.m_connections.push_back(connection); + } + + if (ImGui::IsKeyPressed(ImGuiKey_Delete, false)) { + std::cerr << "Delete key!" << std::endl; } // Handle link detachements. int link_id = 0; if (ImNodes::IsLinkDestroyed(&link_id)) { - graph_resource.m_connections.erase( - graph_resource.m_connections.begin() + link_id); + sGraphGresource.m_connections.erase( + sGraphGresource.m_connections.begin() + link_id); } int selected_nodes[ImNodes::NumSelectedNodes()]; @@ -415,12 +416,16 @@ void AnimGraphEditorUpdate() { ImGui::NextColumn(); if (ImNodes::NumSelectedNodes() == 1) { - if (selected_nodes[0] < graph_resource.m_nodes.size()) { + if (selected_nodes[0] < sGraphGresource.m_nodes.size()) { AnimNodeResource& selected_node = - graph_resource.m_nodes[selected_nodes[0]]; - AnimGraphEditorRenderSidebar(graph_resource, selected_node); + sGraphGresource.m_nodes[selected_nodes[0]]; + AnimGraphEditorRenderSidebar(sGraphGresource, selected_node); } } ImGui::Columns(1); +} + +void AnimGraphEditorGetRuntimeGraph(AnimGraph& anim_graph) { + sGraphGresource.createInstance(anim_graph); } \ No newline at end of file diff --git a/src/AnimGraph/AnimGraphEditor.h b/src/AnimGraph/AnimGraphEditor.h index ba2cf6d..cd2c511 100644 --- a/src/AnimGraph/AnimGraphEditor.h +++ b/src/AnimGraph/AnimGraphEditor.h @@ -5,6 +5,8 @@ #ifndef ANIMTESTBED_ANIMGRAPHEDITOR_H #define ANIMTESTBED_ANIMGRAPHEDITOR_H +#include "AnimGraph.h" + inline int GenerateInputAttributeId(int node_id, int input_index) { return ((input_index + 1) << 14) + node_id; } @@ -27,4 +29,6 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) { void AnimGraphEditorUpdate(); +void AnimGraphEditorGetRuntimeGraph(AnimGraph& anim_graph); + #endif //ANIMTESTBED_ANIMGRAPHEDITOR_H diff --git a/src/AnimGraph/AnimGraphResource.cc b/src/AnimGraph/AnimGraphResource.cc index 64afb19..8ebbb6b 100644 --- a/src/AnimGraph/AnimGraphResource.cc +++ b/src/AnimGraph/AnimGraphResource.cc @@ -43,7 +43,7 @@ json sSocketToJson(const Socket& socket) { result["value"][2] = socket.m_value.quat[2]; result["value"][3] = socket.m_value.quat[3]; } else if (socket.m_type == SocketType::SocketTypeString) { - result["value"] = std::string(socket.m_value.str); + result["value"] = *socket.m_value.string_ptr; } else { std::cerr << "Invalid socket type '" << static_cast(socket.m_type) << "'." << std::endl; @@ -142,17 +142,7 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) { property.m_value.quat[2] = json_property["value"][2]; property.m_value.quat[3] = json_property["value"][3]; } else if (property.m_type == SocketType::SocketTypeString) { - std::string value_str = json_property["value"]; - size_t string_length = value_str.size(); - constexpr size_t string_max_length = sizeof(property.m_value.str) - 1; - if (string_length > string_max_length) { - std::cerr << "Warning: string '" << value_str - << "' too long, truncating to " << string_max_length - << " bytes." << std::endl; - string_length = string_max_length; - } - memcpy(property.m_value.str, value_str.data(), string_length); - property.m_value.str[string_length] = 0; + *(property.m_value.string_ptr) = json_property["value"].get(); } else { std::cerr << "Invalid type for property '" << property.m_name << "'. Cannot parse json to type '" @@ -263,7 +253,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const { std::ofstream output_file; output_file.open(filename); - output_file << to_string(result) << std::endl; + output_file << result.dump(4, ' ') << std::endl; output_file.close(); return true; @@ -340,18 +330,14 @@ bool AnimGraphResource::loadFromFile(const char* filename) { return true; } -AnimGraph AnimGraphResource::createInstance() const { - AnimGraph result; - +void AnimGraphResource::createInstance(AnimGraph& result) const { createRuntimeNodeInstances(result); prepareGraphIOData(result); connectRuntimeNodes(result); setRuntimeNodeProperties(result); result.updateOrderedNodes(); - result.reset(); - - return result; + result.resetNodeStates(); } void AnimGraphResource::createRuntimeNodeInstances(AnimGraph& instance) const { @@ -384,8 +370,11 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const { for (int i = 0; i < graph_inputs.size(); i++) { input_block_size += sizeof(void*); } - instance.m_input_buffer = new char[input_block_size]; - memset(instance.m_input_buffer, 0, input_block_size); + + if (input_block_size > 0) { + instance.m_input_buffer = new char[input_block_size]; + memset(instance.m_input_buffer, 0, input_block_size); + } int input_block_offset = 0; for (int i = 0; i < graph_inputs.size(); i++) { @@ -400,8 +389,11 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const { for (int i = 0; i < graph_outputs.size(); i++) { output_block_size += graph_outputs[i].m_type_size; } - instance.m_output_buffer = new char[output_block_size]; - memset(instance.m_output_buffer, 0, output_block_size); + + if (output_block_size > 0) { + instance.m_output_buffer = new char[output_block_size]; + memset(instance.m_output_buffer, 0, output_block_size); + } int output_block_offset = 0; for (int i = 0; i < graph_outputs.size(); i++) { @@ -557,9 +549,9 @@ void AnimGraphResource::setRuntimeNodeProperties(AnimGraph& instance) const { property.m_value.quat); break; case SocketType::SocketTypeString: - node_instance_accessor->SetPropertyReferenceValue( + node_instance_accessor->SetPropertyValue( name, - property.m_value.str); + *property.m_value.string_ptr); break; default: std::cerr << "Invalid socket type " diff --git a/src/AnimGraph/AnimGraphResource.h b/src/AnimGraph/AnimGraphResource.h index e4b1ae9..c67db9e 100644 --- a/src/AnimGraph/AnimGraphResource.h +++ b/src/AnimGraph/AnimGraphResource.h @@ -140,7 +140,7 @@ struct AnimGraphResource { return false; } - AnimGraph createInstance() const; + void createInstance(AnimGraph& result) const; void createRuntimeNodeInstances(AnimGraph& instance) const; void prepareGraphIOData(AnimGraph& instance) const; diff --git a/src/main.cc b/src/main.cc index 4401b52..4da9e65 100644 --- a/src/main.cc +++ b/src/main.cc @@ -82,6 +82,7 @@ static struct { float anim_ratio; bool anim_ratio_ui_override; bool paused; + bool use_graph = false; } time; } state; @@ -311,7 +312,7 @@ int main() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); glfwWindowHint(GLFW_SAMPLES, 16); - GLFWwindow* w = glfwCreateWindow(Width, Height, "AnimTestbed", 0, 0); + GLFWwindow* w = glfwCreateWindow(Width, Height, "ATP Editor", 0, 0); glfwMakeContextCurrent(w); glfwSwapInterval(1); @@ -378,9 +379,11 @@ int main() { SkinnedMesh skinned_mesh; skinned_mesh_resource.createInstance(skinned_mesh); - skinned_mesh.SetCurrentAnimation(0); + AnimGraph anim_graph; + AnimGraphContext anim_graph_context; + state.time.factor = 1.0f; Camera_Init(&state.camera); @@ -611,6 +614,13 @@ int main() { ImGui::EndMenu(); } + if (ImGui::Button("Update Runtime Graph")) { + anim_graph.dealloc(); + AnimGraphEditorGetRuntimeGraph(anim_graph); + anim_graph_context.m_skeleton = &skinned_mesh.m_skeleton; + anim_graph.init(anim_graph_context); + } + ImGui::EndMainMenuBar(); } @@ -654,8 +664,8 @@ int main() { } if (gApplicationConfig.animation_player_widget.visible) { - ImGui::SetNextWindowPos(ImVec2(gApplicationConfig.animation_player_widget.position[0], gApplicationConfig.skinned_mesh_widget.position[1]), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSize(ImVec2(gApplicationConfig.animation_player_widget.size[0], gApplicationConfig.skinned_mesh_widget.size[1]), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(gApplicationConfig.animation_player_widget.position[0], gApplicationConfig.animation_player_widget.position[1]), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(gApplicationConfig.animation_player_widget.size[0], gApplicationConfig.animation_player_widget.size[1]), ImGuiCond_FirstUseEver); ImGui::Begin("Animation Player", &gApplicationConfig.animation_player_widget.visible); @@ -667,16 +677,28 @@ int main() { gApplicationConfig.animation_player_widget.size[0] = animation_player_widget_size.x; gApplicationConfig.animation_player_widget.size[1] = animation_player_widget_size.y; - ImGui::Text("Animation"); - - const char* items[255] = {0}; - static int selected = -1; - for (int i = 0; i < skinned_mesh.m_animations.size(); i++) { - items[i] = skinned_mesh.m_animation_names[i].c_str(); + if (anim_graph.m_nodes.size() > 0) { + ImGui::Checkbox("Use Graph", &state.time.use_graph); + } else { + state.time.use_graph = false; } - if (ImGui::Combo("Animation", &selected, items, skinned_mesh.m_animations.size())) { - state.ozz.animation = skinned_mesh.m_animations[selected]; + if (!state.time.use_graph) { + ImGui::Text("Animation"); + + const char* items[255] = {0}; + static int selected = -1; + for (int i = 0; i < skinned_mesh.m_animations.size(); i++) { + items[i] = skinned_mesh.m_animation_names[i].c_str(); + } + + if (ImGui::Combo( + "Animation", + &selected, + items, + skinned_mesh.m_animations.size())) { + state.ozz.animation = skinned_mesh.m_animations[selected]; + } } if (state.time.paused) { diff --git a/tests/AnimGraphEvalTests.cc b/tests/AnimGraphEvalTests.cc index b438019..af7ea02 100644 --- a/tests/AnimGraphEvalTests.cc +++ b/tests/AnimGraphEvalTests.cc @@ -190,8 +190,8 @@ TEST_CASE_METHOD( graph_context.m_animation_map["trans_y"] = animation_translate_y.get(); // Instantiate graph - AnimGraph graph = graph_resource.createInstance(); - graph_context.m_graph = &graph; + AnimGraph graph; + graph_resource.createInstance(graph); graph.init(graph_context); // Get runtime graph inputs and outputs diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 6fd4bdf..48a2dd7 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -74,9 +74,9 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") { AnimGraphResource graph_resource_loaded; graph_resource_loaded.loadFromFile("WalkGraph.animgraph.json"); - AnimGraph graph = graph_resource_loaded.createInstance(); + AnimGraph graph; + graph_resource_loaded.createInstance(graph); AnimGraphContext graph_context; - graph_context.m_graph = &graph; ozz::animation::Skeleton skeleton; REQUIRE(load_skeleton(skeleton, "data/skeleton.ozz")); @@ -283,7 +283,8 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { != nullptr); WHEN("Instantiating an AnimGraph") { - AnimGraph anim_graph = graph_resource_loaded.createInstance(); + AnimGraph anim_graph; + graph_resource_loaded.createInstance(anim_graph); REQUIRE(anim_graph.getInputSocket("GraphFloatInput") != nullptr); REQUIRE( @@ -418,7 +419,8 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { graph_resource_loaded.m_nodes[1]; WHEN("Instantiating an AnimGraph") { - AnimGraph anim_graph = graph_resource_loaded.createInstance(); + AnimGraph anim_graph; + graph_resource_loaded.createInstance(anim_graph); REQUIRE(anim_graph.getInputSocket("GraphFloatInput") != nullptr); REQUIRE( @@ -495,12 +497,12 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { } TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { - AnimGraphResource graph_resource; + AnimGraphResource sGraphGresource; - graph_resource.clear(); - graph_resource.m_name = "TestGraphInputOutputConnectivity"; + sGraphGresource.clear(); + sGraphGresource.m_name = "TestGraphInputOutputConnectivity"; - AnimNodeResource& graph_output_node = graph_resource.m_nodes[0]; + AnimNodeResource& graph_output_node = sGraphGresource.m_nodes[0]; graph_output_node.m_socket_accessor->RegisterInput( "GraphFloatOutput", nullptr); @@ -508,7 +510,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { "GraphAnimOutput", nullptr); - AnimNodeResource& graph_input_node = graph_resource.m_nodes[1]; + AnimNodeResource& graph_input_node = sGraphGresource.m_nodes[1]; graph_input_node.m_socket_accessor->RegisterOutput( "GraphFloatInput", nullptr); @@ -523,13 +525,13 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { nullptr); WHEN("Connecting float input with float output") { - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphFloatInput", - graph_resource.getGraphOutputNode(), + sGraphGresource.getGraphOutputNode(), "GraphFloatOutput")); - AnimGraph anim_graph = graph_resource.createInstance(); + AnimGraph anim_graph = sGraphGresource.createInstance(); THEN("Writing to the input pointer changes the value of the output.") { float* float_input_ptr = (float*)anim_graph.getInput("GraphFloatInput"); @@ -545,18 +547,18 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { WHEN("Connecting adding a Blend2 node") { size_t blend2_node_index = - graph_resource.addNode(AnimNodeResourceFactory("Blend2")); + sGraphGresource.addNode(AnimNodeResourceFactory("Blend2")); AnimNodeResource& blend2_node_resource = - graph_resource.m_nodes[blend2_node_index]; + sGraphGresource.m_nodes[blend2_node_index]; - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphFloatInput", blend2_node_resource, "Weight")); THEN("Connected float input points to the blend weight.") { - AnimGraph anim_graph = graph_resource.createInstance(); + AnimGraph anim_graph = sGraphGresource.createInstance(); Blend2Node* blend2_node = dynamic_cast(anim_graph.m_nodes[blend2_node_index]); @@ -571,28 +573,28 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { WHEN( "Connecting AnimData inputs to blend2 node and blend2 output to graph " "output.") { - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphAnimInput0", blend2_node_resource, "Input0")); - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphAnimInput1", blend2_node_resource, "Input1")); - REQUIRE(graph_resource.connectSockets( + REQUIRE(sGraphGresource.connectSockets( blend2_node_resource, "Output", - graph_resource.getGraphOutputNode(), + sGraphGresource.getGraphOutputNode(), "GraphAnimOutput")); THEN( "AnimData from output gets blended and result is written to " "Output.") { - AnimGraph anim_graph = graph_resource.createInstance(); + AnimGraph anim_graph = sGraphGresource.createInstance(); Blend2Node* blend2_node = dynamic_cast(anim_graph.m_nodes[blend2_node_index]); @@ -623,57 +625,57 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { WHEN("Adding AnimSampler Nodes") { size_t blend2_node_index = - graph_resource.addNode(AnimNodeResourceFactory("Blend2")); + sGraphGresource.addNode(AnimNodeResourceFactory("Blend2")); size_t sampler_node_index = - graph_resource.addNode(AnimNodeResourceFactory("AnimSampler")); + sGraphGresource.addNode(AnimNodeResourceFactory("AnimSampler")); size_t speed_scale_node_index = - graph_resource.addNode(AnimNodeResourceFactory("SpeedScale")); + sGraphGresource.addNode(AnimNodeResourceFactory("SpeedScale")); AnimNodeResource& blend2_node_resource = - graph_resource.m_nodes[blend2_node_index]; + sGraphGresource.m_nodes[blend2_node_index]; AnimNodeResource& sampler_node_resource = - graph_resource.m_nodes[sampler_node_index]; + sGraphGresource.m_nodes[sampler_node_index]; AnimNodeResource& speed_scale_node_resource = - graph_resource.m_nodes[speed_scale_node_index]; + sGraphGresource.m_nodes[speed_scale_node_index]; - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphFloatInput", blend2_node_resource, "Weight")); - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "SpeedScaleInput", speed_scale_node_resource, "SpeedScale")); - REQUIRE(graph_resource.connectSockets( - graph_resource.getGraphInputNode(), + REQUIRE(sGraphGresource.connectSockets( + sGraphGresource.getGraphInputNode(), "GraphAnimInput0", blend2_node_resource, "Input0")); - REQUIRE(graph_resource.connectSockets( + REQUIRE(sGraphGresource.connectSockets( sampler_node_resource, "Output", speed_scale_node_resource, "Input")); - REQUIRE(graph_resource.connectSockets( + REQUIRE(sGraphGresource.connectSockets( speed_scale_node_resource, "Output", blend2_node_resource, "Input1")); - REQUIRE(graph_resource.connectSockets( + REQUIRE(sGraphGresource.connectSockets( blend2_node_resource, "Output", - graph_resource.getGraphOutputNode(), + sGraphGresource.getGraphOutputNode(), "GraphAnimOutput")); THEN("Data flow and node ordering must be correct.") { - AnimGraph anim_graph = graph_resource.createInstance(); + AnimGraph anim_graph = sGraphGresource.createInstance(); Blend2Node* blend2_node = dynamic_cast(anim_graph.m_nodes[blend2_node_index]); SpeedScaleNode* speed_scale_node = dynamic_cast( @@ -727,7 +729,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") { } WHEN("Instantiating graph") { - AnimGraph anim_graph = graph_resource.createInstance(); + AnimGraph anim_graph = sGraphGresource.createInstance(); float* blend_weight_input = reinterpret_cast(anim_graph.getInput("GraphFloatInput"));