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