WIP AnimGraph instantiation.

AnimGraphEditor
Martin Felis 2022-02-12 10:14:26 +01:00
parent c5b0d1f976
commit c2ae0a11d2
4 changed files with 138 additions and 46 deletions

View File

@ -43,7 +43,7 @@ void AnimGraphEditorUpdate() {
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && ImNodes::IsEditorHovered()
&& ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
AnimNodeResource node_resource = AnimNodeResourceFactory("Blend2");
AnimNodeResource node_resource = AnimNodeResourceFactory("SpeedScale");
size_t node_id = gGraphResource.m_nodes.size();
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
gGraphResource.m_nodes.push_back(node_resource);

View File

@ -88,6 +88,9 @@ AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) {
void AnimGraphResource::clear() {
m_name = "";
m_nodes.clear();
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
m_connections.clear();
}

View File

@ -62,12 +62,14 @@ struct Socket {
Vec3* vec3;
Quat* quat;
std::string* str;
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;
};
@ -111,16 +113,43 @@ struct NodeSocketAccessorBase {
return result;
}
const Socket* FindSocket(
const std::vector<Socket>& sockets,
const std::string& name) const {
const Socket* result = nullptr;
for (size_t i = 0, n = sockets.size(); i < n; i++) {
if (sockets[i].m_name == name) {
result = &sockets[i];
break;
}
}
return result;
}
SocketType GetSocketType(
const std::vector<Socket> sockets,
const std::vector<Socket>& sockets,
const std::string& name) {
Socket* socket = FindSocket(m_properties, name);
const Socket* socket = FindSocket(sockets, name);
if (socket == nullptr) {
return SocketType::SocketTypeUndefined;
}
return socket->m_type;
}
size_t GetSocketIndex(
const std::vector<Socket>& sockets,
const std::string& name) const {
for (size_t i = 0, n = sockets.size(); i < n; i++) {
std::cout << i << ", " << sockets[i].m_name << std::endl;
if (sockets[i].m_name == name) {
return i;
}
}
return -1;
}
template <typename T>
bool RegisterSocket(
std::vector<Socket>& sockets,
@ -294,9 +323,15 @@ struct NodeSocketAccessorBase {
T* GetInput(const std::string& name, T* value) {
return GetSocketValue(m_inputs, name, value);
}
Socket* FindInputSocket(const std::string& name) {
return FindSocket(m_inputs, name);
}
SocketType GetInputType(const std::string& name) {
return GetSocketType(m_inputs, name);
}
size_t GetInputIndex(const std::string& name) {
return GetSocketIndex(m_inputs, name);
}
template <typename T>
bool RegisterOutput(const std::string& name, T** value) {
@ -309,6 +344,12 @@ struct NodeSocketAccessorBase {
SocketType GetOutputType(const std::string& name) {
return GetSocketType(m_outputs, name);
}
Socket* FindOutputSocket(const std::string& name) {
return FindSocket(m_outputs, name);
}
size_t GetOutputIndex(const std::string& name) {
return GetSocketIndex(m_outputs, name);
}
std::vector<Socket> m_properties;
std::vector<Socket> m_inputs;
@ -327,6 +368,13 @@ struct NodeRegistry {
AnimNode* node);
};
struct BlendTreeNode : public AnimNode {};
template <>
struct NodeSocketAccessor<BlendTreeNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) : NodeSocketAccessorBase(node_) {}
};
struct Blend2Node : public AnimNode {
AnimData m_input0;
AnimData m_input1;
@ -392,21 +440,41 @@ struct AnimGraphResource {
std::string m_name;
std::vector<AnimNodeResource> m_nodes;
std::vector<AnimGraphConnection> m_connections;
std::vector<Socket> m_inputs;
std::vector<Socket> m_outputs;
~AnimGraphResource() {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
delete m_nodes[i].m_anim_node;
delete m_nodes[i].m_socket_accessor;
}
}
AnimGraphResource() { clear(); }
void clear();
bool saveToFile(const char* filename) const;
bool loadFromFile(const char* filename);
size_t addNode(AnimNodeResource node_resource) {
m_nodes.push_back(node_resource);
return m_nodes.size() - 1;
}
};
static inline AnimNode* AnimNodeFactory(const std::string& name) {
AnimNode* result;
if (name == "Blend2") {
return new Blend2Node;
result = new Blend2Node;
} else if (name == "SpeedScale") {
return new SpeedScaleNode;
result = new SpeedScaleNode;
} else if (name == "AnimSampler") {
return new AnimSamplerNode;
result = new AnimSamplerNode;
} else if (name == "BlendTree") {
result = new BlendTreeNode;
}
if (result != nullptr) {
result->m_node_type_name = name;
return result;
}
std::cerr << "Invalid node type: " << name << std::endl;
@ -422,6 +490,8 @@ static inline NodeSocketAccessorBase* AnimNodeAccessorFactory(
return new NodeSocketAccessor<SpeedScaleNode>(node);
} else if (node_type_name == "AnimSampler") {
return new NodeSocketAccessor<AnimSamplerNode>(node);
} else if (node_type_name == "BlendTree") {
return new NodeSocketAccessor<BlendTreeNode>(node);
} else {
std::cerr << "Invalid node type name " << node_type_name << "."
<< std::endl;
@ -529,23 +599,26 @@ struct AnimGraph {
continue;
}
if (source_node_accessor->m_outputs[connection.m_source_socket_index].m_type
!= target_node_accessor->m_inputs[connection.m_target_socket_index].m_type) {
if (source_node_accessor->m_outputs[connection.m_source_socket_index]
.m_type
!= target_node_accessor->m_inputs[connection.m_target_socket_index]
.m_type) {
std::cerr << "Invalid connection connecting nodes '" << source_node_name
<< "' and '" << target_node_name << "'." << std::endl;
return result;
}
// TODO! How to wire up the different types?
// std::string socket_name = connection.m_target_socket_name;
// AnimData* input_ref =
// target_node_accessor->GetInput<AnimData>(socket_name, nullptr);
// source_node_accessor->SetOutputRef(
// connection.m_source_socket_name,
// input_ref);
Socket* source_socket =
&source_node_accessor->m_outputs[connection.m_source_socket_index];
Socket* target_socket =
&target_node_accessor->m_inputs[connection.m_target_socket_index];
if (source_socket->m_type != target_socket->m_type) {
std::cerr << "Cannot connect sockets: invalid types!" << std::endl;
}
(*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
size_t target_node_index = result.getAnimNodeIndex(target_node);
result.m_node_inputs[target_node_index].push_back(source_node);
}

View File

@ -8,41 +8,56 @@
TEST_CASE("BasicGraph", "[AnimGraphResource]") {
AnimGraphResource graph_resource;
graph_resource.clear();
graph_resource.m_name = "WalkRunBlendGraph";
AnimNodeResource walk_node;
// Prepare graph inputs and outputs
size_t walk_node_index =
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
size_t run_node_index =
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
size_t blend_node_index =
graph_resource.addNode(AnimNodeResourceFactory("Blend2"));
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
walk_node.m_name = "WalkAnim";
walk_node.m_type_name = "AnimSampler";
graph_resource.m_nodes.push_back(walk_node);
AnimNodeResource& run_node = graph_resource.m_nodes[run_node_index];
walk_node.m_name = "RunAnim";
AnimNodeResource& blend_node = graph_resource.m_nodes[blend_node_index];
walk_node.m_name = "BlendWalkRun";
AnimNodeResource run_node;
run_node.m_name = "RunAnim";
run_node.m_type_name = "AnimSampler";
graph_resource.m_nodes.push_back(run_node);
AnimNodeResource& graph_node = graph_resource.m_nodes[0];
graph_node.m_socket_accessor->RegisterInput<AnimData>("Output", nullptr);
AnimNodeResource blend_node;
blend_node.m_name = "BlendWalkRun";
blend_node.m_type_name = "Blend2";
graph_resource.m_nodes.push_back(blend_node);
REQUIRE(graph_node.m_socket_accessor->m_inputs.size() == 1);
REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input0") == 0);
REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input1") == 1);
AnimGraphConnection walk_to_blend;
walk_to_blend.m_source_node = &walk_node;
walk_to_blend.m_source_socket_name = "Output";
walk_to_blend.m_target_node = &blend_node;
walk_to_blend.m_target_socket_name = "Input0";
walk_to_blend.m_source_node_index = walk_node_index;
walk_to_blend.m_source_socket_index =
walk_node.m_socket_accessor->GetOutputIndex("Output");
walk_to_blend.m_target_node_index = blend_node_index;
walk_to_blend.m_target_socket_index =
blend_node.m_socket_accessor->GetInputIndex("Input0");
graph_resource.m_connections.push_back(walk_to_blend);
AnimGraphConnection run_to_blend;
run_to_blend.m_source_node = &run_node;
run_to_blend.m_source_socket_name = "Output";
run_to_blend.m_target_node = &blend_node;
run_to_blend.m_target_socket_name = "Input1";
run_to_blend.m_source_node_index = run_node_index;
run_to_blend.m_source_socket_index =
run_node.m_socket_accessor->GetOutputIndex("Output");
run_to_blend.m_target_node_index = blend_node_index;
run_to_blend.m_target_socket_index =
blend_node.m_socket_accessor->GetInputIndex("Input1");
graph_resource.m_connections.push_back(run_to_blend);
AnimGraphConnection blend_to_output;
blend_to_output.m_source_node = &blend_node;
blend_to_output.m_source_socket_name = "Output";
blend_to_output.m_target_socket_name = "GraphOutput";
blend_to_output.m_source_node_index = blend_node_index;
blend_to_output.m_source_socket_index =
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_resource.m_connections.push_back(blend_to_output);
graph_resource.saveToFile("WalkGraph.animgraph.json");
@ -55,16 +70,17 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
<< std::endl;
}
CHECK(graph.m_nodes.size() == 3);
CHECK(graph.m_nodes[0]->m_node_type_name == "AnimSampler");
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 == "Blend2");
CHECK(graph.m_nodes[2]->m_node_type_name == "AnimSampler");
CHECK(graph.m_nodes[3]->m_node_type_name == "Blend2");
AnimSamplerNode* anim_sampler_instance0 =
dynamic_cast<AnimSamplerNode*>(graph.m_nodes[0]);
AnimSamplerNode* anim_sampler_instance1 =
dynamic_cast<AnimSamplerNode*>(graph.m_nodes[1]);
Blend2Node* blend2_instance = dynamic_cast<Blend2Node*>(graph.m_nodes[2]);
AnimSamplerNode* anim_sampler_instance1 =
dynamic_cast<AnimSamplerNode*>(graph.m_nodes[2]);
Blend2Node* blend2_instance = dynamic_cast<Blend2Node*>(graph.m_nodes[3]);
CHECK(anim_sampler_instance0->m_output == &blend2_instance->m_input0);
CHECK(anim_sampler_instance1->m_output == &blend2_instance->m_input1);