Simple graph output connection working.

AnimGraphEditor
Martin Felis 2022-02-12 11:46:50 +01:00
parent c2ae0a11d2
commit 2b7cbe9d4c
2 changed files with 58 additions and 135 deletions

View File

@ -5,6 +5,7 @@
#ifndef ANIMTESTBED_ANIMGRAPHRESOURCE_H
#define ANIMTESTBED_ANIMGRAPHRESOURCE_H
#include <cstring>
#include <iostream>
#include <map>
#include <string>
@ -54,24 +55,13 @@ struct AnimNodeResource;
struct Socket {
std::string m_name;
SocketType m_type;
union Value {
bool* flag;
AnimData* anim_data;
float* real;
Vec3* vec3;
Quat* quat;
std::string* str;
SocketType m_type = SocketType::SocketTypeUndefined;
union SocketValue {
void* ptr;
bool** flag_ptr;
AnimData** anim_data_ptr;
float** real_ptr;
float** vec3_ptr;
float** quat_ptr;
std::string** str_ptr;
void** ptr_ptr;
};
Value m_value;
SocketValue m_value = {nullptr};
size_t m_type_size = 0;
};
struct AnimNode;
@ -98,7 +88,7 @@ struct AnimNode {
};
struct NodeSocketAccessorBase {
NodeSocketAccessorBase(AnimNode* node) {}
NodeSocketAccessorBase() {}
virtual ~NodeSocketAccessorBase() {}
Socket* FindSocket(std::vector<Socket>& sockets, const std::string& name) {
@ -164,137 +154,41 @@ struct NodeSocketAccessorBase {
sockets.push_back(Socket());
socket = &sockets[sockets.size() - 1];
socket->m_name = name;
socket->m_type_size = sizeof(T);
if constexpr (std::is_same<T, float>::value) {
socket->m_value.real = value_ptr;
socket->m_type = SocketType::SocketTypeFloat;
} else if constexpr (std::is_same<T, bool>::value) {
socket->m_value.flag = value_ptr;
socket->m_type = SocketType::SocketTypeBool;
} else if constexpr (std::is_same<T, Vec3>::value) {
socket->m_value.vec3 = value_ptr;
socket->m_type = SocketType::SocketTypeVec3;
} else if constexpr (std::is_same<T, Quat>::value) {
socket->m_value.quat = value_ptr;
socket->m_type = SocketType::SocketTypeQuat;
} else if constexpr (std::is_same<T, AnimData>::value) {
socket->m_value.anim_data = value_ptr;
socket->m_type = SocketType::SocketTypeAnimation;
} else if constexpr (std::is_same<T, std::string>::value) {
socket->m_value.str = value_ptr;
socket->m_type = SocketType::SocketTypeString;
} else if constexpr (std::is_same<T, float*>::value) {
socket->m_value.real_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeFloat;
} else if constexpr (std::is_same<T, bool*>::value) {
socket->m_value.flag_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeBool;
} else if constexpr (std::is_same<T, Vec3*>::value) {
socket->m_value.vec3_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeVec3;
} else if constexpr (std::is_same<T, Quat*>::value) {
socket->m_value.quat_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeQuat;
} else if constexpr (std::is_same<T, AnimData*>::value) {
socket->m_value.anim_data_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeAnimation;
} else if constexpr (std::is_same<T, std::string*>::value) {
socket->m_value.str_ptr = value_ptr;
socket->m_type = SocketType::SocketTypeString;
} else {
std::cerr << "Cannot register socket, invalid type." << std::endl;
return false;
}
socket->m_value.ptr = value_ptr;
return true;
}
template <typename T>
bool SetSocketValue(
std::vector<Socket>& sockets,
const std::string& name,
T value) {
Socket* socket = FindSocket(sockets, name);
if (socket == nullptr) {
return false;
}
if constexpr (std::is_same<T, float>::value) {
(*socket->m_value.real) = value;
} else if constexpr (std::is_same<T, bool>::value) {
(*socket->m_value.flag) = value;
} else if constexpr (std::is_same<T, Vec3>::value) {
(*socket->m_value.vec3) = value;
} else if constexpr (std::is_same<T, Quat>::value) {
(*socket->m_value.vec3) = value;
} else if constexpr (std::is_same<T, AnimData>::value) {
(*socket->m_value.vec3) = value;
} else if constexpr (std::is_same<T, std::string>::value) {
(*socket->m_value.str) = value;
} else {
std::cerr << "Invalid type!" << std::endl;
return false;
}
return true;
}
template <typename T>
bool SetSocketRef(
std::vector<Socket>& sockets,
const std::string& name,
T* value) {
Socket* socket = FindSocket(sockets, name);
if (socket == nullptr) {
return false;
} else if constexpr (std::is_same<T, float>::value) {
(*socket->m_value.real_ptr) = value;
} else if constexpr (std::is_same<T, bool>::value) {
(*socket->m_value.flag_ptr) = value;
} else if constexpr (std::is_same<T, Vec3>::value) {
(*socket->m_value.vec3_ptr) = value;
} else if constexpr (std::is_same<T, Quat>::value) {
(*socket->m_value.quat_ptr) = value;
} else if constexpr (std::is_same<T, AnimData>::value) {
(*socket->m_value.anim_data_ptr) = value;
} else if constexpr (std::is_same<T, std::string>::value) {
(*socket->m_value.str_ptr) = value;
} else {
std::cerr << "Invalid type!" << std::endl;
return false;
}
return true;
}
template <typename T>
T* GetSocketValue(
std::vector<Socket>& sockets,
const std::string& name,
T* default_value) {
Socket* socket = FindSocket(sockets, name);
if (socket == nullptr) {
return default_value;
}
if constexpr (std::is_same<T, float>::value) {
return socket->m_value.real;
} else if constexpr (std::is_same<T, Vec3>::value) {
return socket->m_value.vec3;
} else if constexpr (std::is_same<T, bool>::value) {
return socket->m_value.flag;
} else if constexpr (std::is_same<T, Quat>::value) {
return socket->m_value.vec3;
} else if constexpr (std::is_same<T, AnimData>::value) {
return socket->m_value.anim_data;
} else if constexpr (std::is_same<T, std::string>::value) {
return socket->m_value.str;
}
std::cerr << "Invalid type!" << std::endl;
return nullptr;
}
template <typename T>
bool RegisterProperty(const std::string& name, T* value) {
return RegisterSocket(m_properties, name, value);
@ -316,10 +210,6 @@ struct NodeSocketAccessorBase {
return RegisterSocket(m_inputs, name, value);
}
template <typename T>
bool SetInput(const std::string& name, T value) {
return SetSocketValue(m_inputs, name, value);
}
template <typename T>
T* GetInput(const std::string& name, T* value) {
return GetSocketValue(m_inputs, name, value);
}
@ -337,10 +227,6 @@ struct NodeSocketAccessorBase {
bool RegisterOutput(const std::string& name, T** value) {
return RegisterSocket(m_outputs, name, value);
}
template <typename T>
bool SetOutputRef(const std::string& name, T* value) {
return SetSocketRef(m_outputs, name, value);
}
SocketType GetOutputType(const std::string& name) {
return GetSocketType(m_outputs, name);
}
@ -372,7 +258,7 @@ struct BlendTreeNode : public AnimNode {};
template <>
struct NodeSocketAccessor<BlendTreeNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {}
NodeSocketAccessor(AnimNode* node_) {}
};
struct Blend2Node : public AnimNode {
@ -385,7 +271,7 @@ struct Blend2Node : public AnimNode {
template <>
struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {
NodeSocketAccessor(AnimNode* node_) {
Blend2Node* node = dynamic_cast<Blend2Node*>(node_);
RegisterInput("Input0", &node->m_input0);
RegisterInput("Input1", &node->m_input1);
@ -405,7 +291,7 @@ struct SpeedScaleNode : public AnimNode {
template <>
struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {
NodeSocketAccessor(AnimNode* node_) {
SpeedScaleNode* node = dynamic_cast<SpeedScaleNode*>(node_);
RegisterInput("SpeedScale", &node->m_speed_scale);
RegisterInput("Input", &node->m_input);
@ -421,7 +307,7 @@ struct AnimSamplerNode : public AnimNode {
template <>
struct NodeSocketAccessor<AnimSamplerNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {
NodeSocketAccessor(AnimNode* node_) {
AnimSamplerNode* node = dynamic_cast<AnimSamplerNode*>(node_);
RegisterOutput("Output", &node->m_output);
@ -516,6 +402,9 @@ struct AnimGraph {
AnimData m_local_transforms;
std::vector<AnimNode*> m_nodes;
std::vector<std::vector<AnimNode*> > m_node_inputs;
NodeSocketAccessorBase* m_socket_accessor;
char* m_input_buffer = nullptr;
char* m_output_buffer = nullptr;
AnimNode* getAnimNode(const char* name) {
for (size_t i = 0; i < m_nodes.size(); i++) {
@ -540,6 +429,8 @@ struct AnimGraph {
static AnimGraph createFromResource(const AnimGraphResource& resource) {
AnimGraph result;
// create nodes
for (int i = 0; i < resource.m_nodes.size(); i++) {
const AnimNodeResource& node_resource = resource.m_nodes[i];
AnimNode* node = AnimNodeFactory(node_resource.m_type_name.c_str());
@ -549,6 +440,27 @@ struct AnimGraph {
result.m_node_inputs.push_back(std::vector<AnimNode*>());
}
// Prepare graph inputs
const AnimNodeResource& graph_node = resource.m_nodes[0];
result.m_socket_accessor = AnimNodeAccessorFactory("BlendTree", result.m_nodes[0]);
int input_block_size = 0;
const std::vector<Socket>& graph_inputs =
graph_node.m_socket_accessor->m_inputs;
for (int i = 0; i < graph_inputs.size(); i++) {
input_block_size += graph_inputs[i].m_type_size;
}
result.m_input_buffer = new char[input_block_size];
memset(result.m_input_buffer, 0, input_block_size);
int input_block_offset = 0;
for (int i = 0; i < graph_inputs.size(); i++) {
if (graph_inputs[i].m_type == SocketType::SocketTypeAnimation) {
result.m_socket_accessor->RegisterInput<AnimData>(graph_inputs[i].m_name, static_cast<AnimData*>( (void*) &result.m_input_buffer[input_block_offset]));
}
input_block_offset += graph_inputs[i].m_type_size;
}
// connect the nodes
for (int i = 0; i < resource.m_connections.size(); i++) {
const AnimGraphConnection& connection = resource.m_connections[i];
std::string source_node_type = "";
@ -574,9 +486,13 @@ struct AnimGraph {
target_node = result.m_nodes[connection.m_target_node_index];
target_node_name = target_node->m_name;
target_node_type = target_node->m_node_type_name;
if (connection.m_target_node_index == 0) {
target_node_accessor = result.m_socket_accessor;
} else {
target_node_accessor =
AnimNodeAccessorFactory(target_node_type, target_node);
}
}
assert(source_node != nullptr);
assert(target_node != nullptr);

View File

@ -27,7 +27,7 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
walk_node.m_name = "BlendWalkRun";
AnimNodeResource& graph_node = graph_resource.m_nodes[0];
graph_node.m_socket_accessor->RegisterInput<AnimData>("Output", nullptr);
graph_node.m_socket_accessor->RegisterInput<AnimData>("GraphOutput", nullptr);
REQUIRE(graph_node.m_socket_accessor->m_inputs.size() == 1);
REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input0") == 0);
@ -57,7 +57,7 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
blend_node.m_socket_accessor->GetOutputIndex("Output");
blend_to_output.m_target_node_index = 0;
blend_to_output.m_target_socket_index =
graph_node.m_socket_accessor->GetInputIndex("Output");
graph_node.m_socket_accessor->GetInputIndex("GraphOutput");
graph_resource.m_connections.push_back(blend_to_output);
graph_resource.saveToFile("WalkGraph.animgraph.json");
@ -70,12 +70,13 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
<< std::endl;
}
CHECK(graph.m_nodes.size() == 4);
CHECK(graph.m_nodes[0]->m_node_type_name == "Graph");
CHECK(graph.m_nodes[1]->m_node_type_name == "AnimSampler");
CHECK(graph.m_nodes[2]->m_node_type_name == "AnimSampler");
CHECK(graph.m_nodes[3]->m_node_type_name == "Blend2");
REQUIRE(graph.m_nodes.size() == 4);
REQUIRE(graph.m_nodes[0]->m_node_type_name == "BlendTree");
REQUIRE(graph.m_nodes[1]->m_node_type_name == "AnimSampler");
REQUIRE(graph.m_nodes[2]->m_node_type_name == "AnimSampler");
REQUIRE(graph.m_nodes[3]->m_node_type_name == "Blend2");
// connections within the graph
AnimSamplerNode* anim_sampler_instance0 =
dynamic_cast<AnimSamplerNode*>(graph.m_nodes[1]);
AnimSamplerNode* anim_sampler_instance1 =
@ -84,6 +85,12 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
CHECK(anim_sampler_instance0->m_output == &blend2_instance->m_input0);
CHECK(anim_sampler_instance1->m_output == &blend2_instance->m_input1);
// connections from graph to the graph node
CHECK(graph.m_socket_accessor->m_inputs.size() == 1);
CHECK(graph.m_socket_accessor->FindInputSocket("GraphOutput"));
CHECK(reinterpret_cast<char*>(blend2_instance->m_output) == graph.m_input_buffer);
// check node input dependencies
size_t anim_sampler_index0 = graph.getAnimNodeIndex(anim_sampler_instance0);
size_t anim_sampler_index1 = graph.getAnimNodeIndex(anim_sampler_instance1);
size_t blend_index = graph.getAnimNodeIndex(blend2_instance);