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