Refactored BlendTreeResources to be a subclass of AnimGraphResource.
The latter is used to abstract saving/loading for both BlendTrees and StateMachines.
This commit is contained in:
+175
-205
@@ -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<BlendTreeConnectionResource>& 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<AnimGraphResource*>(AnimNodeResourceFactory("BlendTree"));
|
||||
sAnimGraphResourceBlendTreeFromJson(json_node, result);
|
||||
BlendTreeResource* result =
|
||||
dynamic_cast<BlendTreeResource*>(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<const AnimGraphResource*>(node);
|
||||
result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource);
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<BlendTreeResource*>(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<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<Socket> BlendTreeResource::GetNodeOutputSockets(
|
||||
}
|
||||
|
||||
if (node->m_node_type_name == "BlendTree") {
|
||||
const AnimGraphResource* graph_resource =
|
||||
dynamic_cast<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
return blend_tree_resource.GetGraphOutputNode()
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(node);
|
||||
|
||||
return blend_tree_resource->GetGraphOutputNode()
|
||||
->m_virtual_socket_accessor->m_inputs;
|
||||
}
|
||||
|
||||
@@ -671,11 +743,10 @@ std::vector<Socket> BlendTreeResource::GetNodeInputSockets(
|
||||
}
|
||||
|
||||
if (node->m_node_type_name == "BlendTree") {
|
||||
const AnimGraphResource* graph_resource =
|
||||
dynamic_cast<const AnimGraphResource*>(node);
|
||||
const BlendTreeResource& blend_tree_resource =
|
||||
graph_resource->m_blend_tree_resource;
|
||||
return blend_tree_resource.GetGraphInputNode()
|
||||
const BlendTreeResource* blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(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<AnimData>(
|
||||
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<AnimGraphResource*>(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<const AnimGraphResource*>(node_resource);
|
||||
const BlendTreeResource* embedded_blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(node_resource);
|
||||
assert(embedded_blend_tree_resource != nullptr);
|
||||
AnimGraphBlendTree* embedded_blend_tree =
|
||||
dynamic_cast<AnimGraphBlendTree*>(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<NodeDescriptorBase*> 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<const AnimGraphResource*>(
|
||||
m_blend_tree_resource.GetNode(connection.source_node_index));
|
||||
const BlendTreeResource* source_blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(
|
||||
GetNode(connection.source_node_index));
|
||||
AnimGraphBlendTree* source_blend_tree =
|
||||
dynamic_cast<AnimGraphBlendTree*>(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<const AnimGraphResource*>(
|
||||
m_blend_tree_resource.GetNode(connection.target_node_index));
|
||||
const BlendTreeResource* target_blend_tree_resource =
|
||||
dynamic_cast<const BlendTreeResource*>(
|
||||
GetNode(connection.target_node_index));
|
||||
AnimGraphBlendTree* target_blend_tree =
|
||||
dynamic_cast<AnimGraphBlendTree*>(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<Socket*> 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
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+121
-114
@@ -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<AnimNodeResource> m_states;
|
||||
std::vector<StateMachineTransitionResources> 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<AnimGraphResource> 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<const AnimNodeResource*, std::string> NodeSocketNamePair;
|
||||
typedef std::map<NodeSocketNamePair, int> NodeSocketDataOffsetMap;
|
||||
|
||||
std::vector<std::vector<size_t> > m_node_input_connection_indices;
|
||||
std::vector<std::vector<size_t> > m_node_inputs_subtree;
|
||||
|
||||
BlendTreeResource() {
|
||||
m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree");
|
||||
|
||||
InitGraphConnectors();
|
||||
RegisterBlendTreeOutputSocket<AnimData>(
|
||||
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 <typename T>
|
||||
bool RegisterBlendTreeInputSocket(const std::string& socket_name) {
|
||||
Socket socket;
|
||||
socket.m_name = socket_name;
|
||||
socket.m_type = GetSocketType<T>();
|
||||
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 <typename T>
|
||||
bool RegisterBlendTreeOutputSocket(const std::string& socket_name) {
|
||||
Socket socket;
|
||||
socket.m_name = socket_name;
|
||||
socket.m_type = GetSocketType<T>();
|
||||
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<AnimNodeResource*>& GetNodes() const {
|
||||
return m_nodes;
|
||||
}
|
||||
@@ -172,6 +275,7 @@ struct BlendTreeResource {
|
||||
const size_t socket_input_index) const;
|
||||
|
||||
std::vector<Socket> GetNodeOutputSockets(const AnimNodeResource* node) const;
|
||||
|
||||
std::vector<Socket> 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<AnimNodeResource*> 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<AnimNodeResource> m_states;
|
||||
std::vector<StateMachineTransitionResources> 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<const AnimNodeResource*, std::string> NodeSocketPair;
|
||||
typedef std::map<NodeSocketPair, int> 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 <typename T>
|
||||
bool RegisterBlendTreeInputSocket(const std::string& socket_name) {
|
||||
Socket socket;
|
||||
socket.m_name = socket_name;
|
||||
socket.m_type = GetSocketType<T>();
|
||||
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 <typename T>
|
||||
bool RegisterBlendTreeOutputSocket(const std::string& socket_name) {
|
||||
Socket socket;
|
||||
socket.m_name = socket_name;
|
||||
socket.m_type = GetSocketType<T>();
|
||||
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<AnimGraphResource> 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();
|
||||
|
||||
Reference in New Issue
Block a user