Compare commits

..

3 Commits

Author SHA1 Message Date
Martin Felis
73e7a60875 Minor cleanup. 2022-02-24 23:47:31 +01:00
Martin Felis
976875c218 Added index member to node, preparing synctrack and node evaluation. 2022-02-24 22:55:40 +01:00
Martin Felis
d6453911e2 Removed node input splitting. 2022-02-24 22:06:47 +01:00
4 changed files with 179 additions and 142 deletions

View File

@ -7,7 +7,7 @@
#include "AnimGraphResource.h" #include "AnimGraphResource.h"
#include "imnodes.h" #include "imnodes.h"
using namespace AnimGraphCode; using namespace AniGraph;
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) { ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
switch (socket_type) { switch (socket_type) {

View File

@ -8,7 +8,7 @@
#include "3rdparty/json/json.hpp" #include "3rdparty/json/json.hpp"
namespace AnimGraphCode { namespace AniGraph {
using json = nlohmann::json; using json = nlohmann::json;
@ -351,7 +351,7 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
return true; return true;
} }
void AnimGraph::UpdateOrderedNodes() { void AnimGraph::updateOrderedNodes() {
std::vector<int> node_index_stack; std::vector<int> node_index_stack;
node_index_stack.push_back(0); node_index_stack.push_back(0);
@ -359,7 +359,7 @@ void AnimGraph::UpdateOrderedNodes() {
while (node_index_stack.size() > 0) { while (node_index_stack.size() > 0) {
std::vector<NodeInput>& node_inputs = std::vector<NodeInput>& node_inputs =
m_node_anim_inputs[node_index_stack.back()]; m_node_inputs[node_index_stack.back()];
node_index_stack.pop_back(); node_index_stack.pop_back();
for (size_t i = 0, n = node_inputs.size(); i < n; i++) { for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
@ -368,7 +368,7 @@ void AnimGraph::UpdateOrderedNodes() {
continue; continue;
} }
int input_node_index = getAnimNodeIndex(input_node); int input_node_index = input_node->m_index;
bool is_node_processed = false; bool is_node_processed = false;
for (size_t j = 0, m = m_eval_ordered_nodes.size(); j < m; j++) { for (size_t j = 0, m = m_eval_ordered_nodes.size(); j < m; j++) {
if (m_eval_ordered_nodes[j] == input_node) { if (m_eval_ordered_nodes[j] == input_node) {
@ -387,7 +387,7 @@ void AnimGraph::UpdateOrderedNodes() {
} }
} }
void AnimGraph::MarkActiveNodes() { void AnimGraph::markActiveNodes() {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
m_nodes[i]->m_state = AnimNodeEvalState::Deactivated; m_nodes[i]->m_state = AnimNodeEvalState::Deactivated;
} }
@ -403,9 +403,9 @@ void AnimGraph::MarkActiveNodes() {
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
AnimNode* node = m_eval_ordered_nodes[i]; AnimNode* node = m_eval_ordered_nodes[i];
if (CheckIsNodeActive(node)) { if (checkIsNodeActive(node)) {
int node_index = getAnimNodeIndex(node); int node_index = node->m_index;
node->MarkActiveInputs(m_node_anim_inputs[node_index]); node->MarkActiveInputs(m_node_inputs[node_index]);
// Non-animation data inputs are always active. // Non-animation data inputs are always active.
for (size_t j = 0, nj = m_node_inputs[node_index].size(); j < nj; j++) { for (size_t j = 0, nj = m_node_inputs[node_index].size(); j < nj; j++) {
@ -418,8 +418,20 @@ void AnimGraph::MarkActiveNodes() {
} }
} }
void AnimGraph::UpdateTime(float dt) { void AnimGraph::evalSyncTracks() {
const std::vector<NodeInput> graph_output_inputs = m_node_anim_inputs[0]; for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
AnimNode* node = m_eval_ordered_nodes[i];
int node_index = node->m_index;
if (node->m_state == AnimNodeEvalState::Deactivated) {
continue;
}
node->CalcSyncTrack(m_node_inputs[node_index]);
}
}
void AnimGraph::updateTime(float dt) {
const std::vector<NodeInput> graph_output_inputs = m_node_inputs[0];
for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) { for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) {
AnimNode* node = m_eval_ordered_nodes[i]; AnimNode* node = m_eval_ordered_nodes[i];
if (node != nullptr) { if (node != nullptr) {
@ -433,15 +445,18 @@ void AnimGraph::UpdateTime(float dt) {
continue; continue;
} }
int node_index = getAnimNodeIndex(node); int node_index = node->m_index;
const std::vector<NodeInput> node_anim_inputs = const std::vector<NodeInput> node_inputs =
m_node_anim_inputs[node_index]; m_node_inputs[node_index];
float node_time_now = node->m_time_now; float node_time_now = node->m_time_now;
float node_time_last = node->m_time_last; float node_time_last = node->m_time_last;
for (size_t i = 0, n = node_anim_inputs.size(); i < n; i++) { for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
AnimNode* input_node = node_anim_inputs[i].m_node; AnimNode* input_node = node_inputs[i].m_node;
// Only propagate time updates via animation sockets.
if (input_node != nullptr if (input_node != nullptr
&& node_inputs[i].m_type == SocketType::SocketTypeAnimation
&& input_node->m_state == AnimNodeEvalState::Activated) { && input_node->m_state == AnimNodeEvalState::Activated) {
input_node->UpdateTime(node_time_last, node_time_now); input_node->UpdateTime(node_time_last, node_time_now);
} }
@ -449,7 +464,18 @@ void AnimGraph::UpdateTime(float dt) {
} }
} }
void* AnimGraph::GetOutput(const std::string& name) const { void AnimGraph::evaluate() {
for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
AnimNode* node = m_eval_ordered_nodes[i];
if (node->m_state == AnimNodeEvalState::Deactivated) {
continue;
}
node->Evaluate();
}
}
void* AnimGraph::getOutput(const std::string& name) const {
Socket* socket = m_socket_accessor->FindInputSocket(name); Socket* socket = m_socket_accessor->FindInputSocket(name);
if (socket == nullptr) { if (socket == nullptr) {
return nullptr; return nullptr;
@ -458,7 +484,7 @@ void* AnimGraph::GetOutput(const std::string& name) const {
return socket->m_value.ptr; return socket->m_value.ptr;
} }
void* AnimGraph::GetInput(const std::string& name) const { void* AnimGraph::getInput(const std::string& name) const {
Socket* socket = m_socket_accessor->FindOutputSocket(name); Socket* socket = m_socket_accessor->FindOutputSocket(name);
if (socket == nullptr) { if (socket == nullptr) {
return nullptr; return nullptr;
@ -467,4 +493,4 @@ void* AnimGraph::GetInput(const std::string& name) const {
return *(socket->m_value.ptr_ptr); return *(socket->m_value.ptr_ptr);
} }
} // namespace AnimGraphCode } // namespace AniGraph

View File

@ -14,19 +14,11 @@
#include "SyncTrack.h" #include "SyncTrack.h"
namespace AnimGraphCode { namespace AniGraph {
enum class SocketType { //
SocketTypeUndefined, // Data types
SocketTypeBool, //
SocketTypeAnimation,
SocketTypeFloat,
SocketTypeVec3,
SocketTypeQuat,
SocketTypeString
};
enum SocketFlags { SocketFlagAffectsTime = 1 };
struct AnimData { struct AnimData {
float m_bone_transforms[16]; float m_bone_transforms[16];
@ -55,7 +47,18 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) {
*output_index = (attribute_id >> 23) - 1; *output_index = (attribute_id >> 23) - 1;
} }
struct AnimNodeResource;
enum class SocketType {
SocketTypeUndefined,
SocketTypeBool,
SocketTypeAnimation,
SocketTypeFloat,
SocketTypeVec3,
SocketTypeQuat,
SocketTypeString
};
enum SocketFlags { SocketFlagAffectsTime = 1 };
struct Socket { struct Socket {
std::string m_name; std::string m_name;
@ -77,7 +80,6 @@ struct AnimNodeResource {
std::string m_type_name; std::string m_type_name;
AnimNode* m_anim_node = nullptr; AnimNode* m_anim_node = nullptr;
NodeSocketAccessorBase* m_socket_accessor = nullptr; NodeSocketAccessorBase* m_socket_accessor = nullptr;
float m_position[2] = {0.f, 0.f}; float m_position[2] = {0.f, 0.f};
}; };
@ -98,6 +100,14 @@ enum class AnimNodeEvalState {
}; };
struct AnimNode { struct AnimNode {
std::string m_name;
std::string m_node_type_name;
float m_time_now = 0.f;
float m_time_last = 0.f;
size_t m_index = -1;
AnimNodeEvalState m_state = AnimNodeEvalState::Undefined;
SyncTrack m_sync_track;
virtual ~AnimNode(){}; virtual ~AnimNode(){};
virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) { virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) {
@ -109,22 +119,33 @@ struct AnimNode {
} }
} }
virtual void CalcSyncTrack(const std::vector<NodeInput>& inputs) {
for (size_t i = 0, n = inputs.size(); i < n; i++) {
AnimNode* input_node = inputs[i].m_node;
if (input_node != nullptr
&& inputs[i].m_type == SocketType::SocketTypeAnimation
&& input_node->m_state != AnimNodeEvalState::Deactivated) {
m_sync_track = input_node->m_sync_track;
return;
}
}
}
virtual void UpdateTime(float time_last, float time_now) { virtual void UpdateTime(float time_last, float time_now) {
m_time_last = time_last; m_time_last = time_last;
m_time_now = time_now; m_time_now = time_now;
m_state = AnimNodeEvalState::TimeUpdated; m_state = AnimNodeEvalState::TimeUpdated;
} }
std::string m_name; virtual void Evaluate() {};
std::string m_node_type_name;
float m_time_now = 0.f;
float m_time_last = 0.f;
AnimNodeEvalState m_state = AnimNodeEvalState::Undefined;
SyncTrack m_sync_track;
}; };
struct NodeSocketAccessorBase { struct NodeSocketAccessorBase {
std::vector<Socket> m_properties;
std::vector<Socket> m_inputs;
std::vector<Socket> m_outputs;
NodeSocketAccessorBase() {} NodeSocketAccessorBase() {}
virtual ~NodeSocketAccessorBase() {} virtual ~NodeSocketAccessorBase() {}
@ -304,10 +325,6 @@ struct NodeSocketAccessorBase {
size_t GetOutputIndex(const std::string& name) { size_t GetOutputIndex(const std::string& name) {
return GetSocketIndex(m_outputs, name); return GetSocketIndex(m_outputs, name);
} }
std::vector<Socket> m_properties;
std::vector<Socket> m_inputs;
std::vector<Socket> m_outputs;
}; };
template <typename T> template <typename T>
@ -322,6 +339,9 @@ struct NodeRegistry {
AnimNode* node); AnimNode* node);
}; };
//
// BlendTreeNode
//
struct BlendTreeNode : public AnimNode {}; struct BlendTreeNode : public AnimNode {};
template <> template <>
@ -329,6 +349,9 @@ struct NodeSocketAccessor<BlendTreeNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) {} NodeSocketAccessor(AnimNode* node_) {}
}; };
//
// Blend2Node
//
struct Blend2Node : public AnimNode { struct Blend2Node : public AnimNode {
AnimData m_input0; AnimData m_input0;
AnimData m_input1; AnimData m_input1;
@ -336,7 +359,6 @@ struct Blend2Node : public AnimNode {
float m_blend_weight = 0.f; float m_blend_weight = 0.f;
bool m_sync_blend = false; bool m_sync_blend = false;
virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) override { virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) override {
for (size_t i = 0, n = inputs.size(); i < n; i++) { for (size_t i = 0, n = inputs.size(); i < n; i++) {
AnimNode* input_node = inputs[i].m_node; AnimNode* input_node = inputs[i].m_node;
@ -406,6 +428,9 @@ struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
} }
}; };
//
// SpeedScaleNode
//
struct SpeedScaleNode : public AnimNode { struct SpeedScaleNode : public AnimNode {
AnimData m_input; AnimData m_input;
AnimData* m_output = nullptr; AnimData* m_output = nullptr;
@ -432,6 +457,9 @@ struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
} }
}; };
//
// AnimSamplerNode
//
struct AnimSamplerNode : public AnimNode { struct AnimSamplerNode : public AnimNode {
AnimData* m_output = nullptr; AnimData* m_output = nullptr;
std::string m_filename; std::string m_filename;
@ -447,6 +475,9 @@ struct NodeSocketAccessor<AnimSamplerNode> : public NodeSocketAccessorBase {
} }
}; };
//
// AnimGraphResource
//
struct AnimGraphConnection { struct AnimGraphConnection {
int m_source_node_index; int m_source_node_index;
int m_source_socket_index; int m_source_socket_index;
@ -475,7 +506,6 @@ struct AnimGraphResource {
bool loadFromFile(const char* filename); bool loadFromFile(const char* filename);
AnimNodeResource& getGraphOutputNode() { return m_nodes[0]; } AnimNodeResource& getGraphOutputNode() { return m_nodes[0]; }
AnimNodeResource& getGraphInputNode() { return m_nodes[1]; } AnimNodeResource& getGraphInputNode() { return m_nodes[1]; }
size_t addNode(AnimNodeResource node_resource) { size_t addNode(AnimNodeResource node_resource) {
@ -581,7 +611,22 @@ static inline AnimNodeResource AnimNodeResourceFactory(
return result; return result;
} }
//
// AnimGraph (Runtime)
//
struct AnimGraph { struct AnimGraph {
AnimData m_local_transforms;
std::vector<AnimNode*> m_nodes;
std::vector<AnimNode*> m_eval_ordered_nodes;
std::vector<std::vector<NodeInput> > m_node_inputs;
NodeSocketAccessorBase* m_socket_accessor;
char* m_input_buffer = nullptr;
char* m_output_buffer = nullptr;
std::vector<Socket>& getGraphOutputs() { return m_socket_accessor->m_inputs; }
std::vector<Socket>& getGraphInputs() { return m_socket_accessor->m_outputs; }
~AnimGraph() { ~AnimGraph() {
delete[] m_input_buffer; delete[] m_input_buffer;
delete[] m_output_buffer; delete[] m_output_buffer;
@ -593,14 +638,15 @@ struct AnimGraph {
delete m_socket_accessor; delete m_socket_accessor;
} }
void UpdateOrderedNodes(); void updateOrderedNodes();
void MarkActiveNodes(); void markActiveNodes();
bool CheckIsNodeActive(AnimNode* node) { bool checkIsNodeActive(AnimNode* node) {
return node->m_state != AnimNodeEvalState::Deactivated; return node->m_state != AnimNodeEvalState::Deactivated;
} }
void UpdateTime(float dt); void evalSyncTracks();
void Evaluate(); void updateTime(float dt);
void Reset() { void evaluate();
void reset() {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
m_nodes[i]->m_time_now = 0.f; m_nodes[i]->m_time_now = 0.f;
m_nodes[i]->m_time_last = 0.f; m_nodes[i]->m_time_last = 0.f;
@ -608,21 +654,9 @@ struct AnimGraph {
} }
} }
AnimData m_local_transforms;
std::vector<AnimNode*> m_nodes; void* getOutput(const std::string& name) const;
std::vector<AnimNode*> m_eval_ordered_nodes; void* getInput(const std::string& name) const;
std::vector<std::vector<NodeInput> > m_node_inputs;
std::vector<std::vector<NodeInput> > m_node_anim_inputs;
NodeSocketAccessorBase* m_socket_accessor;
char* m_input_buffer = nullptr;
char* m_output_buffer = nullptr;
std::vector<Socket>& GetGraphOutputs() { return m_socket_accessor->m_inputs; }
std::vector<Socket>& GetGraphInputs() { return m_socket_accessor->m_outputs; }
void* GetOutput(const std::string& name) const;
void* GetInput(const std::string& name) const;
int getNodeEvalOrderIndex(const AnimNode* node) { int getNodeEvalOrderIndex(const AnimNode* node) {
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
@ -637,9 +671,9 @@ struct AnimGraph {
size_t node_index, size_t node_index,
const std::string& input_name) { const std::string& input_name) {
assert(node_index < m_nodes.size()); assert(node_index < m_nodes.size());
assert(node_index < m_node_anim_inputs.size()); assert(node_index < m_node_inputs.size());
std::vector<NodeInput>& node_inputs = m_node_anim_inputs[node_index]; std::vector<NodeInput>& node_inputs = m_node_inputs[node_index];
for (size_t i = 0, n = node_inputs.size(); i < n; i++) { for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
if (node_inputs[i].m_input_name == input_name) { if (node_inputs[i].m_input_name == input_name) {
return node_inputs[i].m_node; return node_inputs[i].m_node;
@ -659,17 +693,6 @@ struct AnimGraph {
return nullptr; return nullptr;
} }
size_t getAnimNodeIndex(AnimNode* node) {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
if (m_nodes[i] == node) {
return i;
}
}
std::cerr << "Could not find node " << node << "." << std::endl;
return -1;
}
static AnimGraph createFromResource(const AnimGraphResource& resource) { static AnimGraph createFromResource(const AnimGraphResource& resource) {
AnimGraph result; AnimGraph result;
@ -679,13 +702,12 @@ struct AnimGraph {
AnimNode* node = AnimNodeFactory(node_resource.m_type_name.c_str()); AnimNode* node = AnimNodeFactory(node_resource.m_type_name.c_str());
node->m_name = node_resource.m_name; node->m_name = node_resource.m_name;
node->m_node_type_name = node_resource.m_type_name; node->m_node_type_name = node_resource.m_type_name;
node->m_index = i;
result.m_nodes.push_back(node); result.m_nodes.push_back(node);
assert(node_resource.m_socket_accessor != nullptr); assert(node_resource.m_socket_accessor != nullptr);
result.m_node_inputs.push_back(std::vector<NodeInput>()); result.m_node_inputs.push_back(std::vector<NodeInput>());
std::vector<NodeInput>& node_inputs = result.m_node_inputs.back(); std::vector<NodeInput>& node_inputs = result.m_node_inputs.back();
result.m_node_anim_inputs.push_back(std::vector<NodeInput>());
std::vector<NodeInput>& node_anim_inputs = result.m_node_anim_inputs.back();
for (int j = 0, n = node_resource.m_socket_accessor->m_inputs.size(); for (int j = 0, n = node_resource.m_socket_accessor->m_inputs.size();
j < n; j < n;
@ -699,10 +721,6 @@ struct AnimGraph {
input.m_input_name = input_socket.m_name; input.m_input_name = input_socket.m_name;
node_inputs.push_back(input); node_inputs.push_back(input);
if (input_socket.m_type == SocketType::SocketTypeAnimation) {
node_anim_inputs.push_back(input);
}
} }
} }
@ -716,7 +734,7 @@ struct AnimGraph {
// inputs // inputs
int input_block_size = 0; int input_block_size = 0;
std::vector<Socket>& graph_inputs = result.GetGraphInputs(); std::vector<Socket>& graph_inputs = result.getGraphInputs();
for (int i = 0; i < graph_inputs.size(); i++) { for (int i = 0; i < graph_inputs.size(); i++) {
input_block_size += sizeof(void*); input_block_size += sizeof(void*);
} }
@ -734,7 +752,7 @@ struct AnimGraph {
// outputs // outputs
int output_block_size = 0; int output_block_size = 0;
std::vector<Socket>& graph_outputs = result.GetGraphOutputs(); std::vector<Socket>& graph_outputs = result.getGraphOutputs();
for (int i = 0; i < graph_outputs.size(); i++) { for (int i = 0; i < graph_outputs.size(); i++) {
output_block_size += graph_outputs[i].m_type_size; output_block_size += graph_outputs[i].m_type_size;
} }
@ -828,7 +846,7 @@ struct AnimGraph {
(*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr; (*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
size_t target_node_index = result.getAnimNodeIndex(target_node); size_t target_node_index = target_node->m_index;
std::vector<NodeInput>& node_inputs = std::vector<NodeInput>& node_inputs =
result.m_node_inputs[target_node_index]; result.m_node_inputs[target_node_index];
@ -838,14 +856,6 @@ struct AnimGraph {
} }
} }
std::vector<NodeInput>& node_anim_inputs =
result.m_node_anim_inputs[target_node_index];
for (int j = 0, n = node_anim_inputs.size(); j < n; j++) {
if (node_anim_inputs[j].m_input_name == target_socket->m_name) {
node_anim_inputs[j].m_node = source_node;
}
}
if (target_node_accessor != result.m_socket_accessor) { if (target_node_accessor != result.m_socket_accessor) {
delete target_node_accessor; delete target_node_accessor;
} }
@ -855,13 +865,13 @@ struct AnimGraph {
} }
} }
result.UpdateOrderedNodes(); result.updateOrderedNodes();
result.Reset(); result.reset();
return result; return result;
} }
}; };
} // namespace AnimGraphCode } // namespace AniGraph
#endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H #endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H

View File

@ -5,7 +5,7 @@
#include "AnimGraphResource.h" #include "AnimGraphResource.h"
#include "catch.hpp" #include "catch.hpp"
using namespace AnimGraphCode; using namespace AniGraph;
TEST_CASE("BasicGraph", "[AnimGraphResource]") { TEST_CASE("BasicGraph", "[AnimGraphResource]") {
AnimGraphResource graph_resource; AnimGraphResource graph_resource;
@ -87,18 +87,19 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
CHECK(graph.m_socket_accessor->FindInputSocket("GraphOutput")); CHECK(graph.m_socket_accessor->FindInputSocket("GraphOutput"));
CHECK( CHECK(
reinterpret_cast<char*>(blend2_instance->m_output) reinterpret_cast<char*>(blend2_instance->m_output)
== graph.GetOutput("GraphOutput")); == graph.getOutput("GraphOutput"));
// check node input dependencies // check node input dependencies
size_t anim_sampler_index0 = graph.getAnimNodeIndex(anim_sampler_instance0); size_t anim_sampler_index0 = anim_sampler_instance0->m_index;
size_t anim_sampler_index1 = graph.getAnimNodeIndex(anim_sampler_instance1); size_t anim_sampler_index1 = anim_sampler_instance1->m_index;
size_t blend_index = graph.getAnimNodeIndex(blend2_instance); size_t blend_index = blend2_instance->m_index;
CHECK(graph.m_node_anim_inputs[anim_sampler_index0].size() == 0); CHECK(graph.m_node_inputs[anim_sampler_index0].size() == 0);
CHECK(graph.m_node_anim_inputs[anim_sampler_index1].size() == 0); CHECK(graph.m_node_inputs[anim_sampler_index1].size() == 0);
CHECK(graph.m_node_anim_inputs[blend_index].size() == 2); CHECK(graph.m_node_inputs[blend_index].size() == 3);
CHECK(graph.m_node_anim_inputs[blend_index][0].m_node == anim_sampler_instance0); CHECK(graph.m_node_inputs[blend_index][0].m_node == anim_sampler_instance0);
CHECK(graph.m_node_anim_inputs[blend_index][1].m_node == anim_sampler_instance1); CHECK(graph.m_node_inputs[blend_index][1].m_node == anim_sampler_instance1);
CHECK(graph.m_node_inputs[blend_index][2].m_node == nullptr);
} }
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") { TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
@ -193,14 +194,14 @@ TEST_CASE("ResourceSaveLoadGraphInputs", "[AnimGraphResource]") {
AnimGraph anim_graph = AnimGraph anim_graph =
AnimGraph::createFromResource(graph_resource_loaded); AnimGraph::createFromResource(graph_resource_loaded);
REQUIRE( REQUIRE(
anim_graph.GetOutput("GraphOutput") == anim_graph.m_output_buffer); anim_graph.getOutput("GraphOutput") == anim_graph.m_output_buffer);
REQUIRE( REQUIRE(
anim_graph.GetOutput("SomeFloatOutput") anim_graph.getOutput("SomeFloatOutput")
== anim_graph.m_output_buffer + sizeof(AnimData)); == anim_graph.m_output_buffer + sizeof(AnimData));
REQUIRE(anim_graph.GetInput("GraphAnimInput") == nullptr); REQUIRE(anim_graph.getInput("GraphAnimInput") == nullptr);
REQUIRE(anim_graph.GetInput("GraphFloatInput") == nullptr); REQUIRE(anim_graph.getInput("GraphFloatInput") == nullptr);
REQUIRE(anim_graph.GetInput("GraphBoolInput") == nullptr); REQUIRE(anim_graph.getInput("GraphBoolInput") == nullptr);
} }
} }
@ -216,15 +217,15 @@ TEST_CASE("ResourceSaveLoadGraphInputs", "[AnimGraphResource]") {
AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource_origin); AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource_origin);
void* graph_anim_input_ptr = anim_graph.GetInput("GraphAnimInput"); void* graph_anim_input_ptr = anim_graph.getInput("GraphAnimInput");
void* graph_output_ptr = anim_graph.GetOutput("GraphOutput"); void* graph_output_ptr = anim_graph.getOutput("GraphOutput");
REQUIRE(graph_anim_input_ptr == graph_output_ptr); REQUIRE(graph_anim_input_ptr == graph_output_ptr);
REQUIRE(graph_output_ptr == anim_graph.m_output_buffer); REQUIRE(graph_output_ptr == anim_graph.m_output_buffer);
REQUIRE( REQUIRE(
anim_graph.GetInput("GraphAnimInput") anim_graph.getInput("GraphAnimInput")
== anim_graph.GetOutput("GraphOutput")); == anim_graph.getOutput("GraphOutput"));
} }
} }
@ -266,12 +267,12 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource);
THEN("Writing to the input pointer changes the value of the output.") { THEN("Writing to the input pointer changes the value of the output.") {
float* float_input_ptr = (float*)anim_graph.GetInput("GraphFloatInput"); float* float_input_ptr = (float*)anim_graph.getInput("GraphFloatInput");
REQUIRE(float_input_ptr != nullptr); REQUIRE(float_input_ptr != nullptr);
*float_input_ptr = 23.123f; *float_input_ptr = 23.123f;
float* float_output_ptr = float* float_output_ptr =
(float*)anim_graph.GetOutput("GraphFloatOutput"); (float*)anim_graph.getOutput("GraphFloatOutput");
REQUIRE(float_output_ptr != nullptr); REQUIRE(float_output_ptr != nullptr);
CHECK(*float_output_ptr == Approx(23.123f)); CHECK(*float_output_ptr == Approx(23.123f));
} }
@ -297,7 +298,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
REQUIRE( REQUIRE(
*anim_graph.m_socket_accessor->m_outputs[0].m_value.ptr_ptr *anim_graph.m_socket_accessor->m_outputs[0].m_value.ptr_ptr
== &blend2_node->m_blend_weight); == &blend2_node->m_blend_weight);
float* float_input_ptr = (float*)anim_graph.GetInput("GraphFloatInput"); float* float_input_ptr = (float*)anim_graph.getInput("GraphFloatInput");
REQUIRE(float_input_ptr == &blend2_node->m_blend_weight); REQUIRE(float_input_ptr == &blend2_node->m_blend_weight);
} }
@ -330,21 +331,21 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]); dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]);
AnimData* graph_input0 = AnimData* graph_input0 =
(AnimData*)anim_graph.GetInput("GraphAnimInput0"); (AnimData*)anim_graph.getInput("GraphAnimInput0");
REQUIRE(graph_input0 == &blend2_node->m_input0); REQUIRE(graph_input0 == &blend2_node->m_input0);
REQUIRE( REQUIRE(
anim_graph.m_nodes[1] anim_graph.m_nodes[1]
== anim_graph.getAnimNodeForInput(blend2_node_index, "Input0")); == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0"));
AnimData* graph_input1 = AnimData* graph_input1 =
(AnimData*)anim_graph.GetInput("GraphAnimInput1"); (AnimData*)anim_graph.getInput("GraphAnimInput1");
REQUIRE(graph_input1 == &blend2_node->m_input1); REQUIRE(graph_input1 == &blend2_node->m_input1);
REQUIRE( REQUIRE(
anim_graph.m_nodes[1] anim_graph.m_nodes[1]
== anim_graph.getAnimNodeForInput(blend2_node_index, "Input1")); == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1"));
AnimData* graph_output = AnimData* graph_output =
(AnimData*)anim_graph.GetOutput("GraphAnimOutput"); (AnimData*)anim_graph.getOutput("GraphAnimOutput");
REQUIRE(graph_output == blend2_node->m_output); REQUIRE(graph_output == blend2_node->m_output);
REQUIRE( REQUIRE(
anim_graph.m_nodes[blend2_node_index] anim_graph.m_nodes[blend2_node_index]
@ -417,14 +418,14 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
// check connectivity // check connectivity
// //
AnimData* graph_input0 = AnimData* graph_input0 =
(AnimData*)anim_graph.GetInput("GraphAnimInput0"); (AnimData*)anim_graph.getInput("GraphAnimInput0");
REQUIRE(graph_input0 == &blend2_node->m_input0); REQUIRE(graph_input0 == &blend2_node->m_input0);
REQUIRE( REQUIRE(
anim_graph.m_nodes[1] anim_graph.m_nodes[1]
== anim_graph.getAnimNodeForInput(blend2_node_index, "Input0")); == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0"));
AnimData* graph_input1 = AnimData* graph_input1 =
(AnimData*)anim_graph.GetInput("GraphAnimInput1"); (AnimData*)anim_graph.getInput("GraphAnimInput1");
REQUIRE(graph_input1 == nullptr); REQUIRE(graph_input1 == nullptr);
REQUIRE(sampler_node->m_output == &speed_scale_node->m_input); REQUIRE(sampler_node->m_output == &speed_scale_node->m_input);
@ -438,7 +439,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
== anim_graph.getAnimNodeForInput(blend2_node_index, "Input1")); == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1"));
AnimData* graph_output = AnimData* graph_output =
(AnimData*)anim_graph.GetOutput("GraphAnimOutput"); (AnimData*)anim_graph.getOutput("GraphAnimOutput");
REQUIRE(graph_output == blend2_node->m_output); REQUIRE(graph_output == blend2_node->m_output);
REQUIRE( REQUIRE(
anim_graph.m_nodes[blend2_node_index] anim_graph.m_nodes[blend2_node_index]
@ -461,7 +462,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN("Instantiating graph") { WHEN("Instantiating graph") {
AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource); AnimGraph anim_graph = AnimGraph::createFromResource(graph_resource);
float* blend_weight_input = float* blend_weight_input =
reinterpret_cast<float*>(anim_graph.GetInput("GraphFloatInput")); reinterpret_cast<float*>(anim_graph.getInput("GraphFloatInput"));
Blend2Node* blend2_node = Blend2Node* blend2_node =
dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]); dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]);
@ -472,43 +473,43 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN("Setting weight to 0. and marking nodes active.") { WHEN("Setting weight to 0. and marking nodes active.") {
*blend_weight_input = 0.; *blend_weight_input = 0.;
anim_graph.MarkActiveNodes(); anim_graph.markActiveNodes();
THEN("Speed scale and sampler node are inactive") { THEN("Speed scale and sampler node are inactive") {
REQUIRE(anim_graph.CheckIsNodeActive(speed_scale_node) == false); REQUIRE(anim_graph.checkIsNodeActive(speed_scale_node) == false);
REQUIRE(anim_graph.CheckIsNodeActive(sampler_node) == false); REQUIRE(anim_graph.checkIsNodeActive(sampler_node) == false);
} }
} }
WHEN("Setting weight to 0. and marking nodes active") { WHEN("Setting weight to 0. and marking nodes active") {
*blend_weight_input = 0.1; *blend_weight_input = 0.1;
anim_graph.MarkActiveNodes(); anim_graph.markActiveNodes();
THEN("Speed scale and sampler nodes are active") { THEN("Speed scale and sampler nodes are active") {
REQUIRE(anim_graph.CheckIsNodeActive(speed_scale_node) == true); REQUIRE(anim_graph.checkIsNodeActive(speed_scale_node) == true);
REQUIRE(anim_graph.CheckIsNodeActive(sampler_node) == true); REQUIRE(anim_graph.checkIsNodeActive(sampler_node) == true);
} }
} }
WHEN("Setting weight to 1. and marking nodes active") { WHEN("Setting weight to 1. and marking nodes active") {
*blend_weight_input = 1.0; *blend_weight_input = 1.0;
anim_graph.MarkActiveNodes(); anim_graph.markActiveNodes();
THEN("Speed scale and sampler nodes are active") { THEN("Speed scale and sampler nodes are active") {
REQUIRE(anim_graph.CheckIsNodeActive(speed_scale_node) == true); REQUIRE(anim_graph.checkIsNodeActive(speed_scale_node) == true);
REQUIRE(anim_graph.CheckIsNodeActive(sampler_node) == true); REQUIRE(anim_graph.checkIsNodeActive(sampler_node) == true);
} }
} }
WHEN("Updating time with dt = 0.3f and speed scale = 1.0f") { WHEN("Updating time with dt = 0.3f and speed scale = 1.0f") {
float* speed_scale_input = float* speed_scale_input =
reinterpret_cast<float*>(anim_graph.GetInput("SpeedScaleInput")); reinterpret_cast<float*>(anim_graph.getInput("SpeedScaleInput"));
*blend_weight_input = 0.1; *blend_weight_input = 0.1;
*speed_scale_input = 1.0f; *speed_scale_input = 1.0f;
anim_graph.MarkActiveNodes(); anim_graph.markActiveNodes();
anim_graph.UpdateTime(0.3f); anim_graph.updateTime(0.3f);
THEN ("Anim sampler node time now must be 0.3f") { THEN ("Anim sampler node time now must be 0.3f") {
REQUIRE(sampler_node->m_time_now == Approx(0.3f)); REQUIRE(sampler_node->m_time_now == Approx(0.3f));
@ -517,13 +518,13 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN("Updating time with dt = 0.3f and speed scale = 1.3f") { WHEN("Updating time with dt = 0.3f and speed scale = 1.3f") {
float* speed_scale_input = float* speed_scale_input =
reinterpret_cast<float*>(anim_graph.GetInput("SpeedScaleInput")); reinterpret_cast<float*>(anim_graph.getInput("SpeedScaleInput"));
*blend_weight_input = 0.1; *blend_weight_input = 0.1;
*speed_scale_input = 1.3f; *speed_scale_input = 1.3f;
anim_graph.MarkActiveNodes(); anim_graph.markActiveNodes();
anim_graph.UpdateTime(0.3f); anim_graph.updateTime(0.3f);
THEN ("Anim sampler node time now must be 0.39f") { THEN ("Anim sampler node time now must be 0.39f") {
REQUIRE(sampler_node->m_time_now == Approx(0.39f)); REQUIRE(sampler_node->m_time_now == Approx(0.39f));