Nodes can now be deleted in the blend tree editor.

This commit is contained in:
Martin Felis 2025-03-02 16:14:07 +01:00
parent acbe3a4ed5
commit a1c4630ee7
5 changed files with 221 additions and 151 deletions

View File

@ -9,5 +9,4 @@ BinPackParameters: 'false'
BreakBeforeBinaryOperators: NonAssignment
ExperimentalAutoDetectBinPacking: 'false'
ReflowComments: 'false'
...
DerivePointerAlignment: false

View File

@ -192,9 +192,6 @@ AnimNodeResource* sAnimGraphNodeFromJson(
result->m_position[0] = json_node["position"][0];
result->m_position[1] = json_node["position"][1];
result->m_virtual_socket_accessor =
VirtualAnimNodeDescriptorFactory(result->m_node_type_name);
for (auto& property : result->m_virtual_socket_accessor->m_properties) {
property = sJsonToSocket(json_node["properties"][property.m_name]);
}
@ -310,6 +307,9 @@ static bool sAnimGraphResourceBlendTreeFromJson(
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.
blend_tree_resource.ClearAllNodes();
// Load nodes
for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) {
const json& json_node = json_data["nodes"][i];
@ -367,6 +367,76 @@ static bool sAnimGraphResourceBlendTreeFromJson(
return true;
}
static bool sAnimGraphResourceStateMachineFromJson(
const json& json_data,
AnimGraphResource* result_graph_resource) {
assert(false && !"Not yet implemented!");
return false;
}
void BlendTreeResource::RemoveConnectionsForSocket(
const AnimNodeResource* node_resource,
const Socket& socket) {
const BlendTreeConnectionResource* connection =
FindConnectionForSocket(node_resource, socket.m_name);
while (connection != nullptr) {
DisconnectSockets(
GetNode(connection->source_node_index),
connection->source_socket_name,
GetNode(connection->target_node_index),
connection->target_socket_name);
connection = FindConnectionForSocket(node_resource, socket.m_name);
}
}
void BlendTreeResource::RemoveNodeConnections(AnimNodeResource* node_resource) {
for (const Socket& socket :
node_resource->m_virtual_socket_accessor->m_inputs) {
RemoveConnectionsForSocket(node_resource, socket);
}
for (const Socket& socket :
node_resource->m_virtual_socket_accessor->m_outputs) {
RemoveConnectionsForSocket(node_resource, socket);
}
}
bool BlendTreeResource::RemoveNode(AnimNodeResource* node_resource) {
std::vector<AnimNodeResource*>::iterator node_iterator =
std::find(m_nodes.begin(), m_nodes.end(), node_resource);
if (node_iterator == m_nodes.end()) {
return true;
}
const size_t node_index = node_iterator - m_nodes.begin();
if (m_node_input_connection_indices[node_index].size() > 0) {
std::cerr << "Cannot remove node, node still has input connections!"
<< std::endl;
return false;
}
m_node_input_connection_indices.erase(
m_node_input_connection_indices.begin() + node_index);
m_nodes.erase(node_iterator);
for (BlendTreeConnectionResource& connection : m_connections) {
if (connection.source_node_index > node_index) {
connection.source_node_index--;
}
if (connection.target_node_index > node_index) {
connection.target_node_index--;
}
}
UpdateNodeEvalOrder();
UpdateTreeTopologyInfo();
return true;
}
bool BlendTreeResource::ConnectSockets(
const AnimNodeResource* source_node,
const std::string& source_socket_name,
@ -760,7 +830,8 @@ AnimGraphResource::AnimGraphResource(AnimGraphType graph_type) {
m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree");
m_blend_tree_resource.InitGraphConnectors();
RegisterBlendTreeOutputSocket<AnimData>("Output");
RegisterBlendTreeOutputSocket<AnimData>(
AnimGraphResource::DefaultAnimOutput);
} else {
std::cerr
<< "Warning: construction of state machine graphs not yet implemented!"
@ -768,9 +839,7 @@ AnimGraphResource::AnimGraphResource(AnimGraphType graph_type) {
}
}
bool AnimGraphResource::LoadFromFile(const char* filename) {
Clear();
AnimGraphResource* AnimGraphResource::CreateFromFile(const char* filename) {
std::ifstream input_file;
input_file.open(filename);
std::stringstream buffer;
@ -781,7 +850,7 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
std::cerr << "Error parsing json of file '" << filename << "'."
<< std::endl;
return false;
return nullptr;
}
if (json_data["type"] != "AnimNodeResource") {
@ -789,20 +858,23 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
<< "Invalid json object. Expected type 'AnimNodeResource' but got '"
<< json_data["type"] << "'." << std::endl;
return false;
return nullptr;
}
AnimGraphResource* result = nullptr;
if (json_data["node_type"] == "BlendTree") {
return sAnimGraphResourceBlendTreeFromJson(json_data, this);
result =
dynamic_cast<AnimGraphResource*>(AnimNodeResourceFactory("BlendTree"));
sAnimGraphResourceBlendTreeFromJson(json_data, result);
} else if (json_data["node_type"] == "StateMachine") {
return LoadStateMachineResourceFromJson(json_data);
sAnimGraphResourceStateMachineFromJson(json_data, result);
} else {
std::cerr << "Invalid node_type. Expected type 'BlendTree' or "
"'StateMachine' but got '"
<< json_data["node_type"] << "'." << std::endl;
}
std::cerr << "Invalid node_type. Expected type 'BlendTree' or "
"'StateMachine' but got '"
<< json_data["node_type"] << "'." << std::endl;
return false;
return result;
}
bool AnimGraphResource::SaveToFile(const char* filename) const {

View File

@ -43,10 +43,10 @@ struct BlendTreeResource {
std::vector<std::vector<size_t> > m_node_input_connection_indices;
std::vector<std::vector<size_t> > m_node_inputs_subtree;
~BlendTreeResource() { CleanupNodes(); }
~BlendTreeResource() { ClearAllNodes(); }
void Reset() {
CleanupNodes();
ClearAllNodes();
m_connections.clear();
@ -54,7 +54,7 @@ struct BlendTreeResource {
m_node_inputs_subtree.clear();
}
void CleanupNodes() {
void ClearAllNodes() {
for (AnimNodeResource* node_resource : m_nodes) {
delete node_resource;
}
@ -62,18 +62,6 @@ struct BlendTreeResource {
m_nodes.clear();
}
void InitGraphConnectors() {
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* output_node = GetGraphOutputNode();
output_node->m_name = "Outputs";
output_node->m_position[0] = 200;
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* input_node = GetGraphInputNode();
input_node->m_name = "Inputs";
input_node->m_position[0] = -200;
}
[[nodiscard]] AnimNodeResource* GetGraphOutputNode() const {
return m_nodes[0];
}
@ -134,6 +122,12 @@ struct BlendTreeResource {
return m_nodes.size() - 1;
}
void RemoveConnectionsForSocket(
const AnimNodeResource* node_resource,
const Socket& socket);
void RemoveNodeConnections(AnimNodeResource* node_resource);
[[maybe_unused]] bool RemoveNode(AnimNodeResource* node_resource);
[[nodiscard]] size_t GetNumNodes() const { return m_nodes.size(); }
[[nodiscard]] AnimNodeResource* GetNode(size_t i) { return m_nodes[i]; }
[[nodiscard]] const AnimNodeResource* GetNode(size_t i) const {
@ -271,6 +265,18 @@ struct BlendTreeResource {
}
private:
void InitGraphConnectors() {
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* output_node = GetGraphOutputNode();
output_node->m_name = "Outputs";
output_node->m_position[0] = 200;
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* input_node = GetGraphInputNode();
input_node->m_name = "Inputs";
input_node->m_position[0] = -200;
}
void UpdateNodeEvalOrder() {
m_node_eval_order.clear();
UpdateNodeEvalOrderRecursive(0);
@ -281,6 +287,8 @@ struct BlendTreeResource {
std::vector<AnimNodeResource*> m_nodes;
std::vector<BlendTreeConnectionResource> m_connections;
std::vector<size_t> m_node_eval_order;
friend class AnimGraphResource;
};
struct StateMachineTransitionResources {
@ -299,6 +307,8 @@ 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;
@ -308,8 +318,8 @@ struct AnimGraphResource : AnimNodeResource {
StateMachineResource m_state_machine_resource;
void Clear() { m_blend_tree_resource.Reset(); }
bool SaveToFile(const char* filename) const;
bool LoadFromFile(const char* filename);
[[maybe_unused]] bool SaveToFile(const char* filename) const;
static AnimGraphResource* CreateFromFile(const char* filename);
void CreateBlendTreeInstance(AnimGraphBlendTree& result) const;
@ -389,7 +399,9 @@ struct AnimGraphResource : AnimNodeResource {
bool LoadStateMachineResourceFromJson(nlohmann::json const& json_data);
};
static inline AnimNodeResource* AnimNodeResourceFactory(
typedef std::unique_ptr<AnimGraphResource> AnimGraphResourcePtr;
inline AnimNodeResource* AnimNodeResourceFactory(
const std::string& node_type_name) {
AnimNodeResource* result;

View File

@ -132,25 +132,6 @@ bool NodeSocketEditor(Socket& socket) {
return modified;
}
void RemoveBlendTreeConnectionsForSocket(
BlendTreeResource& blend_tree_resource,
AnimNodeResource* node_resource,
Socket& socket) {
const BlendTreeConnectionResource* connection =
blend_tree_resource.FindConnectionForSocket(node_resource, socket.m_name);
while (connection != nullptr) {
blend_tree_resource.DisconnectSockets(
blend_tree_resource.GetNode(connection->source_node_index),
connection->source_socket_name,
blend_tree_resource.GetNode(connection->target_node_index),
connection->target_socket_name);
connection = blend_tree_resource.FindConnectionForSocket(
node_resource,
socket.m_name);
}
}
void SyncTrackEditor(SyncTrack* sync_track) {
ImGui::SliderFloat("duration", &sync_track->m_duration, 0.001f, 10.f);
@ -363,10 +344,7 @@ void AnimGraphEditorRenderSidebar(
current_graph_resource->m_virtual_socket_accessor->m_inputs = inputs;
}
if (ImGui::Button("X")) {
RemoveBlendTreeConnectionsForSocket(
blend_tree_resource,
node_resource,
input);
blend_tree_resource.RemoveConnectionsForSocket(node_resource, input);
iter = inputs.erase(iter);
} else {
iter++;
@ -947,6 +925,21 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
}
}
ax::NodeEditor::NodeId hovered_node = ax::NodeEditor::GetHoveredNode();
if (!hovered_node.Invalid) {
AnimNodeResource* node_resource =
hovered_node.AsPointer<AnimNodeResource>();
if (node_resource && ImGui::IsKeyPressed(ImGuiKey_Delete)) {
AnimGraphResource* current_graph_resource =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
current_graph_resource->m_blend_tree_resource.RemoveNodeConnections(
node_resource);
current_graph_resource->m_blend_tree_resource.RemoveNode(node_resource);
}
}
ax::NodeEditor::SetCurrentEditor(nullptr);
}

View File

@ -19,13 +19,13 @@ class SimpleAnimSamplerGraphResource {
AnimNodeResource* walk_node = nullptr;
public:
SimpleAnimSamplerGraphResource() {
SimpleAnimSamplerGraphResource()
: 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;
blend_tree_resource->InitGraphConnectors();
// Prepare graph inputs and outputs
walk_node_index =
@ -45,13 +45,13 @@ class SimpleAnimSamplerGraphResource {
walk_node,
"Output",
blend_tree_resource->GetGraphOutputNode(),
"GraphOutput");
AnimGraphResource::DefaultAnimOutput);
}
};
class Blend2GraphResource {
protected:
AnimGraphResource graph_resource;
AnimGraphResourcePtr graph_resource;
BlendTreeResource* blend_tree_resource = nullptr;
size_t walk_node_index = -1;
size_t run_node_index = -1;
@ -61,13 +61,13 @@ class Blend2GraphResource {
AnimNodeResource* blend_node = nullptr;
public:
Blend2GraphResource() {
graph_resource.m_name = "WalkRunBlendGraph";
graph_resource.m_node_type_name = "BlendTree";
graph_resource.m_graph_type_name = "BlendTree";
Blend2GraphResource()
: graph_resource(
dynamic_cast<AnimGraphResource*>(
AnimNodeResourceFactory("BlendTree"))) {
graph_resource->m_name = "WalkRunBlendGraph";
blend_tree_resource = &graph_resource.m_blend_tree_resource;
blend_tree_resource->InitGraphConnectors();
blend_tree_resource = &graph_resource->m_blend_tree_resource;
// Prepare graph inputs and outputs
walk_node_index =
@ -93,11 +93,12 @@ class Blend2GraphResource {
blend_node->m_name = "BlendWalkRun";
AnimNodeResource* graph_node = blend_tree_resource->GetGraphOutputNode();
graph_node->m_virtual_socket_accessor->RegisterInput<AnimData>(
"GraphOutput",
nullptr);
REQUIRE(graph_node->m_virtual_socket_accessor->m_inputs.size() == 1);
REQUIRE(
graph_node->m_virtual_socket_accessor->m_inputs[0].m_name
== AnimGraphResource::DefaultAnimOutput);
REQUIRE(
blend_node->m_virtual_socket_accessor->GetInputIndex("Input0") == 0);
REQUIRE(
@ -112,7 +113,7 @@ class Blend2GraphResource {
blend_node,
"Output",
blend_tree_resource->GetGraphOutputNode(),
"GraphOutput");
AnimGraphResource::DefaultAnimOutput);
}
};
@ -142,20 +143,13 @@ class EmbeddedBlendTreeGraphResource {
size_t embedded_speed_scale_index = -1;
public:
EmbeddedBlendTreeGraphResource() {
EmbeddedBlendTreeGraphResource()
: parent_graph_resource(AnimGraphType::GraphTypeBlendTree) {
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_blend_tree_resource->Reset();
parent_blend_tree_resource->InitGraphConnectors();
// Setup parent outputs
AnimNodeResource* parent_blend_tree_outputs =
parent_blend_tree_resource->GetGraphOutputNode();
parent_blend_tree_outputs->m_virtual_socket_accessor
->RegisterInput<AnimData>("Output", nullptr);
// Parent AnimSampler
walk_node_index = parent_blend_tree_resource->AddNode(
@ -215,6 +209,9 @@ class EmbeddedBlendTreeGraphResource {
"AnimOutput");
// Parent: setup connections
const AnimNodeResource* parent_blend_tree_outputs =
parent_blend_tree_resource->GetGraphOutputNode();
REQUIRE(parent_blend_tree_resource->ConnectSockets(
walk_node_resource,
"Output",
@ -259,20 +256,13 @@ class EmbeddedTreeBlend2GraphResource {
AnimNodeResource* embedded_run_node_resource = nullptr;
public:
EmbeddedTreeBlend2GraphResource() {
EmbeddedTreeBlend2GraphResource()
: parent_graph_resource(AnimGraphType::GraphTypeBlendTree) {
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_blend_tree_resource->Reset();
parent_blend_tree_resource->InitGraphConnectors();
// Setup parent outputs
AnimNodeResource* parent_blend_tree_outputs =
parent_blend_tree_resource->GetGraphOutputNode();
parent_blend_tree_outputs->m_virtual_socket_accessor
->RegisterInput<AnimData>("Output", nullptr);
// Setup parent inputs
AnimNodeResource* parent_blend_tree_inputs =
@ -303,9 +293,6 @@ class EmbeddedTreeBlend2GraphResource {
embedded_graph->m_graph_type_name = "BlendTree";
embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource;
// Embedded: outputs
embedded_graph->RegisterBlendTreeOutputSocket<AnimData>("AnimOutput");
// Embedded: inputs
embedded_graph->RegisterBlendTreeInputSocket<AnimData>("AnimInput");
embedded_graph->RegisterBlendTreeInputSocket<float>("BlendWeight");
@ -346,7 +333,7 @@ class EmbeddedTreeBlend2GraphResource {
embedded_blend2_node_resource,
"Output",
embedded_blend_tree_resource->GetGraphOutputNode(),
"AnimOutput"));
AnimGraphResource::DefaultAnimOutput));
REQUIRE(embedded_blend_tree_resource->ConnectSockets(
embedded_blend_tree_resource->GetGraphInputNode(),
"BlendWeight",
@ -354,6 +341,9 @@ class EmbeddedTreeBlend2GraphResource {
"Weight"));
// Parent: setup connections
AnimNodeResource* parent_blend_tree_outputs =
parent_blend_tree_resource->GetGraphOutputNode();
REQUIRE(parent_blend_tree_resource->ConnectSockets(
walk_node_resource,
"Output",
@ -361,9 +351,9 @@ class EmbeddedTreeBlend2GraphResource {
"AnimInput"));
REQUIRE(parent_blend_tree_resource->ConnectSockets(
embedded_graph,
"AnimOutput",
AnimGraphResource::DefaultAnimOutput,
parent_blend_tree_outputs,
"Output"));
AnimGraphResource::DefaultAnimOutput));
REQUIRE(parent_blend_tree_resource->ConnectSockets(
parent_blend_tree_inputs,
"EmbeddedBlend2Weight",
@ -477,10 +467,10 @@ TEST_CASE_METHOD(
"[SimpleAnimSamplerGraphResource]") {
graph_resource.SaveToFile("TestGraphAnimSamplerBlendTree.json");
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile("TestGraphAnimSamplerBlendTree.json");
std::unique_ptr<AnimGraphResource> graph_resource_loaded(
AnimGraphResource::CreateFromFile("TestGraphAnimSamplerBlendTree.json"));
CheckAnimGraphResourceEqual(graph_resource, graph_resource_loaded);
CheckAnimGraphResourceEqual(graph_resource, *graph_resource_loaded);
}
TEST_CASE_METHOD(
@ -530,7 +520,9 @@ TEST_CASE_METHOD(
// Ensure that outputs are properly propagated.
AnimData output;
output.m_local_matrices.resize(skeleton.num_soa_joints());
anim_graph_blend_tree.SetOutput("GraphOutput", &output);
anim_graph_blend_tree.SetOutput(
AnimGraphResource::DefaultAnimOutput,
&output);
REQUIRE(anim_sampler_walk->o_output == &output);
WHEN("Emulating Graph Evaluation") {
@ -545,13 +537,13 @@ TEST_CASE_METHOD(
// Checks that node const inputs are properly set.
//
TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
AnimGraphResource graph_resource;
graph_resource.m_name = "AnimSamplerSpeedScaleGraph";
graph_resource.m_graph_type_name = "BlendTree";
AnimGraphResourcePtr graph_resource(
dynamic_cast<AnimGraphResource*>(AnimNodeResourceFactory("BlendTree")));
graph_resource->m_name = "AnimSamplerSpeedScaleGraph";
graph_resource->m_graph_type_name = "BlendTree";
BlendTreeResource& blend_tree_resource = graph_resource.m_blend_tree_resource;
blend_tree_resource.Reset();
blend_tree_resource.InitGraphConnectors();
BlendTreeResource& blend_tree_resource =
graph_resource->m_blend_tree_resource;
// Prepare graph inputs and outputs
size_t walk_node_index =
@ -574,11 +566,6 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
"SpeedScale",
speed_scale_value);
AnimNodeResource* graph_node = blend_tree_resource.GetGraphOutputNode();
graph_node->m_virtual_socket_accessor->RegisterInput<AnimData>(
"GraphOutput",
nullptr);
blend_tree_resource
.ConnectSockets(walk_node, "Output", speed_scale_node, "Input");
@ -586,16 +573,16 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
speed_scale_node,
"Output",
blend_tree_resource.GetGraphOutputNode(),
"GraphOutput");
AnimGraphResource::DefaultAnimOutput);
graph_resource.SaveToFile(
"TestGraphAnimSamplerSpeedScaleGraph.animgraph.json");
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile(
graph_resource->SaveToFile(
"TestGraphAnimSamplerSpeedScaleGraph.animgraph.json");
AnimGraphResourcePtr graph_resource_loaded(
AnimGraphResource::CreateFromFile(
"TestGraphAnimSamplerSpeedScaleGraph.animgraph.json"));
BlendTreeResource& blend_tree_resource_loaded =
graph_resource_loaded.m_blend_tree_resource;
graph_resource_loaded->m_blend_tree_resource;
Socket* speed_scale_resource_loaded_input =
blend_tree_resource_loaded.GetNode(speed_scale_node_index)
@ -607,7 +594,7 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
Catch::Matchers::WithinAbs(speed_scale_value, 0.1));
AnimGraphBlendTree blend_tree;
graph_resource_loaded.CreateBlendTreeInstance(blend_tree);
graph_resource_loaded->CreateBlendTreeInstance(blend_tree);
REQUIRE_THAT(
*dynamic_cast<SpeedScaleNode*>(blend_tree.m_nodes[speed_scale_node_index])
@ -616,7 +603,7 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
WHEN("Checking node eval order and node subtrees") {
const std::vector<size_t>& eval_order =
graph_resource_loaded.m_blend_tree_resource.GetNodeEvalOrder();
graph_resource_loaded->m_blend_tree_resource.GetNodeEvalOrder();
THEN("Walk node gets evaluated before speed scale node") {
CHECK(eval_order.size() == 2);
@ -626,12 +613,12 @@ TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
THEN("Subtree of the speed scale node contains only the walk node") {
CHECK(
graph_resource_loaded.m_blend_tree_resource
graph_resource_loaded->m_blend_tree_resource
.m_node_inputs_subtree[speed_scale_node_index]
.size()
== 1);
CHECK(
graph_resource_loaded.m_blend_tree_resource
graph_resource_loaded->m_blend_tree_resource
.m_node_inputs_subtree[speed_scale_node_index][0]
== walk_node_index);
}
@ -651,7 +638,7 @@ TEST_CASE_METHOD(
blend_node,
"Output",
blend_tree_resource->GetGraphOutputNode(),
"GraphOutput")
AnimGraphResource::DefaultAnimOutput)
== true);
CHECK(blend_tree_resource->GetNodeEvalOrder().empty());
@ -667,7 +654,7 @@ TEST_CASE_METHOD(
speed_scale_node_resource,
"Output",
blend_tree_resource->GetGraphOutputNode(),
"GraphOutput")
AnimGraphResource::DefaultAnimOutput)
== true);
const std::vector<size_t>& tree_eval_order =
@ -694,7 +681,7 @@ TEST_CASE_METHOD(
speed_scale_node_resource,
"Output",
blend_tree_resource->GetGraphOutputNode(),
"GraphOutput"));
AnimGraphResource::DefaultAnimOutput));
CHECK(blend_tree_resource
->DisconnectSockets(walk_node, "Output", blend_node, "Input0"));
CHECK(
@ -706,19 +693,29 @@ TEST_CASE_METHOD(
== false);
}
TEST_CASE("FreeAnimGraphResource", "[Test]") {
AnimGraphResourcePtr graph_resource(
dynamic_cast<AnimGraphResource*>(AnimNodeResourceFactory("BlendTree")));
graph_resource->SaveToFile("UniqueSaveToFile.json");
AnimGraphResourcePtr graph_resource_loaded(
AnimGraphResource::CreateFromFile("UniqueSaveToFile.json"));
}
TEST_CASE_METHOD(
Blend2GraphResource,
"Blend2GraphResource saving and loading results in same resource",
"[Blend2GraphResource]") {
graph_resource.SaveToFile("TestGraphBlend2Graph.animgraph.json");
graph_resource->SaveToFile("TestGraphBlend2Graph.animgraph.json");
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile("TestGraphBlend2Graph.animgraph.json");
AnimGraphResourcePtr graph_resource_loaded(
AnimGraphResource::CreateFromFile("TestGraphBlend2Graph.animgraph.json"));
CheckAnimGraphResourceEqual(graph_resource, graph_resource_loaded);
CheckAnimGraphResourceEqual(*graph_resource, *graph_resource_loaded);
BlendTreeResource* blend_tree_resource_loaded =
&graph_resource_loaded.m_blend_tree_resource;
&graph_resource_loaded->m_blend_tree_resource;
// Check that the constant weight of the Blend2 node was properly applied when
// loading the resource.
@ -739,7 +736,7 @@ TEST_CASE_METHOD(
"Blend2GraphResource graph unsynced evaluation",
"[Blend2GraphResource]") {
AnimGraphBlendTree blend_tree_graph;
graph_resource.CreateBlendTreeInstance(blend_tree_graph);
graph_resource->CreateBlendTreeInstance(blend_tree_graph);
AnimGraphContext graph_context;
ozz::animation::Skeleton skeleton;
@ -806,8 +803,9 @@ TEST_CASE_METHOD(
CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output);
CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output);
AnimData* graph_output = static_cast<AnimData*>(
blend_tree_graph.GetOutputPtr<AnimData>("GraphOutput"));
AnimData* graph_output =
static_cast<AnimData*>(blend_tree_graph.GetOutputPtr<AnimData>(
AnimGraphResource::DefaultAnimOutput));
CHECK(
graph_output->m_local_matrices.size()
@ -837,14 +835,12 @@ TEST_CASE_METHOD(
//
//
TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
AnimGraphResource graph_resource_origin;
AnimGraphResource graph_resource_origin(AnimGraphType::GraphTypeBlendTree);
graph_resource_origin.m_name = "TestInputOutputGraph";
graph_resource_origin.m_graph_type_name = "BlendTree";
BlendTreeResource& blend_tree_resource =
graph_resource_origin.m_blend_tree_resource;
blend_tree_resource.Reset();
blend_tree_resource.InitGraphConnectors();
// Prepare graph inputs and outputs
size_t float_to_vec3_node_index = blend_tree_resource.AddNode(
@ -901,11 +897,11 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
const char* filename = "TestGraphResourceSaveLoadGraphInputs.json";
graph_resource_origin.SaveToFile(filename);
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile(filename);
AnimGraphResourcePtr graph_resource_loaded(
AnimGraphResource::CreateFromFile(filename));
BlendTreeResource& graph_blend_tree_loaded =
graph_resource_loaded.m_blend_tree_resource;
graph_resource_loaded->m_blend_tree_resource;
const AnimNodeResource* graph_loaded_output_node =
graph_blend_tree_loaded.GetGraphOutputNode();
@ -939,7 +935,7 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
WHEN("Instantiating an AnimGraph") {
AnimGraphBlendTree blend_tree_node;
graph_resource_loaded.CreateBlendTreeInstance(blend_tree_node);
graph_resource_loaded->CreateBlendTreeInstance(blend_tree_node);
float graph_float_input = 123.456f;
blend_tree_node.SetInput("GraphFloatInput", &graph_float_input);
@ -996,14 +992,12 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
// GraphFloat1Output -> GraphFLoatInputSingle * 3
//
TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
AnimGraphResource graph_resource_origin;
AnimGraphResource graph_resource_origin(AnimGraphType::GraphTypeBlendTree);
graph_resource_origin.m_name = "TestSimpleMathGraph";
graph_resource_origin.m_graph_type_name = "BlendTree";
BlendTreeResource& blend_tree_resource =
graph_resource_origin.m_blend_tree_resource;
blend_tree_resource.Reset();
blend_tree_resource.InitGraphConnectors();
// Prepare graph inputs and outputs
size_t math_add0_node_index =
@ -1084,12 +1078,12 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
const char* filename = "TestGraphResourceSaveLoadGraphInputs.json";
graph_resource_origin.SaveToFile(filename);
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.LoadFromFile(filename);
AnimGraphResourcePtr graph_resource_loaded(
AnimGraphResource::CreateFromFile(filename));
WHEN("Instantiating an AnimGraph") {
AnimGraphBlendTree blend_tree;
graph_resource_loaded.CreateBlendTreeInstance(blend_tree);
graph_resource_loaded->CreateBlendTreeInstance(blend_tree);
float graph_float_input = 123.456f;
blend_tree.SetInput("GraphFloatInput", &graph_float_input);
@ -1145,16 +1139,16 @@ TEST_CASE_METHOD(
"[EmbeddedBlendTreeGraphResource]") {
parent_graph_resource.SaveToFile("TestGraphEmbeddedBlendTree.json");
AnimGraphResource parent_graph_resource_loaded;
parent_graph_resource_loaded.LoadFromFile("TestGraphEmbeddedBlendTree.json");
AnimGraphResourcePtr parent_graph_resource_loaded(
AnimGraphResource::CreateFromFile("TestGraphEmbeddedBlendTree.json"));
// Check the loaded parent graph
CheckAnimGraphResourceEqual(
parent_graph_resource,
parent_graph_resource_loaded);
*parent_graph_resource_loaded);
const BlendTreeResource& parent_blend_tree_resource_loaded =
parent_graph_resource_loaded.m_blend_tree_resource;
parent_graph_resource_loaded->m_blend_tree_resource;
// Check the loaded embedded graph
REQUIRE(
@ -1355,4 +1349,4 @@ TEST_CASE(
CHECK(!blend_tree_graph_resource->RegisterBlendTreeOutputSocket(socket));
delete blend_tree_anim_node_resource;
}
}