Simple graph output connection working.
parent
c2ae0a11d2
commit
2b7cbe9d4c
|
@ -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,8 +486,12 @@ 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;
|
||||
target_node_accessor =
|
||||
AnimNodeAccessorFactory(target_node_type, target_node);
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue