// // Created by martin on 04.02.22. // #include "AnimGraphResource.h" #include #include "3rdparty/json/json.hpp" using json = nlohmann::json; // // Socket <-> json // std::string sSocketTypeToStr(SocketType pin_type) { std::string result = "unknown"; switch (pin_type) { case SocketType::SocketTypeBool: result = "Bool"; break; case SocketType::SocketTypeAnimation: result = "Animation"; break; case SocketType::SocketTypeFloat: result = "Float"; break; case SocketType::SocketTypeVec3: result = "Vec3"; break; case SocketType::SocketTypeQuat: result = "Quat"; break; case SocketType::SocketTypeString: result = "String"; break; default: result = "Unknown"; } return result; } json sSocketToJson(const Socket& socket) { json result; result["name"] = socket.m_name; result["type"] = sSocketTypeToStr(socket.m_type); return result; } Socket sJsonToSocket(const json& json_data) { Socket result; result.m_type = SocketType::SocketTypeUndefined; result.m_value.ptr = nullptr; result.m_name = json_data["name"]; std::string type_string = json_data["type"]; if (type_string == "Bool") { result.m_type = SocketType::SocketTypeBool; result.m_type_size = sizeof(bool); } else if (type_string == "Animation") { result.m_type = SocketType::SocketTypeAnimation; result.m_type_size = sizeof(AnimData); } else if (type_string == "Float") { result.m_type = SocketType::SocketTypeFloat; result.m_type_size = sizeof(float); } else if (type_string == "Vec3") { result.m_type = SocketType::SocketTypeVec3; result.m_type_size = sizeof(Vec3); } else if (type_string == "Quat") { result.m_type = SocketType::SocketTypeQuat; result.m_type_size = sizeof(Quat); } else if (type_string == "String") { result.m_type = SocketType::SocketTypeString; result.m_type_size = sizeof(std::string); } else { std::cerr << "Invalid socket type '" << type_string << "'." << std::endl; } return result; } // // AnimGraphNode <-> json // json sAnimGraphNodeToJson(const AnimNodeResource& node) { json result; result["name"] = node.m_name; result["type"] = "AnimNodeResource"; result["node_type"] = node.m_type_name; for (size_t j = 0; j < 2; j++) { result["position"][j] = node.m_position[j]; } return result; } AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) { AnimNodeResource result; result.m_name = json_node["name"]; result.m_type_name = json_node["node_type"]; result.m_position[0] = json_node["position"][0]; result.m_position[1] = json_node["position"][1]; result.m_anim_node = AnimNodeFactory(result.m_type_name); result.m_socket_accessor = AnimNodeAccessorFactory(result.m_type_name, result.m_anim_node); return result; } // // AnimGraphConnection <-> Json // json sAnimGraphConnectionToJson(const AnimGraphConnection& connection) { json result; result["type"] = "AnimGraphConnection"; result["source_node_index"] = connection.m_source_node_index; result["source_socket_index"] = connection.m_source_socket_index; result["target_node_index"] = connection.m_target_node_index; result["target_socket_index"] = connection.m_target_socket_index; return result; } AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) { AnimGraphConnection connection; connection.m_source_node_index = json_node["source_node_index"]; connection.m_source_socket_index = json_node["source_socket_index"]; connection.m_target_node_index = json_node["target_node_index"]; connection.m_target_socket_index = json_node["target_socket_index"]; return connection; } void AnimGraphResource::clear() { m_name = ""; for (size_t i = 0; i < m_nodes.size(); i++) { delete m_nodes[i].m_socket_accessor; m_nodes[i].m_socket_accessor = nullptr; delete m_nodes[i].m_anim_node; m_nodes[i].m_anim_node = nullptr; } m_nodes.clear(); m_nodes.push_back(AnimNodeResourceFactory("BlendTree")); m_nodes[0].m_name = "Outputs"; m_nodes.push_back(AnimNodeResourceFactory("BlendTree")); m_nodes[1].m_name = "Inputs"; m_connections.clear(); } bool AnimGraphResource::saveToFile(const char* filename) const { json result; result["name"] = m_name; result["type"] = "AnimGraphResource"; for (size_t i = 0; i < m_nodes.size(); i++) { const AnimNodeResource& node = m_nodes[i]; result["nodes"][i] = sAnimGraphNodeToJson(node); } for (size_t i = 0; i < m_connections.size(); i++) { const AnimGraphConnection& connection = m_connections[i]; result["connections"][i] = sAnimGraphConnectionToJson(connection); } // Graph inputs and outputs { const AnimNodeResource& graph_output_node = m_nodes[0]; const std::vector graph_inputs = graph_output_node.m_socket_accessor->m_inputs; for (size_t i = 0; i < graph_inputs.size(); i++) { result["nodes"][0]["inputs"][i] = sSocketToJson(graph_inputs[i]); } const AnimNodeResource& graph_input_node = m_nodes[1]; const std::vector graph_outputs = graph_input_node.m_socket_accessor->m_outputs; for (size_t i = 0; i < graph_outputs.size(); i++) { result["nodes"][1]["outputs"][i] = sSocketToJson(graph_outputs[i]); } } std::ofstream output_file; output_file.open(filename); output_file << to_string(result) << std::endl; output_file.close(); return true; } bool AnimGraphResource::loadFromFile(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; } if (json_data["type"] != "AnimGraphResource") { std::cerr << "Invalid json object. Expected type 'AnimGraphResource' but got '" << json_data["type"] << "'." << std::endl; } clear(); m_name = json_data["name"]; for (size_t i = 0; i < json_data["nodes"].size(); i++) { const json& json_node = json_data["nodes"][i]; if (json_node["type"] != "AnimNodeResource") { std::cerr << "Invalid json object. Expected type 'AnimNodeResource' but got '" << json_node["type"] << "'." << std::endl; return false; } AnimNodeResource node = sAnimGraphNodeFromJson(json_node); m_nodes.push_back(node); } for (size_t i = 0; i < json_data["connections"].size(); i++) { const json& json_connection = json_data["connections"][i]; if (json_connection["type"] != "AnimGraphConnection") { std::cerr << "Invalid json object. Expected type 'AnimGraphConnection' " "but got '" << json_connection["type"] << "'." << std::endl; return false; } AnimGraphConnection connection = sAnimGraphConnectionFromJson(json_connection); m_connections.push_back(connection); } const json& graph_outputs = json_data["nodes"][0]["inputs"]; for (size_t i = 0; i < graph_outputs.size(); i++) { AnimNodeResource& graph_node = m_nodes[0]; graph_node.m_socket_accessor->m_inputs.push_back( sJsonToSocket(graph_outputs[i])); } const json& graph_inputs = json_data["nodes"][1]["outputs"]; for (size_t i = 0; i < graph_inputs.size(); i++) { AnimNodeResource& graph_node = m_nodes[1]; graph_node.m_socket_accessor->m_outputs.push_back( sJsonToSocket(graph_inputs[i])); } return false; } void* AnimGraph::GetOutput(const std::string& name) { Socket* socket = m_socket_accessor->FindInputSocket(name); if (socket == nullptr) { return nullptr; } return socket->m_value.ptr; } void* AnimGraph::GetInput(const std::string& name) { Socket* socket = m_socket_accessor->FindOutputSocket(name); if (socket == nullptr) { return nullptr; } return *(socket->m_value.ptr_ptr); }