WIP AnimGraph instantiation.
parent
c5b0d1f976
commit
c2ae0a11d2
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue