Added support of saving and loading of embedded blend tree resources.

This commit is contained in:
Martin Felis
2024-03-24 21:50:22 +01:00
parent 3a7f470acf
commit 116bf7699b
6 changed files with 483 additions and 255 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ struct AnimNode;
struct AnimNodeResource {
std::string m_name;
std::string m_type_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};
+3 -3
View File
@@ -162,7 +162,7 @@ void SkinnedMeshWidget(SkinnedMesh* skinned_mesh) {
void AnimGraphEditorRenderSidebar(
AnimGraphBlendTreeResource& graph_resource,
AnimNodeResource& node_resource) {
ImGui::Text("[%s]", node_resource.m_type_name.c_str());
ImGui::Text("[%s]", node_resource.m_node_type_name.c_str());
char node_name_buffer[256];
memset(node_name_buffer, 0, sizeof(node_name_buffer));
@@ -307,7 +307,7 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
ImVec2(node_resource.m_position[0], node_resource.m_position[1]));
}
ax::NodeEditor::BeginNode(node_id);
ImGui::Text("%s", node_resource.m_type_name.c_str());
ImGui::Text("%s", node_resource.m_node_type_name.c_str());
// Inputs
std::vector<Socket>& node_inputs =
@@ -485,7 +485,7 @@ void LegacyAnimGraphEditorUpdate() {
} else if (&node_resource == &sGraphGresource.getGraphInputNode()) {
ImGui::TextUnformatted("Graph Inputs");
} else {
ImGui::TextUnformatted(node_resource.m_type_name.c_str());
ImGui::TextUnformatted(node_resource.m_node_type_name.c_str());
}
ImNodes::EndNodeTitleBar();
+4
View File
@@ -262,6 +262,8 @@ static inline AnimNode* AnimNodeFactory(const std::string& name) {
result = new LockTranslationNode;
} else if (name == "BlendTree") {
result = new BlendTreeNode;
} else if (name == "BlendTreeSockets") {
result = new BlendTreeNode;
} else if (name == "MathAddNode") {
result = new MathAddNode;
} else if (name == "MathFloatToVec3Node") {
@@ -292,6 +294,8 @@ static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
return CreateNodeDescriptor<LockTranslationNode>(node);
} else if (node_type_name == "BlendTree") {
return CreateNodeDescriptor<BlendTreeNode>(node);
} else if (node_type_name == "BlendTreeSockets") {
return CreateNodeDescriptor<BlendTreeNode>(node);
} else if (node_type_name == "MathAddNode") {
return CreateNodeDescriptor<MathAddNode>(node);
} else if (node_type_name == "MathFloatToVec3Node") {
+209 -125
View File
@@ -14,6 +14,10 @@
using json = nlohmann::json;
// forward declarations
static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_graph_resource);
static bool sAnimGraphResourceBlendTreeFromJson(const json& json_data, AnimGraphResource* result_graph_resource);
//
// Socket <-> json
//
@@ -125,20 +129,24 @@ Socket sJsonToSocket(const json& json_data) {
// AnimGraphNode <-> json
//
json sAnimGraphNodeToJson(
const AnimNodeResource& node,
const AnimNodeResource* node,
size_t node_index,
const std::vector<BlendTreeConnectionResource>& connections) {
json result;
result["name"] = node.m_name;
result["name"] = node->m_name;
result["type"] = "AnimNodeResource";
result["node_type"] = node.m_type_name;
result["node_type"] = node->m_node_type_name;
for (size_t j = 0; j < 2; j++) {
result["position"][j] = node.m_position[j];
result["position"][j] = node->m_position[j];
}
for (const auto& socket : node.m_socket_accessor->m_inputs) {
if (node->m_node_type_name == "BlendTree") {
}
for (const auto& socket : node->m_socket_accessor->m_inputs) {
if (socket.m_type == SocketType::SocketTypeAnimation) {
continue;
}
@@ -157,28 +165,37 @@ json sAnimGraphNodeToJson(
}
}
for (auto& property : node.m_socket_accessor->m_properties) {
for (auto& property : node->m_socket_accessor->m_properties) {
result["properties"][property.m_name] = sSocketToJson(property);
}
return result;
}
AnimNodeResource sAnimGraphNodeFromJson(
AnimNodeResource* sAnimGraphNodeFromJson(
const json& json_node,
size_t node_index) {
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];
std::string node_type = json_node["node_type"];
result.m_anim_node = AnimNodeFactory(result.m_type_name);
result.m_socket_accessor =
AnimNodeDescriptorFactory(result.m_type_name, result.m_anim_node);
if (node_type == "BlendTree") {
AnimGraphResource* result = new AnimGraphResource();
sAnimGraphResourceBlendTreeFromJson(json_node, result);
return result;
}
for (auto& property : result.m_socket_accessor->m_properties) {
AnimNodeResource* result;
result = new AnimNodeResource();
result->m_name = json_node["name"];
result->m_node_type_name = 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_node_type_name);
result->m_socket_accessor =
AnimNodeDescriptorFactory(result->m_node_type_name, result->m_anim_node);
for (auto& property : result->m_socket_accessor->m_properties) {
property = sJsonToSocket(json_node["properties"][property.m_name]);
}
@@ -187,10 +204,10 @@ AnimNodeResource sAnimGraphNodeFromJson(
assert(json_node["inputs"][j].contains("name"));
std::string input_name = json_node["inputs"][j]["name"];
Socket* input_socket =
result.m_socket_accessor->GetInputSocket(input_name.c_str());
result->m_socket_accessor->GetInputSocket(input_name.c_str());
if (input_socket == nullptr) {
std::cerr << "Could not find input socket with name " << input_name
<< " for node type " << result.m_type_name << std::endl;
<< " for node type " << result->m_node_type_name << std::endl;
abort();
}
*input_socket = sJsonToSocket(json_node["inputs"][j]);
@@ -230,6 +247,160 @@ BlendTreeConnectionResource sAnimGraphConnectionFromJson(
return connection;
}
static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_graph_resource) {
json result;
result["name"] = anim_graph_resource.m_name;
result["type"] = "AnimNodeResource";
result["node_type"] = "BlendTree";
const BlendTreeResource& blend_tree_resource = anim_graph_resource.m_blend_tree_resource;
for (size_t i = 0; i < blend_tree_resource.m_nodes.size(); i++) {
const AnimNodeResource* node = blend_tree_resource.m_nodes[i];
if (node->m_node_type_name == "BlendTree") {
const AnimGraphResource* graph_resource = dynamic_cast<const AnimGraphResource*>(node);
result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource);
} else {
result["nodes"][i] =
sAnimGraphNodeToJson(node, i, blend_tree_resource.m_connections);
}
}
for (size_t i = 0; i < blend_tree_resource.m_connections.size(); i++) {
const BlendTreeConnectionResource& connection =
blend_tree_resource.m_connections[i];
result["connections"][i] = sAnimGraphConnectionToJson(connection);
}
// Graph inputs and outputs
{
const AnimNodeResource* graph_output_node =
blend_tree_resource.m_nodes[0];
const std::vector<Socket> 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 = blend_tree_resource.m_nodes[1];
const std::vector<Socket> 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]);
}
}
return result;
}
static bool sAnimGraphResourceBlendTreeFromJson(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"];
// Load nodes
for (size_t i = 0, n = json_data["nodes"].size(); i < n; 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, i);
blend_tree_resource.m_nodes.push_back(node);
}
// Graph outputs
const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (const auto& graph_output : graph_outputs) {
AnimNodeResource* graph_node = blend_tree_resource.m_nodes[0];
graph_node->m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_output));
}
// Graph inputs (optional)
if (json_data["nodes"][1].contains("outputs")) {
const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (const auto& graph_input : graph_inputs) {
AnimNodeResource* graph_node = blend_tree_resource.m_nodes[1];
graph_node->m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_input));
}
}
// Load connections
for (const auto& json_connection : json_data["connections"]) {
if (json_connection["type"] != "AnimGraphConnectionResource") {
std::cerr << "Invalid json object. Expected type "
"'AnimGraphConnectionResource' "
"but got '"
<< json_connection["type"] << "'." << std::endl;
return false;
}
BlendTreeConnectionResource connection =
sAnimGraphConnectionFromJson(json_connection);
blend_tree_resource.m_connections.push_back(connection);
}
return true;
}
bool BlendTreeResource::ConnectSockets (
const AnimNodeResource* source_node,
const std::string& source_socket_name,
const AnimNodeResource* target_node,
const std::string& target_socket_name) {
size_t source_node_index = GetNodeIndex(source_node);
size_t target_node_index = GetNodeIndex(target_node);
if (source_node_index >= m_nodes.size()
|| target_node_index >= m_nodes.size()) {
std::cerr << "Cannot connect nodes: could not find nodes." << std::endl;
return false;
}
Socket* source_socket;
Socket* target_socket;
if (target_node->m_node_type_name == "BlendTree") {
const AnimGraphResource* target_graph_resource = dynamic_cast<const AnimGraphResource*>(target_node);
AnimNodeResource* graph_output_node = target_graph_resource->m_blend_tree_resource.GetGraphInputNode();
target_socket = graph_output_node->m_socket_accessor->GetOutputSocket(target_socket_name.c_str());
} else {
target_socket =
target_node->m_socket_accessor->GetInputSocket(target_socket_name.c_str());
}
if (source_node->m_node_type_name == "BlendTree") {
const AnimGraphResource* source_graph_resource = dynamic_cast<const AnimGraphResource*>(source_node);
AnimNodeResource* graph_output_node = source_graph_resource->m_blend_tree_resource.GetGraphOutputNode();
source_socket = graph_output_node->m_socket_accessor->GetInputSocket(source_socket_name.c_str());
} else {
source_socket =
source_node->m_socket_accessor->GetOutputSocket(source_socket_name.c_str());
}
if (source_socket == nullptr || target_socket == nullptr) {
std::cerr << "Cannot connect nodes: could not find sockets." << std::endl;
return false;
}
BlendTreeConnectionResource connection;
connection.source_node_index = source_node_index;
connection.source_socket_name = source_socket_name;
connection.target_node_index = target_node_index;
connection.target_socket_name = target_socket_name;
m_connections.push_back(connection);
return true;
}
bool AnimGraphResource::LoadFromFile(const char* filename) {
std::ifstream input_file;
input_file.open(filename);
@@ -253,7 +424,7 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
}
if (json_data["node_type"] == "BlendTree") {
return LoadBlendTreeResourceFromJson(json_data);
return sAnimGraphResourceBlendTreeFromJson(json_data, this);
} else if (json_data["node_type"] == "StateMachine") {
return LoadStateMachineResourceFromJson(json_data);
}
@@ -265,69 +436,14 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
return false;
}
bool AnimGraphResource::LoadBlendTreeResourceFromJson(nlohmann::json const& json_data) {
m_blend_tree_resource.Reset();
m_type = "BlendTree";
m_name = json_data["name"];
// Load nodes
for (size_t i = 0, n = json_data["nodes"].size(); i < n; 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, i);
m_blend_tree_resource.m_nodes.push_back(node);
}
// Graph outputs
const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (const auto& graph_output : graph_outputs) {
AnimNodeResource& graph_node = m_blend_tree_resource.m_nodes[0];
graph_node.m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_output));
}
// Graph inputs (optional)
if (json_data["nodes"][1].contains("outputs")) {
const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (const auto& graph_input : graph_inputs) {
AnimNodeResource& graph_node = m_blend_tree_resource.m_nodes[1];
graph_node.m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_input));
}
}
// Load connections
for (const auto& json_connection : json_data["connections"]) {
if (json_connection["type"] != "AnimGraphConnectionResource") {
std::cerr << "Invalid json object. Expected type "
"'AnimGraphConnectionResource' "
"but got '"
<< json_connection["type"] << "'." << std::endl;
return false;
}
BlendTreeConnectionResource connection =
sAnimGraphConnectionFromJson(json_connection);
m_blend_tree_resource.m_connections.push_back(connection);
}
return true;
}
bool AnimGraphResource::SaveToFile(const char* filename) const {
if (m_type == "BlendTree") {
if (m_graph_type_name == "BlendTree") {
return SaveBlendTreeResourceToFile(filename);
} else if (m_type == "StateMachine") {
} else if (m_graph_type_name == "StateMachine") {
return SaveStateMachineResourceToFile(filename);
}
std::cerr << "Invalid AnimGraphResource type: " << m_type << "." << std::endl;
std::cerr << "Invalid AnimGraphResource type: " << m_graph_type_name << "." << std::endl;
return false;
}
@@ -336,39 +452,8 @@ bool AnimGraphResource::SaveBlendTreeResourceToFile(
const char* filename) const {
json result;
result["name"] = m_name;
result["type"] = "AnimNodeResource";
result["node_type"] = "BlendTree";
for (size_t i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) {
const AnimNodeResource& node = m_blend_tree_resource.m_nodes[i];
result["nodes"][i] =
sAnimGraphNodeToJson(node, i, m_blend_tree_resource.m_connections);
}
for (size_t i = 0; i < m_blend_tree_resource.m_connections.size(); i++) {
const BlendTreeConnectionResource& connection =
m_blend_tree_resource.m_connections[i];
result["connections"][i] = sAnimGraphConnectionToJson(connection);
}
// Graph inputs and outputs
{
const AnimNodeResource& graph_output_node =
m_blend_tree_resource.m_nodes[0];
const std::vector<Socket> 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_blend_tree_resource.m_nodes[1];
const std::vector<Socket> 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]);
}
}
result = sAnimGraphResourceBlendTreeToJson(
*this);
std::ofstream output_file;
output_file.open(filename);
@@ -380,9 +465,9 @@ bool AnimGraphResource::SaveBlendTreeResourceToFile(
void AnimGraphResource::CreateBlendTreeInstance(
AnimGraphBlendTree& result) const {
if (m_type != "BlendTree") {
if (m_node_type_name != "BlendTree") {
std::cerr << "Invalid AnimGraphResource. Expected type 'BlendTree' but got '"
<< m_type << "'." << std::endl;
<< m_graph_type_name << "'." << std::endl;
return;
}
@@ -396,11 +481,10 @@ void AnimGraphResource::CreateBlendTreeInstance(
void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances(
AnimGraphBlendTree& result) const {
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) {
const AnimNodeResource& node_resource = m_blend_tree_resource.m_nodes[i];
AnimNode* node = AnimNodeFactory(node_resource.m_type_name);
node->m_name = node_resource.m_name;
node->m_node_type_name = node_resource.m_type_name;
for (auto node_resource : m_blend_tree_resource.m_nodes) {
AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name);
node->m_name = node_resource->m_name;
node->m_node_type_name = node_resource->m_node_type_name;
result.m_nodes.push_back(node);
// runtime node connections
@@ -414,9 +498,9 @@ void AnimGraphResource::PrepareBlendTreeIOData(
instance.m_node_descriptor =
AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]);
instance.m_node_descriptor->m_outputs =
m_blend_tree_resource.m_nodes[1].m_socket_accessor->m_outputs;
m_blend_tree_resource.m_nodes[1]->m_socket_accessor->m_outputs;
instance.m_node_descriptor->m_inputs =
m_blend_tree_resource.m_nodes[0].m_socket_accessor->m_inputs;
m_blend_tree_resource.m_nodes[0]->m_socket_accessor->m_inputs;
//
// graph inputs
@@ -466,9 +550,9 @@ void AnimGraphResource::PrepareBlendTreeIOData(
// TODO: instead of every connection, only create data blocks for the source sockets and make sure every source socket gets allocated once.
size_t connection_data_storage_size = 0;
for (const auto& connection : m_blend_tree_resource.m_connections) {
const AnimNodeResource& source_node =
const AnimNodeResource* source_node =
m_blend_tree_resource.m_nodes[connection.source_node_index];
Socket* source_socket = source_node.m_socket_accessor->GetOutputSocket(
Socket* source_socket = source_node->m_socket_accessor->GetOutputSocket(
connection.source_socket_name.c_str());
connection_data_storage_size += source_socket->m_type_size;
}
@@ -483,7 +567,7 @@ void AnimGraphResource::PrepareBlendTreeIOData(
nullptr);
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) {
instance_node_descriptors[i] = AnimNodeDescriptorFactory(
m_blend_tree_resource.m_nodes[i].m_type_name,
m_blend_tree_resource.m_nodes[i]->m_node_type_name,
instance.m_nodes[i]);
}
@@ -579,13 +663,13 @@ void AnimGraphResource::PrepareBlendTreeIOData(
void AnimGraphResource::SetRuntimeNodeProperties(
AnimGraphBlendTree& result) const {
for (int i = 2; i < m_blend_tree_resource.m_nodes.size(); i++) {
const AnimNodeResource& node_resource = m_blend_tree_resource.m_nodes[i];
const AnimNodeResource* node_resource = m_blend_tree_resource.m_nodes[i];
NodeDescriptorBase* node_instance_accessor =
AnimNodeDescriptorFactory(node_resource.m_type_name, result.m_nodes[i]);
AnimNodeDescriptorFactory(node_resource->m_node_type_name, result.m_nodes[i]);
std::vector<Socket>& resource_properties =
node_resource.m_socket_accessor->m_properties;
node_resource->m_socket_accessor->m_properties;
for (const auto& property : resource_properties) {
const std::string& name = property.m_name;
+49 -57
View File
@@ -14,22 +14,16 @@ struct AnimGraphBlendTree;
struct AnimGraphStateMachine;
struct AnimNodeResource {
virtual ~AnimNodeResource() = default;
std::string m_name;
std::string m_type_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) {
AnimNodeResource result;
result.m_type_name = node_type_name;
result.m_anim_node = AnimNodeFactory(node_type_name);
result.m_socket_accessor =
AnimNodeDescriptorFactory(node_type_name, result.m_anim_node);
return result;
}
static inline AnimNodeResource* AnimNodeResourceFactory(const std::string& node_type_name);
struct BlendTreeConnectionResource {
size_t source_node_index = -1;
@@ -39,7 +33,7 @@ struct BlendTreeConnectionResource {
};
struct BlendTreeResource {
std::vector<AnimNodeResource> m_nodes;
std::vector<AnimNodeResource*> m_nodes;
std::vector<BlendTreeConnectionResource> m_connections;
~BlendTreeResource() { CleanupNodes();
@@ -52,27 +46,28 @@ struct BlendTreeResource {
}
void CleanupNodes() {
for (AnimNodeResource& node_resource : m_nodes) {
delete node_resource.m_anim_node;
delete node_resource.m_socket_accessor;
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("BlendTree"));
m_nodes[0].m_name = "Outputs";
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
m_nodes[1].m_name = "Inputs";
m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets"));
m_nodes[0]->m_name = "Outputs";
m_nodes.push_back(AnimNodeResourceFactory("BlendTreeSockets"));
m_nodes[1]->m_name = "Inputs";
}
AnimNodeResource& GetGraphOutputNode() { return m_nodes[0]; }
AnimNodeResource& GetGraphInputNode() { return m_nodes[1]; }
[[nodiscard]] AnimNodeResource* GetGraphOutputNode() const { return m_nodes[0]; }
[[nodiscard]] AnimNodeResource* GetGraphInputNode() const { return m_nodes[1]; }
size_t GetNodeIndex(const AnimNodeResource& node_resource) const {
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) {
if (m_nodes[i] == node_resource) {
return i;
}
}
@@ -81,38 +76,10 @@ struct BlendTreeResource {
}
bool ConnectSockets (
const AnimNodeResource& source_node,
const AnimNodeResource* source_node,
const std::string& source_socket_name,
const AnimNodeResource& target_node,
const std::string& target_socket_name) {
size_t source_node_index = GetNodeIndex(source_node);
size_t target_node_index = GetNodeIndex(target_node);
if (source_node_index >= m_nodes.size()
|| target_node_index >= m_nodes.size()) {
std::cerr << "Cannot connect nodes: could not find nodes." << std::endl;
return false;
}
Socket* source_socket =
source_node.m_socket_accessor->GetOutputSocket(source_socket_name.c_str());
Socket* target_socket =
target_node.m_socket_accessor->GetInputSocket(target_socket_name.c_str());
if (source_socket == nullptr || target_socket == nullptr) {
std::cerr << "Cannot connect nodes: could not find sockets." << std::endl;
return false;
}
BlendTreeConnectionResource connection;
connection.source_node_index = source_node_index;
connection.source_socket_name = source_socket_name;
connection.target_node_index = target_node_index;
connection.target_socket_name = target_socket_name;
m_connections.push_back(connection);
return true;
}
const AnimNodeResource* target_node,
const std::string& target_socket_name);
std::vector<Socket*> GetConstantNodeInputs(
std::vector<NodeDescriptorBase*>& instance_node_descriptors) const {
@@ -125,7 +92,7 @@ struct BlendTreeResource {
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));
memcpy(&input.m_value, &m_nodes[i]->m_socket_accessor->m_inputs[j].m_value, sizeof(Socket::SocketValue));
result.push_back(&input);
}
}
@@ -147,8 +114,8 @@ struct StateMachineResource {
std::vector<StateMachineTransitionResources> m_transitions;
};
struct AnimGraphResource {
std::string m_type;
struct AnimGraphResource: AnimNodeResource {
std::string m_graph_type_name;
std::string m_name;
BlendTreeResource m_blend_tree_resource;
@@ -163,7 +130,6 @@ struct AnimGraphResource {
private:
// BlendTree
bool SaveBlendTreeResourceToFile(const char* filename) const;
bool LoadBlendTreeResourceFromJson(nlohmann::json const& json_data);
void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const;
void PrepareBlendTreeIOData(AnimGraphBlendTree& instance) const;
void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const;
@@ -172,4 +138,30 @@ struct AnimGraphResource {
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