diff --git a/src/AnimGraph/AnimGraphResource.cc b/src/AnimGraph/AnimGraphResource.cc index 0df9a5a..c4b0bf3 100644 --- a/src/AnimGraph/AnimGraphResource.cc +++ b/src/AnimGraph/AnimGraphResource.cc @@ -16,11 +16,11 @@ using json = nlohmann::json; // forward declarations -static json sAnimGraphResourceBlendTreeToJson( - const AnimGraphResource& anim_graph_resource); -static bool sAnimGraphResourceBlendTreeFromJson( +static json sBlendTreeToJson(const BlendTreeResource& anim_graph_resource); + +static bool sBlendTreeFromJson( const json& json_data, - AnimGraphResource* result_graph_resource); + BlendTreeResource* result_graph_resource); // // Socket <-> json @@ -134,7 +134,7 @@ Socket sJsonToSocket(const json& json_data) { // json sAnimGraphNodeToJson( const AnimNodeResource* node, - size_t node_index, + const size_t node_index, const std::vector& connections) { json result; @@ -181,9 +181,9 @@ AnimNodeResource* sAnimGraphNodeFromJson( std::string node_type = json_node["node_type"]; if (node_type == "BlendTree") { - AnimGraphResource* result = - dynamic_cast(AnimNodeResourceFactory("BlendTree")); - sAnimGraphResourceBlendTreeFromJson(json_node, result); + BlendTreeResource* result = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + sBlendTreeFromJson(json_node, result); return result; } @@ -244,26 +244,25 @@ BlendTreeConnectionResource sAnimGraphConnectionFromJson( return connection; } -static json sAnimGraphResourceBlendTreeToJson( - const AnimGraphResource& anim_graph_resource) { +// +// BlendTreeResource <-> Json +// +static json sBlendTreeToJson(const BlendTreeResource& blend_tree_resource) { json result; - result["name"] = anim_graph_resource.m_name; + result["name"] = blend_tree_resource.m_name; result["type"] = "AnimNodeResource"; result["node_type"] = "BlendTree"; - result["position"][0] = anim_graph_resource.m_position[0]; - result["position"][1] = anim_graph_resource.m_position[1]; - - const BlendTreeResource& blend_tree_resource = - anim_graph_resource.m_blend_tree_resource; + result["position"][0] = blend_tree_resource.m_position[0]; + result["position"][1] = blend_tree_resource.m_position[1]; for (size_t i = 0; i < blend_tree_resource.GetNumNodes(); i++) { const AnimNodeResource* node = blend_tree_resource.GetNode(i); if (node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource); + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); + result["nodes"][i] = sBlendTreeToJson(*blend_tree_resource); } else { result["nodes"][i] = sAnimGraphNodeToJson(node, i, blend_tree_resource.GetConnections()); @@ -295,20 +294,16 @@ static json sAnimGraphResourceBlendTreeToJson( return result; } -static bool sAnimGraphResourceBlendTreeFromJson( +static bool sBlendTreeFromJson( const json& json_data, - AnimGraphResource* result_graph_resource) { - BlendTreeResource& blend_tree_resource = - result_graph_resource->m_blend_tree_resource; - - result_graph_resource->m_graph_type_name = "BlendTree"; - result_graph_resource->m_node_type_name = "BlendTree"; - result_graph_resource->m_name = json_data["name"]; - result_graph_resource->m_position[0] = json_data["position"][0]; - result_graph_resource->m_position[1] = json_data["position"][1]; + BlendTreeResource* result_blend_tree_resource) { + result_blend_tree_resource->m_node_type_name = "BlendTree"; + result_blend_tree_resource->m_name = json_data["name"]; + result_blend_tree_resource->m_position[0] = json_data["position"][0]; + result_blend_tree_resource->m_position[1] = json_data["position"][1]; // Clear all nodes as we overwrite them here anyway. - blend_tree_resource.ClearAllNodes(); + result_blend_tree_resource->ClearAllNodes(); // Load nodes for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) { @@ -321,14 +316,14 @@ static bool sAnimGraphResourceBlendTreeFromJson( } AnimNodeResource* node = sAnimGraphNodeFromJson(json_node, i); - blend_tree_resource.AddNode(node); + result_blend_tree_resource->AddNode(node); } // Graph outputs if (json_data["nodes"][0].contains("inputs")) { const json& graph_outputs = json_data["nodes"][0]["inputs"]; for (const auto& graph_output : graph_outputs) { - result_graph_resource->RegisterBlendTreeOutputSocket( + result_blend_tree_resource->RegisterBlendTreeOutputSocket( sJsonToSocket(graph_output)); } } @@ -337,7 +332,7 @@ static bool sAnimGraphResourceBlendTreeFromJson( if (json_data["nodes"][1].contains("outputs")) { const json& graph_inputs = json_data["nodes"][1]["outputs"]; for (const auto& graph_input : graph_inputs) { - result_graph_resource->RegisterBlendTreeInputSocket( + result_blend_tree_resource->RegisterBlendTreeInputSocket( sJsonToSocket(graph_input)); } } @@ -356,10 +351,10 @@ static bool sAnimGraphResourceBlendTreeFromJson( BlendTreeConnectionResource connection = sAnimGraphConnectionFromJson(json_connection); - blend_tree_resource.ConnectSockets( - blend_tree_resource.GetNode(connection.source_node_index), + result_blend_tree_resource->ConnectSockets( + result_blend_tree_resource->GetNode(connection.source_node_index), connection.source_socket_name, - blend_tree_resource.GetNode(connection.target_node_index), + result_blend_tree_resource->GetNode(connection.target_node_index), connection.target_socket_name); } } @@ -375,6 +370,92 @@ static bool sAnimGraphResourceStateMachineFromJson( return false; } +AnimGraphResource* AnimGraphResource::CreateFromFile(const char* filename) { + std::ifstream input_file; + input_file.open(filename); + std::stringstream buffer; + buffer << input_file.rdbuf(); + + json json_data = json::parse(buffer.str(), nullptr, false); + if (json_data.is_discarded()) { + std::cerr << "Error parsing json of file '" << filename << "'." + << std::endl; + + return nullptr; + } + + if (json_data["type"] != "AnimNodeResource") { + std::cerr + << "Invalid json object. Expected type 'AnimNodeResource' but got '" + << json_data["type"] << "'." << std::endl; + + return nullptr; + } + + AnimGraphResource* result = nullptr; + if (json_data["node_type"] == "BlendTree") { + result = BlendTreeResource::CreateFromFile(filename); + } else if (json_data["node_type"] == "StateMachine") { + sAnimGraphResourceStateMachineFromJson(json_data, result); + } else { + std::cerr << "Invalid node_type. Expected type 'BlendTree' or " + "'StateMachine' but got '" + << json_data["node_type"] << "'." << std::endl; + } + + return result; +} + +bool BlendTreeResource::SaveToFile(const char* filename) const { + json result; + + result = sBlendTreeToJson(*this); + + std::ofstream output_file; + output_file.open(filename); + output_file << result.dump(4, ' ') << std::endl; + output_file.close(); + + return true; +} + +BlendTreeResource* BlendTreeResource::CreateFromFile(const char* filename) { + std::ifstream input_file; + input_file.open(filename); + std::stringstream buffer; + buffer << input_file.rdbuf(); + + json json_data = json::parse(buffer.str(), nullptr, false); + if (json_data.is_discarded()) { + std::cerr << "Error parsing json of file '" << filename << "'." + << std::endl; + + return nullptr; + } + + if (json_data["type"] != "AnimNodeResource") { + std::cerr + << "Invalid json object. Expected type 'AnimNodeResource' but got '" + << json_data["type"] << "'." << std::endl; + + return nullptr; + } + + if (json_data["node_type"] != "BlendTree") { + std::cerr << "Invalid node type. Expected type 'BlendTree' but got '" + << json_data["node_type"] << "'." << std::endl; + + return nullptr; + } + + BlendTreeResource* result = nullptr; + result = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + sBlendTreeFromJson(json_data, result); + + return result; +} + void BlendTreeResource::RemoveConnectionsForSocket( const AnimNodeResource* node_resource, const Socket& socket) { @@ -563,12 +644,10 @@ Socket* BlendTreeResource::GetNodeOutputSocket( } if (output_socket == nullptr && node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); output_socket = - blend_tree_resource.GetGraphOutputSocket(output_socket_name.c_str()); + blend_tree_resource->GetGraphOutputSocket(output_socket_name.c_str()); } return output_socket; @@ -582,12 +661,10 @@ const Socket* BlendTreeResource::GetNodeOutputSocketByIndex( if (node->m_virtual_socket_accessor) { output_sockets = &node->m_virtual_socket_accessor->m_outputs; } else if (node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); - output_sockets = &blend_tree_resource.GetGraphOutputNode() + output_sockets = &blend_tree_resource->GetGraphOutputNode() ->m_virtual_socket_accessor->m_outputs; } @@ -610,12 +687,10 @@ Socket* BlendTreeResource::GetNodeInputSocket( } if (input_socket == nullptr && node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); input_socket = - blend_tree_resource.GetGraphInputSocket(input_socket_name.c_str()); + blend_tree_resource->GetGraphInputSocket(input_socket_name.c_str()); } return input_socket; @@ -629,12 +704,10 @@ const Socket* BlendTreeResource::GetNodeInputSocketByIndex( if (node->m_virtual_socket_accessor) { output_sockets = &node->m_virtual_socket_accessor->m_inputs; } else if (node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); - output_sockets = &blend_tree_resource.GetGraphOutputNode() + output_sockets = &blend_tree_resource->GetGraphOutputNode() ->m_virtual_socket_accessor->m_outputs; } @@ -653,11 +726,10 @@ std::vector BlendTreeResource::GetNodeOutputSockets( } if (node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; - return blend_tree_resource.GetGraphOutputNode() + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); + + return blend_tree_resource->GetGraphOutputNode() ->m_virtual_socket_accessor->m_inputs; } @@ -671,11 +743,10 @@ std::vector BlendTreeResource::GetNodeInputSockets( } if (node->m_node_type_name == "BlendTree") { - const AnimGraphResource* graph_resource = - dynamic_cast(node); - const BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; - return blend_tree_resource.GetGraphInputNode() + const BlendTreeResource* blend_tree_resource = + dynamic_cast(node); + + return blend_tree_resource->GetGraphInputNode() ->m_virtual_socket_accessor->m_outputs; } @@ -824,92 +895,12 @@ void BlendTreeResource::UpdateNodeSubtrees() { } } -AnimGraphResource::AnimGraphResource(AnimGraphType graph_type) { - if (graph_type == AnimGraphType::GraphTypeBlendTree) { - m_graph_type_name = "BlendTree"; - m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree"); - - m_blend_tree_resource.InitGraphConnectors(); - RegisterBlendTreeOutputSocket( - AnimGraphResource::DefaultAnimOutput); - } else { - std::cerr - << "Warning: construction of state machine graphs not yet implemented!" - << std::endl; - } -} - -AnimGraphResource* AnimGraphResource::CreateFromFile(const char* filename) { - std::ifstream input_file; - input_file.open(filename); - std::stringstream buffer; - buffer << input_file.rdbuf(); - - json json_data = json::parse(buffer.str(), nullptr, false); - if (json_data.is_discarded()) { - std::cerr << "Error parsing json of file '" << filename << "'." - << std::endl; - - return nullptr; - } - - if (json_data["type"] != "AnimNodeResource") { - std::cerr - << "Invalid json object. Expected type 'AnimNodeResource' but got '" - << json_data["type"] << "'." << std::endl; - - return nullptr; - } - - AnimGraphResource* result = nullptr; - if (json_data["node_type"] == "BlendTree") { - result = - dynamic_cast(AnimNodeResourceFactory("BlendTree")); - sAnimGraphResourceBlendTreeFromJson(json_data, result); - } else if (json_data["node_type"] == "StateMachine") { - sAnimGraphResourceStateMachineFromJson(json_data, result); - } else { - std::cerr << "Invalid node_type. Expected type 'BlendTree' or " - "'StateMachine' but got '" - << json_data["node_type"] << "'." << std::endl; - } - - return result; -} - -bool AnimGraphResource::SaveToFile(const char* filename) const { - if (m_graph_type_name == "BlendTree") { - return SaveBlendTreeResourceToFile(filename); - } else if (m_graph_type_name == "StateMachine") { - return SaveStateMachineResourceToFile(filename); - } - - std::cerr << "Invalid AnimGraphResource type: " << m_graph_type_name << "." - << std::endl; - - return false; -} - -bool AnimGraphResource::SaveBlendTreeResourceToFile( - const char* filename) const { - json result; - - result = sAnimGraphResourceBlendTreeToJson(*this); - - std::ofstream output_file; - output_file.open(filename); - output_file << result.dump(4, ' ') << std::endl; - output_file.close(); - - return true; -} - -void AnimGraphResource::CreateBlendTreeInstance( +void BlendTreeResource::CreateBlendTreeInstance( AnimGraphBlendTree& result) const { if (m_node_type_name != "BlendTree") { std::cerr << "Invalid AnimGraphResource. Expected type 'BlendTree' but got '" - << m_graph_type_name << "'." << std::endl; + << m_node_type_name << "'." << std::endl; return; } @@ -926,15 +917,14 @@ void AnimGraphResource::CreateBlendTreeInstance( result.ResetNodeStates(); } -void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances( +void BlendTreeResource::CreateBlendTreeRuntimeNodeInstances( AnimGraphBlendTree& result) const { - for (const AnimNodeResource* node_resource : - m_blend_tree_resource.GetNodes()) { + for (const AnimNodeResource* node_resource : GetNodes()) { AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name); if (node_resource->m_node_type_name == "BlendTree") { - const AnimGraphResource* embedded_blend_tree_resource = - dynamic_cast(node_resource); + const BlendTreeResource* embedded_blend_tree_resource = + dynamic_cast(node_resource); assert(embedded_blend_tree_resource != nullptr); AnimGraphBlendTree* embedded_blend_tree = dynamic_cast(node); @@ -958,18 +948,16 @@ void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances( } } -void AnimGraphResource::PrepareBlendTreeIOData( +void BlendTreeResource::PrepareBlendTreeIOData( AnimGraphBlendTree& instance, NodeSocketDataOffsetMap& node_offset_map) const { instance.m_node_descriptor = AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]); instance.m_node_descriptor->m_outputs = - m_blend_tree_resource.GetGraphInputNode() - ->m_virtual_socket_accessor->m_outputs; + GetGraphInputNode()->m_virtual_socket_accessor->m_outputs; instance.m_node_descriptor->m_inputs = - m_blend_tree_resource.GetGraphOutputNode() - ->m_virtual_socket_accessor->m_inputs; + GetGraphOutputNode()->m_virtual_socket_accessor->m_inputs; // // graph inputs @@ -1019,15 +1007,13 @@ void AnimGraphResource::PrepareBlendTreeIOData( // connecton data storage // size_t connection_data_storage_size = 0; - for (const BlendTreeConnectionResource& connection : - m_blend_tree_resource.GetConnections()) { - const AnimNodeResource* source_node = - m_blend_tree_resource.GetNode(connection.source_node_index); + for (const BlendTreeConnectionResource& connection : GetConnections()) { + const AnimNodeResource* source_node = GetNode(connection.source_node_index); Socket* source_socket = source_node->m_virtual_socket_accessor->GetOutputSocket( connection.source_socket_name.c_str()); - NodeSocketPair source_socket_pair{source_node, source_socket->m_name}; + NodeSocketNamePair source_socket_pair{source_node, source_socket->m_name}; if (node_offset_map.find(source_socket_pair) == node_offset_map.end()) { node_offset_map.insert( {source_socket_pair, connection_data_storage_size}); @@ -1042,24 +1028,22 @@ void AnimGraphResource::PrepareBlendTreeIOData( } } -void AnimGraphResource::CreateBlendTreeConnectionInstances( +void BlendTreeResource::CreateBlendTreeConnectionInstances( AnimGraphBlendTree& instance, NodeSocketDataOffsetMap& node_offset_map) const { std::vector instance_node_descriptors( - m_blend_tree_resource.GetNumNodes(), + GetNumNodes(), nullptr); - for (int i = 0; i < m_blend_tree_resource.GetNumNodes(); i++) { + for (int i = 0; i < GetNumNodes(); i++) { instance_node_descriptors[i] = AnimNodeDescriptorFactory( - m_blend_tree_resource.GetNode(i)->m_node_type_name, + GetNode(i)->m_node_type_name, instance.m_nodes[i]); - if (i > 1 - && m_blend_tree_resource.GetNode(i)->m_node_type_name == "BlendTree") { + if (i > 1 && GetNode(i)->m_node_type_name == "BlendTree") { instance_node_descriptors[i]->m_inputs = - m_blend_tree_resource.GetNode(i)->m_virtual_socket_accessor->m_inputs; + GetNode(i)->m_virtual_socket_accessor->m_inputs; instance_node_descriptors[i]->m_outputs = - m_blend_tree_resource.GetNode(i) - ->m_virtual_socket_accessor->m_outputs; + GetNode(i)->m_virtual_socket_accessor->m_outputs; } } @@ -1067,8 +1051,7 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( instance_node_descriptors[1]->m_outputs = instance.m_node_descriptor->m_outputs; - for (const BlendTreeConnectionResource& connection : - m_blend_tree_resource.GetConnections()) { + for (const BlendTreeConnectionResource& connection : GetConnections()) { NodeDescriptorBase* source_node_descriptor = instance_node_descriptors[connection.source_node_index]; NodeDescriptorBase* target_node_descriptor = @@ -1110,15 +1093,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( instance.m_node_output_connections[connection.source_node_index] .push_back(embedded_graph_activation_connection); - const AnimGraphResource* source_blend_tree_resource = - dynamic_cast( - m_blend_tree_resource.GetNode(connection.source_node_index)); + const BlendTreeResource* source_blend_tree_resource = + dynamic_cast( + GetNode(connection.source_node_index)); AnimGraphBlendTree* source_blend_tree = dynamic_cast(source_node); size_t source_blend_tree_output_node_index = - source_blend_tree_resource->m_blend_tree_resource - .GetNodeIndexForOutputSocket(connection.source_socket_name); + source_blend_tree_resource->GetNodeIndexForOutputSocket( + connection.source_socket_name); source_node = source_blend_tree->m_nodes[source_blend_tree_output_node_index]; instance_connection.m_crosses_hierarchy = true; @@ -1127,15 +1110,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( // that the embedded node knows about its connection partner in the parent // tree. This allows the embedded node to properly activate the node in // the parent graph. - const AnimGraphResource* target_blend_tree_resource = - dynamic_cast( - m_blend_tree_resource.GetNode(connection.target_node_index)); + const BlendTreeResource* target_blend_tree_resource = + dynamic_cast( + GetNode(connection.target_node_index)); AnimGraphBlendTree* target_blend_tree = dynamic_cast(target_node); size_t target_blend_tree_output_node_index = - target_blend_tree_resource->m_blend_tree_resource - .GetNodeIndexForInputSocket(connection.target_socket_name); + target_blend_tree_resource->GetNodeIndexForInputSocket( + connection.target_socket_name); target_node = target_blend_tree->m_nodes[target_blend_tree_output_node_index]; @@ -1175,8 +1158,8 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( instance_connection.m_socket = *source_socket; } - NodeSocketPair node_socket_pair{ - m_blend_tree_resource.GetNode(connection.source_node_index), + NodeSocketNamePair node_socket_pair{ + GetNode(connection.source_node_index), source_socket->m_name}; NodeSocketDataOffsetMap::const_iterator socket_data_offset_iter = @@ -1214,7 +1197,7 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( // const node inputs // std::vector const_inputs = - m_blend_tree_resource.GetConstantNodeInputs(instance_node_descriptors); + GetConstantNodeInputs(instance_node_descriptors); size_t const_node_inputs_buffer_size = 0; for (auto& const_input : const_inputs) { if (const_input->m_type == SocketType::SocketTypeString) { @@ -1248,15 +1231,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( const_input_buffer_offset += i->m_type_size; } - for (int i = 0; i < m_blend_tree_resource.GetNumNodes(); i++) { + for (int i = 0; i < GetNumNodes(); i++) { delete instance_node_descriptors[i]; } } -void AnimGraphResource::SetRuntimeNodeProperties( +void BlendTreeResource::SetRuntimeNodeProperties( AnimGraphBlendTree& result) const { - for (int i = 2; i < m_blend_tree_resource.GetNumNodes(); i++) { - const AnimNodeResource* node_resource = m_blend_tree_resource.GetNode(i); + for (int i = 2; i < GetNumNodes(); i++) { + const AnimNodeResource* node_resource = GetNode(i); NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory( node_resource->m_node_type_name, @@ -1308,17 +1291,4 @@ void AnimGraphResource::SetRuntimeNodeProperties( } } -bool AnimGraphResource::SaveStateMachineResourceToFile( - const char* filename) const { - assert(false && "Not yet implemented"); - - return false; -} - -bool AnimGraphResource::LoadStateMachineResourceFromJson( - nlohmann::json const& json_data) { - assert(false && "Not yet implemented"); - - return false; -} -#pragma clang diagnostic pop \ No newline at end of file +#pragma clang diagnostic pop diff --git a/src/AnimGraph/AnimGraphResource.h b/src/AnimGraph/AnimGraphResource.h index be02716..edf9fb0 100644 --- a/src/AnimGraph/AnimGraphResource.h +++ b/src/AnimGraph/AnimGraphResource.h @@ -10,9 +10,10 @@ struct AnimGraphBlendTree; struct AnimGraphStateMachine; +struct BlendTreeResource; struct AnimNodeResource { - virtual ~AnimNodeResource() { delete m_virtual_socket_accessor; }; + virtual ~AnimNodeResource() { delete m_virtual_socket_accessor; } std::string m_name; std::string m_node_type_name; @@ -23,6 +24,30 @@ struct AnimNodeResource { static inline AnimNodeResource* AnimNodeResourceFactory( const std::string& node_type_name); +struct StateMachineTransitionResources { + size_t source_state_index = -1; + size_t target_state_index = -1; + float blend_time = 0.f; + bool sync_blend = false; +}; + +struct StateMachineResource { + std::vector m_states; + std::vector m_transitions; +}; + +struct AnimGraphResource : AnimNodeResource { + ~AnimGraphResource() override = default; + + static constexpr char DefaultAnimOutput[] = "Output"; + + [[maybe_unused]] virtual bool SaveToFile(const char* filename) const = 0; + + static AnimGraphResource* CreateFromFile(const char* filename); +}; + +typedef std::unique_ptr AnimGraphResourcePtr; + struct BlendTreeConnectionResource { int source_node_index = -1; std::string source_socket_name; @@ -39,12 +64,27 @@ struct BlendTreeConnectionResource { } }; -struct BlendTreeResource { +struct BlendTreeResource : AnimGraphResource { + typedef std::pair NodeSocketNamePair; + typedef std::map NodeSocketDataOffsetMap; + std::vector > m_node_input_connection_indices; std::vector > m_node_inputs_subtree; + BlendTreeResource() { + m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree"); + + InitGraphConnectors(); + RegisterBlendTreeOutputSocket( + AnimGraphResource::DefaultAnimOutput); + } ~BlendTreeResource() { ClearAllNodes(); } + [[maybe_unused]] bool SaveToFile(const char* filename) const override; + static BlendTreeResource* CreateFromFile(const char* filename); + + void CreateBlendTreeInstance(AnimGraphBlendTree& result) const; + void Reset() { ClearAllNodes(); @@ -65,18 +105,77 @@ struct BlendTreeResource { [[nodiscard]] AnimNodeResource* GetGraphOutputNode() const { return m_nodes[0]; } + [[nodiscard]] AnimNodeResource* GetGraphInputNode() const { return m_nodes[1]; } + Socket* GetGraphOutputSocket(const char* socket_name) const { return GetGraphOutputNode()->m_virtual_socket_accessor->GetInputSocket( socket_name); } + Socket* GetGraphInputSocket(const char* socket_name) const { return GetGraphInputNode()->m_virtual_socket_accessor->GetOutputSocket( socket_name); } + template + bool RegisterBlendTreeInputSocket(const std::string& socket_name) { + Socket socket; + socket.m_name = socket_name; + socket.m_type = GetSocketType(); + socket.m_type_size = sizeof(T); + + return RegisterBlendTreeInputSocket(socket); + } + + bool RegisterBlendTreeInputSocket(const Socket& socket) { + AnimNodeResource* input_node = GetGraphInputNode(); + + Socket* input_socket = GetGraphInputSocket(socket.m_name.c_str()); + + if (input_socket != nullptr) { + std::cerr << "Error: cannot register output socket as socket with name '" + << socket.m_name << "' already exists!" << std::endl; + return false; + } + + input_node->m_virtual_socket_accessor->m_outputs.push_back(socket); + m_virtual_socket_accessor->m_inputs = + input_node->m_virtual_socket_accessor->m_outputs; + + return true; + } + + template + bool RegisterBlendTreeOutputSocket(const std::string& socket_name) { + Socket socket; + socket.m_name = socket_name; + socket.m_type = GetSocketType(); + socket.m_type_size = sizeof(T); + + return RegisterBlendTreeOutputSocket(socket); + } + + bool RegisterBlendTreeOutputSocket(const Socket& socket) { + AnimNodeResource* output_node = GetGraphOutputNode(); + + Socket* output_socket = GetGraphOutputSocket(socket.m_name.c_str()); + + if (output_socket != nullptr) { + std::cerr << "Error: cannot register output socket as socket with name '" + << socket.m_name << "' already exists!" << std::endl; + return false; + } + + output_node->m_virtual_socket_accessor->m_inputs.push_back(socket); + m_virtual_socket_accessor->m_outputs = + output_node->m_virtual_socket_accessor->m_inputs; + + return true; + } + int GetNodeIndex(const AnimNodeResource* node_resource) const { for (size_t i = 0, n = m_nodes.size(); i < n; i++) { if (m_nodes[i] == node_resource) { @@ -125,14 +224,18 @@ struct BlendTreeResource { void RemoveConnectionsForSocket( const AnimNodeResource* node_resource, const Socket& socket); + void RemoveNodeConnections(AnimNodeResource* node_resource); + [[maybe_unused]] bool RemoveNode(AnimNodeResource* node_resource); [[nodiscard]] size_t GetNumNodes() const { return m_nodes.size(); } [[nodiscard]] AnimNodeResource* GetNode(size_t i) { return m_nodes[i]; } + [[nodiscard]] const AnimNodeResource* GetNode(size_t i) const { return m_nodes[i]; } + [[nodiscard]] const std::vector& GetNodes() const { return m_nodes; } @@ -172,6 +275,7 @@ struct BlendTreeResource { const size_t socket_input_index) const; std::vector GetNodeOutputSockets(const AnimNodeResource* node) const; + std::vector GetNodeInputSockets(const AnimNodeResource* node) const; bool ConnectSockets( @@ -265,6 +369,18 @@ struct BlendTreeResource { } private: + void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const; + + void PrepareBlendTreeIOData( + AnimGraphBlendTree& instance, + NodeSocketDataOffsetMap& node_offset_map) const; + + void CreateBlendTreeConnectionInstances( + AnimGraphBlendTree& instance, + NodeSocketDataOffsetMap& node_offset_map) const; + + void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const; + void InitGraphConnectors() { AddNode(AnimNodeResourceFactory("BlendTreeSockets")); AnimNodeResource* output_node = GetGraphOutputNode(); @@ -281,7 +397,9 @@ struct BlendTreeResource { m_node_eval_order.clear(); UpdateNodeEvalOrderRecursive(0); } + void UpdateNodeEvalOrderRecursive(size_t node_index); + void UpdateNodeSubtrees(); std::vector m_nodes; @@ -291,123 +409,12 @@ struct BlendTreeResource { friend class AnimGraphResource; }; -struct StateMachineTransitionResources { - size_t source_state_index = -1; - size_t target_state_index = -1; - float blend_time = 0.f; - bool sync_blend = false; -}; - -struct StateMachineResource { - std::vector m_states; - std::vector m_transitions; -}; - -struct AnimGraphResource : AnimNodeResource { - explicit AnimGraphResource(AnimGraphType graph_type); - virtual ~AnimGraphResource() { Clear(); }; - - static constexpr char DefaultAnimOutput[] = "Output"; - - std::string m_graph_type_name; - - BlendTreeResource m_blend_tree_resource; - typedef std::pair NodeSocketPair; - typedef std::map NodeSocketDataOffsetMap; - - StateMachineResource m_state_machine_resource; - - void Clear() { m_blend_tree_resource.Reset(); } - [[maybe_unused]] bool SaveToFile(const char* filename) const; - static AnimGraphResource* CreateFromFile(const char* filename); - - void CreateBlendTreeInstance(AnimGraphBlendTree& result) const; - - template - bool RegisterBlendTreeInputSocket(const std::string& socket_name) { - Socket socket; - socket.m_name = socket_name; - socket.m_type = GetSocketType(); - socket.m_type_size = sizeof(T); - - return RegisterBlendTreeInputSocket(socket); - } - - bool RegisterBlendTreeInputSocket(const Socket& socket) { - AnimNodeResource* input_node = m_blend_tree_resource.GetGraphInputNode(); - - Socket* input_socket = - m_blend_tree_resource.GetGraphInputSocket(socket.m_name.c_str()); - - if (input_socket != nullptr) { - std::cerr << "Error: cannot register output socket as socket with name '" - << socket.m_name << "' already exists!" << std::endl; - return false; - } - - input_node->m_virtual_socket_accessor->m_outputs.push_back(socket); - m_virtual_socket_accessor->m_inputs = - input_node->m_virtual_socket_accessor->m_outputs; - - return true; - } - - template - bool RegisterBlendTreeOutputSocket(const std::string& socket_name) { - Socket socket; - socket.m_name = socket_name; - socket.m_type = GetSocketType(); - socket.m_type_size = sizeof(T); - - return RegisterBlendTreeOutputSocket(socket); - } - - bool RegisterBlendTreeOutputSocket(const Socket& socket) { - AnimNodeResource* output_node = m_blend_tree_resource.GetGraphOutputNode(); - - Socket* output_socket = - m_blend_tree_resource.GetGraphOutputSocket(socket.m_name.c_str()); - - if (output_socket != nullptr) { - std::cerr << "Error: cannot register output socket as socket with name '" - << socket.m_name << "' already exists!" << std::endl; - return false; - } - - output_node->m_virtual_socket_accessor->m_inputs.push_back(socket); - m_virtual_socket_accessor->m_outputs = - output_node->m_virtual_socket_accessor->m_inputs; - - return true; - } - - void CreateStateMachineInstance(AnimGraphStateMachine& result) const; - - private: - // BlendTree - bool SaveBlendTreeResourceToFile(const char* filename) const; - void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const; - void PrepareBlendTreeIOData( - AnimGraphBlendTree& instance, - NodeSocketDataOffsetMap& node_offset_map) const; - void CreateBlendTreeConnectionInstances( - AnimGraphBlendTree& instance, - NodeSocketDataOffsetMap& node_offset_map) const; - void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const; - - bool SaveStateMachineResourceToFile(const char* filename) const; - bool LoadStateMachineResourceFromJson(nlohmann::json const& json_data); -}; - -typedef std::unique_ptr AnimGraphResourcePtr; - inline AnimNodeResource* AnimNodeResourceFactory( const std::string& node_type_name) { AnimNodeResource* result; if (node_type_name == "BlendTree") { - AnimGraphResource* blend_tree_resource = - new AnimGraphResource(AnimGraphType::GraphTypeBlendTree); + AnimGraphResource* blend_tree_resource = new BlendTreeResource(); result = blend_tree_resource; } else { result = new AnimNodeResource(); diff --git a/src/AnimGraphEditor/AnimGraphEditor.cc b/src/AnimGraphEditor/AnimGraphEditor.cc index 1ce6c82..35674d3 100644 --- a/src/AnimGraphEditor/AnimGraphEditor.cc +++ b/src/AnimGraphEditor/AnimGraphEditor.cc @@ -214,9 +214,15 @@ void SkinnedMeshWidget(SkinnedMesh* skinned_mesh) { } } -void AnimGraphEditorRenderSidebar( - BlendTreeResource& blend_tree_resource, +void BlendTreeEditorRenderSidebar( + BlendTreeResource* blend_tree_resource, AnimNodeResource* node_resource) { + BlendTreeResource* current_blend_tree_resource = + dynamic_cast( + sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]); + + assert(current_blend_tree_resource != nullptr); + ImGui::Text( "[%s (%2.2f, %2.2f)]", node_resource->m_node_type_name.c_str(), @@ -276,7 +282,7 @@ void AnimGraphEditorRenderSidebar( } } - if (node_resource == blend_tree_resource.GetGraphOutputNode()) { + if (node_resource == blend_tree_resource->GetGraphOutputNode()) { ImGui::Text("Outputs"); // Graph outputs are the inputs of the output node! @@ -319,17 +325,14 @@ void AnimGraphEditorRenderSidebar( ImGui::PopStyleVar(); if (ImGui::Button("+")) { - AnimGraphResource* current_graph_resource = - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]; - current_graph_resource->RegisterBlendTreeOutputSocket( + current_blend_tree_resource->RegisterBlendTreeOutputSocket( "GraphFloatOutput" - + std::to_string(current_graph_resource->m_blend_tree_resource - .GetGraphOutputNode() + + std::to_string(current_blend_tree_resource->GetGraphOutputNode() ->m_virtual_socket_accessor->m_inputs.size())); } } - if (node_resource == blend_tree_resource.GetGraphInputNode()) { + if (node_resource == blend_tree_resource->GetGraphInputNode()) { ImGui::Text("Inputs"); // Graph inputs are the outputs of the input node! @@ -346,7 +349,7 @@ void AnimGraphEditorRenderSidebar( current_graph_resource->m_virtual_socket_accessor->m_inputs = inputs; } if (ImGui::Button("X")) { - blend_tree_resource.RemoveConnectionsForSocket(node_resource, input); + blend_tree_resource->RemoveConnectionsForSocket(node_resource, input); iter = inputs.erase(iter); } else { iter++; @@ -355,13 +358,10 @@ void AnimGraphEditorRenderSidebar( } if (ImGui::Button("+")) { - AnimGraphResource* current_graph_resource = - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]; - current_graph_resource->RegisterBlendTreeInputSocket( + current_blend_tree_resource->RegisterBlendTreeInputSocket( "GraphFloatInput" - + std::to_string( - current_graph_resource->m_blend_tree_resource.GetGraphInputNode() - ->m_virtual_socket_accessor->m_outputs.size())); + + std::to_string(current_blend_tree_resource->GetGraphInputNode() + ->m_virtual_socket_accessor->m_outputs.size())); } } } @@ -439,12 +439,15 @@ void BlendTreeEditorNodePopup() { } if (!node_type_name.empty()) { + BlendTreeResource* current_blend_tree_resource = + dynamic_cast( + sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]); + AnimNodeResource* node_resource = AnimNodeResourceFactory(node_type_name); ax::NodeEditor::SetNodePosition( ax::NodeEditor::NodeId(node_resource), sEditorState.mousePopupStart); - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource.AddNode(node_resource); + current_blend_tree_resource->AddNode(node_resource); } ImGui::EndPopup(); @@ -559,7 +562,7 @@ void AnimGraphEditorBreadcrumbNavigation() { } } -void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { +void BlendTreeHandleConnectionCreation(BlendTreeResource* current_blend_tree) { if (ax::NodeEditor::BeginCreate()) { ax::NodeEditor::PinId input_pin_id, output_pin_id; if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) { @@ -603,14 +606,14 @@ void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { &source_node_index, &source_node_socket_index); - source_node = current_blend_tree.GetNode(source_node_index); + source_node = current_blend_tree->GetNode(source_node_index); if (source_node != nullptr) { if (source_node->m_virtual_socket_accessor->m_outputs.size() < source_node_socket_index) { source_node_socket_index = -1; } else { - source_socket = current_blend_tree.GetNodeOutputSocketByIndex( + source_socket = current_blend_tree->GetNodeOutputSocketByIndex( source_node, source_node_socket_index); } @@ -628,14 +631,14 @@ void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { &target_node_index, &target_node_socket_index); - target_node = current_blend_tree.GetNode(target_node_index); + target_node = current_blend_tree->GetNode(target_node_index); if (target_node != nullptr) { if (target_node->m_virtual_socket_accessor->m_inputs.size() < target_node_socket_index) { target_node_socket_index = -1; } else { - target_socket = current_blend_tree.GetNodeInputSocketByIndex( + target_socket = current_blend_tree->GetNodeInputSocketByIndex( target_node, target_node_socket_index); } @@ -658,14 +661,14 @@ void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { if (!source_pin.Invalid && !target_pin.Invalid) { if (source_socket == nullptr || target_socket == nullptr - || !current_blend_tree.IsConnectionValid( + || !current_blend_tree->IsConnectionValid( source_node, source_socket->m_name, target_node, target_socket->m_name)) { ax::NodeEditor::RejectNewItem(); } else if (ax::NodeEditor::AcceptNewItem()) { - current_blend_tree.ConnectSockets( + current_blend_tree->ConnectSockets( source_node, source_socket->m_name, target_node, @@ -678,12 +681,12 @@ void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { } void BlendTreeRenderNodes( - BlendTreeResource& current_blend_tree, + BlendTreeResource* current_blend_tree, ax::NodeEditor::Utilities::BlueprintNodeBuilder& builder) { - for (size_t node_index = 0, n = current_blend_tree.GetNumNodes(); + for (size_t node_index = 0, n = current_blend_tree->GetNumNodes(); node_index < n; node_index++) { - AnimNodeResource* node_resource = current_blend_tree.GetNode(node_index); + AnimNodeResource* node_resource = current_blend_tree->GetNode(node_index); ax::NodeEditor::NodeId node_id(node_resource); @@ -706,7 +709,7 @@ void BlendTreeRenderNodes( // Inputs std::vector node_inputs = - current_blend_tree.GetNodeInputSockets(node_resource); + current_blend_tree->GetNodeInputSockets(node_resource); for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) { Socket& socket = node_inputs[j]; ax::NodeEditor::PinId input_pin = NodeIndexAndSocketIndexToInputPinId( @@ -718,7 +721,7 @@ void BlendTreeRenderNodes( DrawSocketIcon( socket.m_type, - current_blend_tree.IsSocketConnected(node_resource, socket.m_name)); + current_blend_tree->IsSocketConnected(node_resource, socket.m_name)); ImGui::Spring(0); //ImGui::PushItemWidth(100.0f); @@ -729,7 +732,7 @@ void BlendTreeRenderNodes( // Outputs std::vector node_outputs = - current_blend_tree.GetNodeOutputSockets(node_resource); + current_blend_tree->GetNodeOutputSockets(node_resource); for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) { Socket& socket = node_outputs[j]; builder.Output(NodeIndexAndSocketIndexToOutputPinId( @@ -741,7 +744,7 @@ void BlendTreeRenderNodes( ImGui::Spring(0); DrawSocketIcon( socket.m_type, - current_blend_tree.IsSocketConnected(node_resource, socket.m_name)); + current_blend_tree->IsSocketConnected(node_resource, socket.m_name)); builder.EndOutput(); } @@ -754,21 +757,21 @@ void BlendTreeRenderNodes( } } -void BlendTreeRenderConnections(BlendTreeResource& current_blend_tree) { - for (size_t connection_id = 0, n = current_blend_tree.GetNumConnections(); +void BlendTreeRenderConnections(BlendTreeResource* current_blend_tree) { + for (size_t connection_id = 0, n = current_blend_tree->GetNumConnections(); connection_id < n; connection_id++) { const BlendTreeConnectionResource* connection_resource = - current_blend_tree.GetConnection(connection_id); + current_blend_tree->GetConnection(connection_id); const AnimNodeResource* source_node_resource = - current_blend_tree.GetNode(connection_resource->source_node_index); + current_blend_tree->GetNode(connection_resource->source_node_index); int source_socket_index = source_node_resource->m_virtual_socket_accessor->GetOutputIndex( connection_resource->source_socket_name.c_str()); const AnimNodeResource* target_node_resource = - current_blend_tree.GetNode(connection_resource->target_node_index); + current_blend_tree->GetNode(connection_resource->target_node_index); int target_socket_index = target_node_resource->m_virtual_socket_accessor->GetInputIndex( connection_resource->target_socket_name.c_str()); @@ -786,7 +789,8 @@ void BlendTreeRenderConnections(BlendTreeResource& current_blend_tree) { target_socket_pin_id); } } -void AnimGraphEditorDebugWidget() { + +void BlendTreeEditorDebugWidget() { ImGui::Begin("Connection Debug Panel"); ImGui::BeginTable("Connection", 3); ImGui::TableNextRow(); @@ -882,17 +886,19 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { graph_size.y -= 20; ax::NodeEditor::Begin("Graph Editor", graph_size); - AnimGraphResource* current_graph = - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]; - BlendTreeResource& current_blend_tree = current_graph->m_blend_tree_resource; + BlendTreeResource* current_blend_tree_resource = + dynamic_cast( + sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]); - ax::NodeEditor::Utilities::BlueprintNodeBuilder builder; + if (current_blend_tree_resource) { + ax::NodeEditor::Utilities::BlueprintNodeBuilder builder; - BlendTreeRenderNodes(current_blend_tree, builder); - BlendTreeRenderConnections(current_blend_tree); + BlendTreeRenderNodes(current_blend_tree_resource, builder); + BlendTreeRenderConnections(current_blend_tree_resource); + BlendTreeHandleConnectionCreation(current_blend_tree_resource); - HandleConnectionCreation(current_blend_tree); - BlendTreeEditorNodePopup(); + BlendTreeEditorNodePopup(); + } ax::NodeEditor::End(); @@ -903,22 +909,22 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { // ImGui::TableSetColumnIndex(1); - if (ax::NodeEditor::GetSelectedObjectCount() > 0) { + if (current_blend_tree_resource + && ax::NodeEditor::GetSelectedObjectCount() > 0) { ax::NodeEditor::NodeId selected_node_id = 0; ax::NodeEditor::GetSelectedNodes(&selected_node_id, 1); if (selected_node_id.Get() != 0) { - AnimGraphEditorRenderSidebar( - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource, + BlendTreeEditorRenderSidebar( + current_blend_tree_resource, selected_node_id.AsPointer()); } } ImGui::EndTable(); - AnimGraphEditorDebugWidget(); + BlendTreeEditorDebugWidget(); // Clear flag, however it may be re-set further down when handling double // clicking into subgraphs. @@ -962,15 +968,14 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { BlendTreeConnectionResource* connection_resource = hovered_link.AsPointer(); - if (connection_resource && ImGui::IsKeyPressed(ImGuiKey_Delete)) { - BlendTreeResource* blend_tree_resource = - &sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource; - - blend_tree_resource->DisconnectSockets( - blend_tree_resource->GetNode(connection_resource->source_node_index), + if (connection_resource && current_blend_tree_resource + && ImGui::IsKeyPressed(ImGuiKey_Delete)) { + current_blend_tree_resource->DisconnectSockets( + current_blend_tree_resource->GetNode( + connection_resource->source_node_index), connection_resource->source_socket_name, - blend_tree_resource->GetNode(connection_resource->target_node_index), + current_blend_tree_resource->GetNode( + connection_resource->target_node_index), connection_resource->target_socket_name); ax::NodeEditor::DeleteLink(hovered_link); @@ -982,19 +987,20 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { AnimNodeResource* node_resource = hovered_node.AsPointer(); - if (node_resource && ImGui::IsKeyPressed(ImGuiKey_Delete)) { - AnimGraphResource* current_graph_resource = - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]; - - current_graph_resource->m_blend_tree_resource.RemoveNodeConnections( - node_resource); - current_graph_resource->m_blend_tree_resource.RemoveNode(node_resource); + if (node_resource && current_blend_tree_resource + && ImGui::IsKeyPressed(ImGuiKey_Delete)) { + current_blend_tree_resource->RemoveNodeConnections(node_resource); + current_blend_tree_resource->RemoveNode(node_resource); } } ax::NodeEditor::SetCurrentEditor(nullptr); } -void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& blend_tree) { - sEditorState.rootGraphResource->CreateBlendTreeInstance(blend_tree); +void AnimGraphEditorGetRuntimeBlendTree(AnimGraphBlendTree& blend_tree) { + BlendTreeResource* root_blend_tree_resource = + dynamic_cast(sEditorState.rootGraphResource); + assert(root_blend_tree_resource); + + root_blend_tree_resource->CreateBlendTreeInstance(blend_tree); } \ No newline at end of file diff --git a/src/AnimGraphEditor/AnimGraphEditor.h b/src/AnimGraphEditor/AnimGraphEditor.h index 11e29c2..8b01f11 100644 --- a/src/AnimGraphEditor/AnimGraphEditor.h +++ b/src/AnimGraphEditor/AnimGraphEditor.h @@ -83,6 +83,6 @@ void AnimGraphEditorClear(); void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context); -void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& anim_graph); +void AnimGraphEditorGetRuntimeBlendTree(AnimGraphBlendTree& anim_graph); #endif //ANIMTESTBED_ANIMGRAPHEDITOR_H diff --git a/src/main.cc b/src/main.cc index 59735fe..5f804d8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -745,7 +745,7 @@ int main() { if (ImGui::Button("Update Runtime Graph")) { anim_graph.dealloc(); - AnimGraphEditorGetRuntimeGraph(anim_graph); + AnimGraphEditorGetRuntimeBlendTree(anim_graph); anim_graph_context.m_skeleton = &skinned_mesh.m_skeleton; anim_graph.Init(anim_graph_context); diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 524de65..b77ffa9 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -11,22 +11,26 @@ #include "ozz/base/io/stream.h" #include "ozz/base/log.h" -class SimpleAnimSamplerGraphResource { - protected: - AnimGraphResource graph_resource; +class BlendTreeResourceFixture { + public: + BlendTreeResourceFixture() { + blend_tree_resource = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + } + + virtual ~BlendTreeResourceFixture() { delete blend_tree_resource; } + BlendTreeResource* blend_tree_resource = nullptr; +}; + +class SimpleAnimSamplerBlendTreeResourceFixture + : public BlendTreeResourceFixture { + protected: size_t walk_node_index = -1; AnimNodeResource* walk_node = nullptr; public: - SimpleAnimSamplerGraphResource() - : graph_resource(AnimGraphType::GraphTypeBlendTree) { - graph_resource.m_name = "AnimSamplerBlendTree"; - graph_resource.m_node_type_name = "BlendTree"; - graph_resource.m_graph_type_name = "BlendTree"; - - blend_tree_resource = &graph_resource.m_blend_tree_resource; - + SimpleAnimSamplerBlendTreeResourceFixture() { // Prepare graph inputs and outputs walk_node_index = blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler")); @@ -49,10 +53,8 @@ class SimpleAnimSamplerGraphResource { } }; -class Blend2GraphResource { +class Blend2BlendTreeResource : public BlendTreeResourceFixture { protected: - AnimGraphResourcePtr graph_resource; - BlendTreeResource* blend_tree_resource = nullptr; size_t walk_node_index = -1; size_t run_node_index = -1; size_t blend_node_index = -1; @@ -61,13 +63,8 @@ class Blend2GraphResource { AnimNodeResource* blend_node = nullptr; public: - Blend2GraphResource() - : graph_resource( - dynamic_cast( - AnimNodeResourceFactory("BlendTree"))) { - graph_resource->m_name = "WalkRunBlendGraph"; - - blend_tree_resource = &graph_resource->m_blend_tree_resource; + Blend2BlendTreeResource() { + blend_tree_resource->m_name = "WalkRunBlendGraph"; // Prepare graph inputs and outputs walk_node_index = @@ -129,12 +126,8 @@ class Blend2GraphResource { // | | // +----------------------------------------+ // -class EmbeddedBlendTreeGraphResource { +class EmbeddedBlendTreeGraphResource : public BlendTreeResourceFixture { protected: - AnimGraphResource parent_graph_resource; - BlendTreeResource* parent_blend_tree_resource = nullptr; - - AnimGraphResource* embedded_graph = nullptr; BlendTreeResource* embedded_blend_tree_resource = nullptr; size_t walk_node_index = -1; @@ -143,19 +136,14 @@ class EmbeddedBlendTreeGraphResource { size_t embedded_speed_scale_index = -1; public: - EmbeddedBlendTreeGraphResource() - : parent_graph_resource(AnimGraphType::GraphTypeBlendTree) { - parent_graph_resource.m_name = "ParentBlendTree"; - parent_graph_resource.m_graph_type_name = "BlendTree"; - parent_graph_resource.m_node_type_name = "BlendTree"; - - parent_blend_tree_resource = &parent_graph_resource.m_blend_tree_resource; + EmbeddedBlendTreeGraphResource() { + blend_tree_resource->m_name = "ParentBlendTree"; // Parent AnimSampler - walk_node_index = parent_blend_tree_resource->AddNode( - AnimNodeResourceFactory("AnimSampler")); + walk_node_index = + blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler")); - walk_node_resource = parent_blend_tree_resource->GetNode(walk_node_index); + walk_node_resource = blend_tree_resource->GetNode(walk_node_index); walk_node_resource->m_name = "WalkAnim"; walk_node_resource->m_virtual_socket_accessor->SetPropertyValue( "Filename", @@ -164,14 +152,11 @@ class EmbeddedBlendTreeGraphResource { // // Embedded Tree // - embedded_blend_tree_node_index = parent_blend_tree_resource->AddNode( - AnimNodeResourceFactory("BlendTree")); - embedded_graph = dynamic_cast( - parent_blend_tree_resource->GetNode(embedded_blend_tree_node_index)); - embedded_graph->m_name = "EmbeddedBlendTree"; - embedded_graph->m_node_type_name = "BlendTree"; - embedded_graph->m_graph_type_name = "BlendTree"; - embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource; + embedded_blend_tree_node_index = + blend_tree_resource->AddNode(AnimNodeResourceFactory("BlendTree")); + embedded_blend_tree_resource = dynamic_cast( + blend_tree_resource->GetNode(embedded_blend_tree_node_index)); + embedded_blend_tree_resource->m_name = "EmbeddedBlendTree"; // Embedded: outputs AnimNodeResource* embedded_outputs = @@ -210,15 +195,15 @@ class EmbeddedBlendTreeGraphResource { // Parent: setup connections const AnimNodeResource* parent_blend_tree_outputs = - parent_blend_tree_resource->GetGraphOutputNode(); + blend_tree_resource->GetGraphOutputNode(); - REQUIRE(parent_blend_tree_resource->ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( walk_node_resource, "Output", - embedded_graph, + embedded_blend_tree_resource, "AnimInput")); - REQUIRE(parent_blend_tree_resource->ConnectSockets( - embedded_graph, + REQUIRE(blend_tree_resource->ConnectSockets( + embedded_blend_tree_resource, "AnimOutput", parent_blend_tree_outputs, "Output")); @@ -238,12 +223,8 @@ class EmbeddedBlendTreeGraphResource { // | | // +----------------------------------------+ // -class EmbeddedTreeBlend2GraphResource { +class EmbeddedTreeBlend2GraphResource : public BlendTreeResourceFixture { protected: - AnimGraphResource parent_graph_resource; - BlendTreeResource* parent_blend_tree_resource = nullptr; - - AnimGraphResource* embedded_graph = nullptr; BlendTreeResource* embedded_blend_tree_resource = nullptr; size_t walk_node_index = -1; @@ -256,26 +237,21 @@ class EmbeddedTreeBlend2GraphResource { AnimNodeResource* embedded_run_node_resource = nullptr; public: - EmbeddedTreeBlend2GraphResource() - : parent_graph_resource(AnimGraphType::GraphTypeBlendTree) { - parent_graph_resource.m_name = "ParentBlendTree"; - parent_graph_resource.m_graph_type_name = "BlendTree"; - parent_graph_resource.m_node_type_name = "BlendTree"; - - parent_blend_tree_resource = &parent_graph_resource.m_blend_tree_resource; + EmbeddedTreeBlend2GraphResource() { + blend_tree_resource->m_name = "ParentBlendTree"; // Setup parent inputs AnimNodeResource* parent_blend_tree_inputs = - parent_blend_tree_resource->GetGraphInputNode(); + blend_tree_resource->GetGraphInputNode(); parent_blend_tree_inputs->m_virtual_socket_accessor->RegisterOutput( "EmbeddedBlend2Weight", nullptr); // Parent AnimSampler - walk_node_index = parent_blend_tree_resource->AddNode( - AnimNodeResourceFactory("AnimSampler")); + walk_node_index = + blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler")); - walk_node_resource = parent_blend_tree_resource->GetNode(walk_node_index); + walk_node_resource = blend_tree_resource->GetNode(walk_node_index); walk_node_resource->m_name = "WalkAnim"; walk_node_resource->m_virtual_socket_accessor->SetPropertyValue( "Filename", @@ -284,18 +260,17 @@ class EmbeddedTreeBlend2GraphResource { // // Embedded Tree // - embedded_blend_tree_node_index = parent_blend_tree_resource->AddNode( - AnimNodeResourceFactory("BlendTree")); - embedded_graph = dynamic_cast( - parent_blend_tree_resource->GetNode(embedded_blend_tree_node_index)); - embedded_graph->m_name = "EmbeddedTreeBlend2GraphResource"; - embedded_graph->m_node_type_name = "BlendTree"; - embedded_graph->m_graph_type_name = "BlendTree"; - embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource; + embedded_blend_tree_node_index = + blend_tree_resource->AddNode(AnimNodeResourceFactory("BlendTree")); + embedded_blend_tree_resource = dynamic_cast( + blend_tree_resource->GetNode(embedded_blend_tree_node_index)); + embedded_blend_tree_resource->m_name = "EmbeddedTreeBlend2GraphResource"; // Embedded: inputs - embedded_graph->RegisterBlendTreeInputSocket("AnimInput"); - embedded_graph->RegisterBlendTreeInputSocket("BlendWeight"); + embedded_blend_tree_resource->RegisterBlendTreeInputSocket( + "AnimInput"); + embedded_blend_tree_resource->RegisterBlendTreeInputSocket( + "BlendWeight"); // Embedded nodes embedded_blend2_node_index = embedded_blend_tree_resource->AddNode( @@ -342,22 +317,22 @@ class EmbeddedTreeBlend2GraphResource { // Parent: setup connections AnimNodeResource* parent_blend_tree_outputs = - parent_blend_tree_resource->GetGraphOutputNode(); + blend_tree_resource->GetGraphOutputNode(); - REQUIRE(parent_blend_tree_resource->ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( walk_node_resource, "Output", - embedded_graph, + embedded_blend_tree_resource, "AnimInput")); - REQUIRE(parent_blend_tree_resource->ConnectSockets( - embedded_graph, + REQUIRE(blend_tree_resource->ConnectSockets( + embedded_blend_tree_resource, AnimGraphResource::DefaultAnimOutput, parent_blend_tree_outputs, AnimGraphResource::DefaultAnimOutput)); - REQUIRE(parent_blend_tree_resource->ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( parent_blend_tree_inputs, "EmbeddedBlend2Weight", - embedded_graph, + embedded_blend_tree_resource, "BlendWeight")); } }; @@ -386,6 +361,14 @@ bool load_skeleton(ozz::animation::Skeleton& skeleton, const char* filename) { void CheckBlendTreeResourcesEqual( const BlendTreeResource* blend_tree_resource_reference, const BlendTreeResource* blend_tree_resource_rhs) { + REQUIRE( + blend_tree_resource_reference->m_node_type_name + == blend_tree_resource_rhs->m_node_type_name); + REQUIRE(blend_tree_resource_reference->m_node_type_name == "BlendTree"); + + REQUIRE( + blend_tree_resource_reference->m_name == blend_tree_resource_rhs->m_name); + REQUIRE( blend_tree_resource_reference->GetNumNodes() == blend_tree_resource_rhs->GetNumNodes()); @@ -420,27 +403,6 @@ void CheckBlendTreeResourcesEqual( } } -void CheckAnimGraphResourceEqual( - const AnimGraphResource& graph_resource_reference, - const AnimGraphResource& graph_resource_rhs) { - REQUIRE( - graph_resource_reference.m_graph_type_name - == graph_resource_rhs.m_graph_type_name); - REQUIRE(graph_resource_reference.m_name == graph_resource_rhs.m_name); - - REQUIRE(graph_resource_reference.m_graph_type_name == "BlendTree"); - - const BlendTreeResource* blend_tree_resource_reference = - &graph_resource_reference.m_blend_tree_resource; - - const BlendTreeResource* blend_tree_resource_rhs = - &graph_resource_rhs.m_blend_tree_resource; - - CheckBlendTreeResourcesEqual( - blend_tree_resource_reference, - blend_tree_resource_rhs); -} - TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") { int node_id = 3321; int input_index = 221; @@ -461,24 +423,26 @@ TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") { } TEST_CASE_METHOD( - SimpleAnimSamplerGraphResource, + SimpleAnimSamplerBlendTreeResourceFixture, "SimpleAnimSamplerGraphResource saving and loading results in same " "resource", "[SimpleAnimSamplerGraphResource]") { - graph_resource.SaveToFile("TestGraphAnimSamplerBlendTree.json"); + blend_tree_resource->SaveToFile("TestGraphAnimSamplerBlendTree.json"); - std::unique_ptr graph_resource_loaded( - AnimGraphResource::CreateFromFile("TestGraphAnimSamplerBlendTree.json")); + std::unique_ptr blend_tree_resource_loaded( + BlendTreeResource::CreateFromFile("TestGraphAnimSamplerBlendTree.json")); - CheckAnimGraphResourceEqual(graph_resource, *graph_resource_loaded); + CheckBlendTreeResourcesEqual( + blend_tree_resource, + blend_tree_resource_loaded.get()); } TEST_CASE_METHOD( - SimpleAnimSamplerGraphResource, + SimpleAnimSamplerBlendTreeResourceFixture, "SimpleAnimSamplerGraphResource emulated evaluation", "[SimpleAnimSamplerGraphResource]") { AnimGraphBlendTree anim_graph_blend_tree; - graph_resource.CreateBlendTreeInstance(anim_graph_blend_tree); + blend_tree_resource->CreateBlendTreeInstance(anim_graph_blend_tree); AnimGraphContext graph_context; ozz::animation::Skeleton skeleton; @@ -537,29 +501,25 @@ TEST_CASE_METHOD( // Checks that node const inputs are properly set. // TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") { - AnimGraphResourcePtr graph_resource( - dynamic_cast(AnimNodeResourceFactory("BlendTree"))); - graph_resource->m_name = "AnimSamplerSpeedScaleGraph"; - graph_resource->m_graph_type_name = "BlendTree"; - - BlendTreeResource& blend_tree_resource = - graph_resource->m_blend_tree_resource; + BlendTreeResource* blend_tree_resource = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + blend_tree_resource->m_name = "AnimSamplerSpeedScaleBlendTree"; // Prepare graph inputs and outputs size_t walk_node_index = - blend_tree_resource.AddNode(AnimNodeResourceFactory("AnimSampler")); + blend_tree_resource->AddNode(AnimNodeResourceFactory("AnimSampler")); size_t speed_scale_node_index = - blend_tree_resource.AddNode(AnimNodeResourceFactory("SpeedScale")); + blend_tree_resource->AddNode(AnimNodeResourceFactory("SpeedScale")); - AnimNodeResource* walk_node = blend_tree_resource.GetNode(walk_node_index); + AnimNodeResource* walk_node = blend_tree_resource->GetNode(walk_node_index); walk_node->m_name = "WalkAnim"; walk_node->m_virtual_socket_accessor->SetPropertyValue( "Filename", std::string("media/Walking-loop.ozz")); AnimNodeResource* speed_scale_node = - blend_tree_resource.GetNode(speed_scale_node_index); + blend_tree_resource->GetNode(speed_scale_node_index); speed_scale_node->m_name = "SpeedScale"; float speed_scale_value = 1.35f; speed_scale_node->m_virtual_socket_accessor->SetInputValue( @@ -567,25 +527,23 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") { speed_scale_value); blend_tree_resource - .ConnectSockets(walk_node, "Output", speed_scale_node, "Input"); + ->ConnectSockets(walk_node, "Output", speed_scale_node, "Input"); - blend_tree_resource.ConnectSockets( + blend_tree_resource->ConnectSockets( speed_scale_node, "Output", - blend_tree_resource.GetGraphOutputNode(), + blend_tree_resource->GetGraphOutputNode(), AnimGraphResource::DefaultAnimOutput); - graph_resource->SaveToFile( - "TestGraphAnimSamplerSpeedScaleGraph.animgraph.json"); - AnimGraphResourcePtr graph_resource_loaded( - AnimGraphResource::CreateFromFile( - "TestGraphAnimSamplerSpeedScaleGraph.animgraph.json")); + constexpr char filename[] = + "TestGraphAnimSamplerSpeedScaleGraph.animgraph.json"; - BlendTreeResource& blend_tree_resource_loaded = - graph_resource_loaded->m_blend_tree_resource; + REQUIRE(blend_tree_resource->SaveToFile(filename)); + BlendTreeResource* blend_tree_resource_loaded = + BlendTreeResource::CreateFromFile(filename); Socket* speed_scale_resource_loaded_input = - blend_tree_resource_loaded.GetNode(speed_scale_node_index) + blend_tree_resource_loaded->GetNode(speed_scale_node_index) ->m_virtual_socket_accessor->GetInputSocket("SpeedScale"); REQUIRE(speed_scale_resource_loaded_input != nullptr); @@ -594,7 +552,7 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") { Catch::Matchers::WithinAbs(speed_scale_value, 0.1)); AnimGraphBlendTree blend_tree; - graph_resource_loaded->CreateBlendTreeInstance(blend_tree); + blend_tree_resource_loaded->CreateBlendTreeInstance(blend_tree); REQUIRE_THAT( *dynamic_cast(blend_tree.m_nodes[speed_scale_node_index]) @@ -603,7 +561,7 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") { WHEN("Checking node eval order and node subtrees") { const std::vector& eval_order = - graph_resource_loaded->m_blend_tree_resource.GetNodeEvalOrder(); + blend_tree_resource_loaded->GetNodeEvalOrder(); THEN("Walk node gets evaluated before speed scale node") { CHECK(eval_order.size() == 2); @@ -613,23 +571,26 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") { THEN("Subtree of the speed scale node contains only the walk node") { CHECK( - graph_resource_loaded->m_blend_tree_resource - .m_node_inputs_subtree[speed_scale_node_index] + blend_tree_resource_loaded + ->m_node_inputs_subtree[speed_scale_node_index] .size() == 1); CHECK( - graph_resource_loaded->m_blend_tree_resource - .m_node_inputs_subtree[speed_scale_node_index][0] + blend_tree_resource_loaded + ->m_node_inputs_subtree[speed_scale_node_index][0] == walk_node_index); } } + + delete blend_tree_resource_loaded; + delete blend_tree_resource; } // // Checks that connections additions and removals are properly validated. // TEST_CASE_METHOD( - Blend2GraphResource, + Blend2BlendTreeResource, "Connectivity Tests", "[AnimGraphResource][Blend2GraphResource]") { INFO("Removing Blend2 -> Output Connection") @@ -704,18 +665,16 @@ TEST_CASE("FreeAnimGraphResource", "[Test]") { } TEST_CASE_METHOD( - Blend2GraphResource, + Blend2BlendTreeResource, "Blend2GraphResource saving and loading results in same resource", "[Blend2GraphResource]") { - graph_resource->SaveToFile("TestGraphBlend2Graph.animgraph.json"); - - AnimGraphResourcePtr graph_resource_loaded( - AnimGraphResource::CreateFromFile("TestGraphBlend2Graph.animgraph.json")); - - CheckAnimGraphResourceEqual(*graph_resource, *graph_resource_loaded); + constexpr char filename[] = "TestGraphBlend2Graph.animgraph.json"; + REQUIRE(blend_tree_resource->SaveToFile(filename)); BlendTreeResource* blend_tree_resource_loaded = - &graph_resource_loaded->m_blend_tree_resource; + BlendTreeResource::CreateFromFile(filename); + + CheckBlendTreeResourcesEqual(blend_tree_resource, blend_tree_resource_loaded); // Check that the constant weight of the Blend2 node was properly applied when // loading the resource. @@ -729,14 +688,16 @@ TEST_CASE_METHOD( Catch::Matchers::WithinAbs( blend2_node_descriptor_loaded->GetInputValue("Weight"), 0.01)); + + delete blend_tree_resource_loaded; } TEST_CASE_METHOD( - Blend2GraphResource, + Blend2BlendTreeResource, "Blend2GraphResource graph unsynced evaluation", "[Blend2GraphResource]") { AnimGraphBlendTree blend_tree_graph; - graph_resource->CreateBlendTreeInstance(blend_tree_graph); + blend_tree_resource->CreateBlendTreeInstance(blend_tree_graph); AnimGraphContext graph_context; ozz::animation::Skeleton skeleton; @@ -835,19 +796,16 @@ TEST_CASE_METHOD( // // TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { - AnimGraphResource graph_resource_origin(AnimGraphType::GraphTypeBlendTree); - graph_resource_origin.m_name = "TestInputOutputGraph"; - graph_resource_origin.m_graph_type_name = "BlendTree"; - - BlendTreeResource& blend_tree_resource = - graph_resource_origin.m_blend_tree_resource; + BlendTreeResource* blend_tree_resource = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + blend_tree_resource->m_name = "TestInputOutputGraph"; // Prepare graph inputs and outputs - size_t float_to_vec3_node_index = blend_tree_resource.AddNode( + size_t float_to_vec3_node_index = blend_tree_resource->AddNode( AnimNodeResourceFactory("MathFloatToVec3Node")); AnimNodeResource* graph_output_node = - blend_tree_resource.GetGraphOutputNode(); + blend_tree_resource->GetGraphOutputNode(); graph_output_node->m_virtual_socket_accessor->RegisterInput( "GraphFloatOutput", nullptr); @@ -856,38 +814,38 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { nullptr); AnimNodeResource* graph_input_node_resource = - blend_tree_resource.GetGraphInputNode(); + blend_tree_resource->GetGraphInputNode(); graph_input_node_resource->m_virtual_socket_accessor->RegisterOutput( "GraphFloatInput", nullptr); // Prepare graph inputs and outputs AnimNodeResource* float_to_vec3_node_resource = - blend_tree_resource.GetNode(float_to_vec3_node_index); + blend_tree_resource->GetNode(float_to_vec3_node_index); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node_resource, "GraphFloatInput", graph_output_node, "GraphFloatOutput")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node_resource, "GraphFloatInput", float_to_vec3_node_resource, "Input0")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node_resource, "GraphFloatInput", float_to_vec3_node_resource, "Input1")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node_resource, "GraphFloatInput", float_to_vec3_node_resource, "Input2")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( float_to_vec3_node_resource, "Output", graph_output_node, @@ -895,18 +853,15 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { WHEN("Saving and loading graph resource") { const char* filename = "TestGraphResourceSaveLoadGraphInputs.json"; - graph_resource_origin.SaveToFile(filename); + REQUIRE(blend_tree_resource->SaveToFile(filename)); - AnimGraphResourcePtr graph_resource_loaded( - AnimGraphResource::CreateFromFile(filename)); - - BlendTreeResource& graph_blend_tree_loaded = - graph_resource_loaded->m_blend_tree_resource; + BlendTreeResource* blend_tree_resource_loaded = + BlendTreeResource::CreateFromFile(filename); const AnimNodeResource* graph_loaded_output_node = - graph_blend_tree_loaded.GetGraphOutputNode(); + blend_tree_resource_loaded->GetGraphOutputNode(); const AnimNodeResource* graph_loaded_input_node = - graph_blend_tree_loaded.GetGraphInputNode(); + blend_tree_resource_loaded->GetGraphInputNode(); THEN("Graph inputs and outputs must be in loaded resource as well.") { REQUIRE( @@ -935,7 +890,7 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { WHEN("Instantiating an AnimGraph") { AnimGraphBlendTree blend_tree_node; - graph_resource_loaded->CreateBlendTreeInstance(blend_tree_node); + blend_tree_resource_loaded->CreateBlendTreeInstance(blend_tree_node); float graph_float_input = 123.456f; blend_tree_node.SetInput("GraphFloatInput", &graph_float_input); @@ -975,7 +930,11 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { } } } + + delete blend_tree_resource_loaded; } + + delete blend_tree_resource; } // @@ -992,21 +951,18 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { // GraphFloat1Output -> GraphFLoatInputSingle * 3 // TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { - AnimGraphResource graph_resource_origin(AnimGraphType::GraphTypeBlendTree); - graph_resource_origin.m_name = "TestSimpleMathGraph"; - graph_resource_origin.m_graph_type_name = "BlendTree"; - - BlendTreeResource& blend_tree_resource = - graph_resource_origin.m_blend_tree_resource; + BlendTreeResource* blend_tree_resource = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); + blend_tree_resource->m_name = "TestSimpleMathGraph"; // Prepare graph inputs and outputs size_t math_add0_node_index = - blend_tree_resource.AddNode(AnimNodeResourceFactory("MathAddNode")); + blend_tree_resource->AddNode(AnimNodeResourceFactory("MathAddNode")); size_t math_add1_node_index = - blend_tree_resource.AddNode(AnimNodeResourceFactory("MathAddNode")); + blend_tree_resource->AddNode(AnimNodeResourceFactory("MathAddNode")); AnimNodeResource* graph_output_node = - blend_tree_resource.GetGraphOutputNode(); + blend_tree_resource->GetGraphOutputNode(); graph_output_node->m_virtual_socket_accessor->RegisterInput( "GraphFloat0Output", @@ -1018,57 +974,57 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { "GraphFloat2Output", nullptr); - AnimNodeResource* graph_input_node = blend_tree_resource.GetGraphInputNode(); + AnimNodeResource* graph_input_node = blend_tree_resource->GetGraphInputNode(); graph_input_node->m_virtual_socket_accessor->RegisterOutput( "GraphFloatInput", nullptr); // Prepare graph inputs and outputs AnimNodeResource* math_add0_node = - blend_tree_resource.GetNode(math_add0_node_index); + blend_tree_resource->GetNode(math_add0_node_index); AnimNodeResource* math_add1_node = - blend_tree_resource.GetNode(math_add1_node_index); + blend_tree_resource->GetNode(math_add1_node_index); // direct output - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node, "GraphFloatInput", graph_output_node, "GraphFloat0Output")); // add0 node - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node, "GraphFloatInput", math_add0_node, "Input0")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node, "GraphFloatInput", math_add0_node, "Input1")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( math_add0_node, "Output", graph_output_node, "GraphFloat1Output")); // add1 node - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( math_add0_node, "Output", math_add1_node, "Input0")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( graph_input_node, "GraphFloatInput", math_add1_node, "Input1")); - REQUIRE(blend_tree_resource.ConnectSockets( + REQUIRE(blend_tree_resource->ConnectSockets( math_add1_node, "Output", graph_output_node, @@ -1076,14 +1032,14 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { WHEN("Saving and loading graph resource") { const char* filename = "TestGraphResourceSaveLoadGraphInputs.json"; - graph_resource_origin.SaveToFile(filename); + REQUIRE(blend_tree_resource->SaveToFile(filename)); - AnimGraphResourcePtr graph_resource_loaded( - AnimGraphResource::CreateFromFile(filename)); + BlendTreeResource* blend_tree_resource_loaded = + BlendTreeResource::CreateFromFile(filename); WHEN("Instantiating an AnimGraph") { AnimGraphBlendTree blend_tree; - graph_resource_loaded->CreateBlendTreeInstance(blend_tree); + blend_tree_resource_loaded->CreateBlendTreeInstance(blend_tree); float graph_float_input = 123.456f; blend_tree.SetInput("GraphFloatInput", &graph_float_input); @@ -1117,7 +1073,11 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { context.freeAnimations(); } } + + delete blend_tree_resource_loaded; } + + delete blend_tree_resource; } // @@ -1137,33 +1097,28 @@ TEST_CASE_METHOD( "EmbeddedBlendTreeGraphResource saving and loading results in same " "resource", "[EmbeddedBlendTreeGraphResource]") { - parent_graph_resource.SaveToFile("TestGraphEmbeddedBlendTree.json"); + constexpr char filename[] = "TestGraphEmbeddedBlendTree.json"; + REQUIRE(blend_tree_resource->SaveToFile(filename)); - AnimGraphResourcePtr parent_graph_resource_loaded( - AnimGraphResource::CreateFromFile("TestGraphEmbeddedBlendTree.json")); + BlendTreeResource* blend_tree_resource_loaded = + BlendTreeResource::CreateFromFile(filename); // Check the loaded parent graph - CheckAnimGraphResourceEqual( - parent_graph_resource, - *parent_graph_resource_loaded); - - const BlendTreeResource& parent_blend_tree_resource_loaded = - parent_graph_resource_loaded->m_blend_tree_resource; + CheckBlendTreeResourcesEqual(blend_tree_resource, blend_tree_resource_loaded); // Check the loaded embedded graph REQUIRE( - parent_blend_tree_resource_loaded.GetNode(3)->m_node_type_name - == "BlendTree"); + blend_tree_resource_loaded->GetNode(3)->m_node_type_name == "BlendTree"); - const AnimGraphResource* embedded_graph_loaded = - dynamic_cast( - parent_blend_tree_resource_loaded.GetNode(3)); const BlendTreeResource* embedded_blend_tree_resource_loaded = - &embedded_graph_loaded->m_blend_tree_resource; + dynamic_cast( + blend_tree_resource_loaded->GetNode(3)); CheckBlendTreeResourcesEqual( embedded_blend_tree_resource, embedded_blend_tree_resource_loaded); + + delete blend_tree_resource_loaded; } TEST_CASE_METHOD( @@ -1172,7 +1127,7 @@ TEST_CASE_METHOD( "[EmbeddedBlendTreeGraphResource]") { AnimGraphBlendTree blend_tree; - parent_graph_resource.CreateBlendTreeInstance(blend_tree); + blend_tree_resource->CreateBlendTreeInstance(blend_tree); AnimGraphContext graph_context; ozz::animation::Skeleton skeleton; @@ -1249,7 +1204,7 @@ TEST_CASE_METHOD( "[EmbeddedTreeBlend2GraphResource]") { AnimGraphBlendTree blend_tree; - parent_graph_resource.CreateBlendTreeInstance(blend_tree); + blend_tree_resource->CreateBlendTreeInstance(blend_tree); AnimGraphContext graph_context; ozz::animation::Skeleton skeleton; @@ -1332,21 +1287,19 @@ TEST_CASE_METHOD( TEST_CASE( "Register AnimGraphResource Blendtree Sockets", "[AnimGraphResource]") { - AnimNodeResource* blend_tree_anim_node_resource = - AnimNodeResourceFactory("BlendTree"); - AnimGraphResource* blend_tree_graph_resource = - dynamic_cast(blend_tree_anim_node_resource); + BlendTreeResource* blend_tree_resource = + dynamic_cast(AnimNodeResourceFactory("BlendTree")); Socket socket; socket.m_name = "FloatSocket"; socket.m_type = SocketType::SocketTypeFloat; socket.m_reference.ptr = nullptr; - CHECK(blend_tree_graph_resource->RegisterBlendTreeInputSocket(socket)); - CHECK(!blend_tree_graph_resource->RegisterBlendTreeInputSocket(socket)); + CHECK(blend_tree_resource->RegisterBlendTreeInputSocket(socket)); + CHECK(!blend_tree_resource->RegisterBlendTreeInputSocket(socket)); - CHECK(blend_tree_graph_resource->RegisterBlendTreeOutputSocket(socket)); - CHECK(!blend_tree_graph_resource->RegisterBlendTreeOutputSocket(socket)); + CHECK(blend_tree_resource->RegisterBlendTreeOutputSocket(socket)); + CHECK(!blend_tree_resource->RegisterBlendTreeOutputSocket(socket)); - delete blend_tree_anim_node_resource; + delete blend_tree_resource; }