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() if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && ImNodes::IsEditorHovered()
&& ImGui::IsMouseReleased(ImGuiMouseButton_Right)) { && ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
AnimNodeResource node_resource = AnimNodeResourceFactory("Blend2"); AnimNodeResource node_resource = AnimNodeResourceFactory("SpeedScale");
size_t node_id = gGraphResource.m_nodes.size(); size_t node_id = gGraphResource.m_nodes.size();
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos()); ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
gGraphResource.m_nodes.push_back(node_resource); gGraphResource.m_nodes.push_back(node_resource);

View File

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

View File

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

View File

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