// // Created by martin on 17.03.24. // #ifndef ANIMTESTBED_ANIMGRAPHRESOURCE_H #define ANIMTESTBED_ANIMGRAPHRESOURCE_H #include "3rdparty/json/json.hpp" #include "AnimGraphNodes.h" struct AnimGraphBlendTree; struct AnimGraphStateMachine; struct AnimNodeResource { virtual ~AnimNodeResource() = default; std::string m_name; std::string m_node_type_name; AnimNode* m_anim_node = nullptr; NodeDescriptorBase* m_socket_accessor = nullptr; float m_position[2] = {0.f, 0.f}; }; static inline AnimNodeResource* AnimNodeResourceFactory( const std::string& node_type_name); struct BlendTreeConnectionResource { size_t source_node_index = -1; std::string source_socket_name; size_t target_node_index = -1; std::string target_socket_name; }; struct BlendTreeResource { std::vector m_nodes; std::vector m_connections; ~BlendTreeResource() { CleanupNodes(); } void Reset() { CleanupNodes(); m_connections.clear(); } void CleanupNodes() { for (AnimNodeResource* node_resource : m_nodes) { delete node_resource->m_anim_node; delete node_resource->m_socket_accessor; delete node_resource; } m_nodes.clear(); } void InitGraphConnectors() { m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets")); m_nodes[0]->m_name = "Outputs"; m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets")); m_nodes[1]->m_name = "Inputs"; } [[nodiscard]] AnimNodeResource* GetGraphOutputNode() const { return m_nodes[0]; } [[nodiscard]] AnimNodeResource* GetGraphInputNode() const { return m_nodes[1]; } size_t GetNodeIndex(const AnimNodeResource* node_resource) const { for (size_t i = 0, n = m_nodes.size(); i < n; i++) { if (m_nodes[i] == node_resource) { return i; } } return -1; } bool ConnectSockets( const AnimNodeResource* source_node, const std::string& source_socket_name, const AnimNodeResource* target_node, const std::string& target_socket_name); std::vector GetConstantNodeInputs( std::vector& instance_node_descriptors) const { std::vector result; for (size_t i = 0; i < m_nodes.size(); i++) { for (size_t j = 0, num_inputs = instance_node_descriptors[i]->m_inputs.size(); j < num_inputs; j++) { Socket& input = instance_node_descriptors[i]->m_inputs[j]; if (*input.m_reference.ptr_ptr == nullptr) { memcpy( &input.m_value, &m_nodes[i]->m_socket_accessor->m_inputs[j].m_value, sizeof(Socket::SocketValue)); result.push_back(&input); } } } return result; } size_t GetNodeIndexForOutputSocket(const std::string& socket_name) const { for (size_t i = 0; i < m_connections.size(); i++) { const BlendTreeConnectionResource& connection = m_connections[i]; if (connection.target_node_index == 0 && connection.target_socket_name == socket_name) { return connection.source_node_index; } } std::cerr << "Error: could not find a node connected to output '" << socket_name << "'." << std::endl; return -1; } size_t GetNodeIndexForInputSocket(const std::string& socket_name) const { for (size_t i = 0; i < m_connections.size(); i++) { const BlendTreeConnectionResource& connection = m_connections[i]; if (connection.source_node_index == 1 && connection.source_socket_name == socket_name) { return connection.target_node_index; } } std::cerr << "Error: could not find a node connected to input '" << socket_name << "'." << std::endl; return -1; } }; 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 { std::string m_graph_type_name; BlendTreeResource m_blend_tree_resource; StateMachineResource m_state_machine_resource; bool SaveToFile(const char* filename) const; bool LoadFromFile(const char* filename); void CreateBlendTreeInstance(AnimGraphBlendTree& result) const; void CreateStateMachineInstance(AnimGraphStateMachine& result) const; private: // BlendTree bool SaveBlendTreeResourceToFile(const char* filename) const; void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const; void PrepareBlendTreeIOData(AnimGraphBlendTree& instance) const; void CreateBlendTreeConnectionInstances(AnimGraphBlendTree& instance) const; void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const; bool SaveStateMachineResourceToFile(const char* filename) const; bool LoadStateMachineResourceFromJson(nlohmann::json const& json_data); }; static inline AnimNodeResource* AnimNodeResourceFactory( const std::string& node_type_name) { AnimNodeResource* result; if (node_type_name == "BlendTree") { AnimGraphResource* blend_tree_resource = new AnimGraphResource(); blend_tree_resource->m_blend_tree_resource.InitGraphConnectors(); result = blend_tree_resource; } else { result = new AnimNodeResource(); } result->m_node_type_name = node_type_name; if (node_type_name == "BlendTreeSockets") { result->m_anim_node = AnimNodeFactory("BlendTree"); result->m_socket_accessor = new NodeDescriptorBase(); } else { result->m_anim_node = AnimNodeFactory(node_type_name); result->m_socket_accessor = AnimNodeDescriptorFactory(node_type_name, result->m_anim_node); } return result; } #endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H