Use socket pointers instead of indices for connections.

AnimGraphEditor
Martin Felis 2022-03-25 11:23:03 +01:00
parent 84a9ef6f14
commit 72a67195e6
3 changed files with 125 additions and 99 deletions

View File

@ -173,28 +173,36 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
// //
// AnimGraphConnection <-> Json // AnimGraphConnection <-> Json
// //
json sAnimGraphConnectionToJson(const AnimGraphConnection& connection) { json sAnimGraphConnectionToJson(const AnimGraphResource& graph_resource, const AnimGraphConnection& connection) {
json result; json result;
result["type"] = "AnimGraphConnection"; result["type"] = "AnimGraphConnection";
result["source_node_index"] = connection.m_source_node_index; const AnimNodeResource* source_node = connection.m_source_node;
result["source_socket_index"] = connection.m_source_socket_index; result["source_node_index"] = graph_resource.getNodeIndex(*source_node);
result["source_socket_index"] = source_node->m_socket_accessor->GetOutputIndex(connection.m_source_socket->m_name);
result["target_node_index"] = connection.m_target_node_index; const AnimNodeResource* target_node = connection.m_source_node;
result["target_socket_index"] = connection.m_target_socket_index; result["source_node_index"] = graph_resource.getNodeIndex(*target_node);
result["source_socket_index"] = target_node->m_socket_accessor->GetInputIndex(connection.m_target_node->m_name);
return result; return result;
} }
AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) { AnimGraphConnection sAnimGraphConnectionFromJson(const AnimGraphResource& graph_resource, const json& json_node) {
AnimGraphConnection connection; AnimGraphConnection connection;
connection.m_source_node_index = json_node["source_node_index"]; int source_node_index = json_node["source_node_index"];
connection.m_source_socket_index = json_node["source_socket_index"]; connection.m_source_node = &graph_resource.m_nodes[source_node_index];
int source_socket_index = json_node["source_socket_index"];
connection.m_source_socket = &connection.m_source_node->m_socket_accessor->m_outputs[source_socket_index];
connection.m_target_node_index = json_node["target_node_index"];
connection.m_target_socket_index = json_node["target_socket_index"]; int target_node_index = json_node["target_node_index"];
connection.m_target_node = &graph_resource.m_nodes[target_node_index];
int target_socket_index = json_node["target_socket_index"];
connection.m_target_socket = &connection.m_target_node->m_socket_accessor->m_outputs[target_socket_index];
return connection; return connection;
} }
@ -238,7 +246,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const {
for (size_t i = 0; i < m_connections.size(); i++) { for (size_t i = 0; i < m_connections.size(); i++) {
const AnimGraphConnection& connection = m_connections[i]; const AnimGraphConnection& connection = m_connections[i];
result["connections"][i] = sAnimGraphConnectionToJson(connection); result["connections"][i] = sAnimGraphConnectionToJson(*this, connection);
} }
// Graph inputs and outputs // Graph inputs and outputs
@ -288,6 +296,8 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
clearNodes(); clearNodes();
m_name = json_data["name"]; m_name = json_data["name"];
// Load nodes
for (size_t i = 0; i < json_data["nodes"].size(); i++) { for (size_t i = 0; i < json_data["nodes"].size(); i++) {
const json& json_node = json_data["nodes"][i]; const json& json_node = json_data["nodes"][i];
if (json_node["type"] != "AnimNodeResource") { if (json_node["type"] != "AnimNodeResource") {
@ -300,7 +310,23 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
AnimNodeResource node = sAnimGraphNodeFromJson(json_node); AnimNodeResource node = sAnimGraphNodeFromJson(json_node);
m_nodes.push_back(node); m_nodes.push_back(node);
} }
// Setup graph inputs and outputs
const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (size_t i = 0; i < graph_outputs.size(); i++) {
AnimNodeResource& graph_node = m_nodes[0];
graph_node.m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_outputs[i]));
}
const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (size_t i = 0; i < graph_inputs.size(); i++) {
AnimNodeResource& graph_node = m_nodes[1];
graph_node.m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_inputs[i]));
}
// Load connections
for (size_t i = 0; i < json_data["connections"].size(); i++) { for (size_t i = 0; i < json_data["connections"].size(); i++) {
const json& json_connection = json_data["connections"][i]; const json& json_connection = json_data["connections"][i];
if (json_connection["type"] != "AnimGraphConnection") { if (json_connection["type"] != "AnimGraphConnection") {
@ -311,24 +337,10 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
} }
AnimGraphConnection connection = AnimGraphConnection connection =
sAnimGraphConnectionFromJson(json_connection); sAnimGraphConnectionFromJson(*this, json_connection);
m_connections.push_back(connection); m_connections.push_back(connection);
} }
const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (size_t i = 0; i < graph_outputs.size(); i++) {
AnimNodeResource& graph_node = m_nodes[0];
graph_node.m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_outputs[i]));
}
const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (size_t i = 0; i < graph_inputs.size(); i++) {
AnimNodeResource& graph_node = m_nodes[1];
graph_node.m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_inputs[i]));
}
return true; return true;
} }

View File

@ -47,7 +47,6 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) {
*output_index = (attribute_id >> 23) - 1; *output_index = (attribute_id >> 23) - 1;
} }
enum class SocketType { enum class SocketType {
SocketTypeUndefined = 0, SocketTypeUndefined = 0,
SocketTypeBool, SocketTypeBool,
@ -59,9 +58,8 @@ enum class SocketType {
SocketTypeLast SocketTypeLast
}; };
static const char* SocketTypeNames[] = { static const char* SocketTypeNames[] =
"", "Bool", "Animation", "Float", "Vec3", "Quat", "String" {"", "Bool", "Animation", "Float", "Vec3", "Quat", "String"};
};
enum SocketFlags { SocketFlagAffectsTime = 1 }; enum SocketFlags { SocketFlagAffectsTime = 1 };
@ -88,7 +86,6 @@ struct AnimNodeResource {
float m_position[2] = {0.f, 0.f}; float m_position[2] = {0.f, 0.f};
}; };
struct NodeInput { struct NodeInput {
AnimNode* m_node; AnimNode* m_node;
SocketType m_type = SocketType::SocketTypeUndefined; SocketType m_type = SocketType::SocketTypeUndefined;
@ -142,10 +139,9 @@ struct AnimNode {
m_state = AnimNodeEvalState::TimeUpdated; m_state = AnimNodeEvalState::TimeUpdated;
} }
virtual void Evaluate() {}; virtual void Evaluate(){};
}; };
struct NodeSocketAccessorBase { struct NodeSocketAccessorBase {
std::vector<Socket> m_properties; std::vector<Socket> m_properties;
std::vector<Socket> m_inputs; std::vector<Socket> m_inputs;
@ -484,10 +480,10 @@ struct NodeSocketAccessor<AnimSamplerNode> : public NodeSocketAccessorBase {
// AnimGraphResource // AnimGraphResource
// //
struct AnimGraphConnection { struct AnimGraphConnection {
int m_source_node_index; const AnimNodeResource* m_source_node = nullptr;
int m_source_socket_index; const Socket* m_source_socket = nullptr;
int m_target_node_index; const AnimNodeResource* m_target_node = nullptr;
int m_target_socket_index; const Socket* m_target_socket = nullptr;
}; };
struct AnimGraphResource { struct AnimGraphResource {
@ -516,7 +512,7 @@ struct AnimGraphResource {
const AnimNodeResource& getGraphOutputNode() const { return m_nodes[0]; } const AnimNodeResource& getGraphOutputNode() const { return m_nodes[0]; }
const AnimNodeResource& getGraphInputNode() const { return m_nodes[1]; } const AnimNodeResource& getGraphInputNode() const { return m_nodes[1]; }
size_t getNodeIndex (const AnimNodeResource& node_resource) const { size_t getNodeIndex(const AnimNodeResource& node_resource) const {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
if (&m_nodes[i] == &node_resource) { if (&m_nodes[i] == &node_resource) {
return i; return i;
@ -533,9 +529,9 @@ struct AnimGraphResource {
bool connectSockets( bool connectSockets(
const AnimNodeResource& source_node, const AnimNodeResource& source_node,
const std::string& source_socket, const std::string& source_socket_name,
const AnimNodeResource& target_node, const AnimNodeResource& target_node,
const std::string& target_socket) { const std::string& target_socket_name) {
size_t source_index = -1; size_t source_index = -1;
size_t target_index = -1; size_t target_index = -1;
for (size_t i = 0, n = m_nodes.size(); i < n; i++) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
@ -557,23 +553,21 @@ struct AnimGraphResource {
return false; return false;
} }
size_t source_socket_index = Socket* source_socket =
source_node.m_socket_accessor->GetOutputIndex(source_socket); source_node.m_socket_accessor->FindOutputSocket(source_socket_name);
size_t target_socket_index = Socket* target_socket =
target_node.m_socket_accessor->GetInputIndex(target_socket); target_node.m_socket_accessor->FindInputSocket(target_socket_name);
if (source_socket_index >= source_node.m_socket_accessor->m_outputs.size() if (source_socket == nullptr || target_socket == nullptr) {
|| target_socket_index
>= target_node.m_socket_accessor->m_inputs.size()) {
std::cerr << "Cannot connect nodes: could not find sockets." << std::endl; std::cerr << "Cannot connect nodes: could not find sockets." << std::endl;
return false; return false;
} }
AnimGraphConnection connection; AnimGraphConnection connection;
connection.m_source_node_index = source_index; connection.m_source_node = &source_node;
connection.m_source_socket_index = source_socket_index; connection.m_source_socket = source_socket;
connection.m_target_node_index = target_index; connection.m_target_node = &target_node;
connection.m_target_socket_index = target_socket_index; connection.m_target_socket = target_socket;
m_connections.push_back(connection); m_connections.push_back(connection);
return true; return true;
@ -672,7 +666,6 @@ struct AnimGraph {
} }
} }
void* getOutput(const std::string& name) const; void* getOutput(const std::string& name) const;
void* getInput(const std::string& name) const; void* getInput(const std::string& name) const;
@ -799,12 +792,19 @@ struct AnimGraph {
NodeSocketAccessorBase* target_node_accessor = nullptr; NodeSocketAccessorBase* target_node_accessor = nullptr;
SocketType source_type; SocketType source_type;
SocketType target_type; SocketType target_type;
size_t source_socket_index = -1;
size_t target_socket_index = -1;
if (connection.m_source_node_index >= 0) { if (connection.m_source_node != nullptr) {
source_node = result.m_nodes[connection.m_source_node_index]; size_t node_index = resource.getNodeIndex(*connection.m_source_node);
if (node_index == -1) {
std::cerr << "Could not find source node index." << std::endl;
continue;
}
source_node = result.m_nodes[node_index];
source_node_name = source_node->m_name; source_node_name = source_node->m_name;
source_node_type = source_node->m_node_type_name; source_node_type = source_node->m_node_type_name;
if (connection.m_source_node_index == 1) { if (node_index == 1) {
source_node_accessor = result.m_socket_accessor; source_node_accessor = result.m_socket_accessor;
} else { } else {
source_node_accessor = source_node_accessor =
@ -812,11 +812,16 @@ struct AnimGraph {
} }
} }
if (connection.m_target_node_index >= 0) { if (connection.m_target_node != nullptr) {
target_node = result.m_nodes[connection.m_target_node_index]; size_t node_index = resource.getNodeIndex(*connection.m_target_node);
if (node_index == -1) {
std::cerr << "Could not find source node index." << std::endl;
continue;
}
target_node = result.m_nodes[node_index];
target_node_name = target_node->m_name; target_node_name = target_node->m_name;
target_node_type = target_node->m_node_type_name; target_node_type = target_node->m_node_type_name;
if (connection.m_target_node_index == 0) { if (node_index == 0) {
target_node_accessor = result.m_socket_accessor; target_node_accessor = result.m_socket_accessor;
} else { } else {
target_node_accessor = target_node_accessor =
@ -827,41 +832,50 @@ struct AnimGraph {
assert(source_node != nullptr); assert(source_node != nullptr);
assert(target_node != nullptr); assert(target_node != nullptr);
if (connection.m_source_socket_index //
> source_node_accessor->m_outputs.size()) { // Map resource node sockets to graph instance node sockets
std::cerr << "Invalid source socket index " //
<< connection.m_source_socket_index << ". Only " if (connection.m_source_socket == nullptr) {
<< source_node_accessor->m_outputs.size() std::cerr << "Invalid source socket for connection " << i << "."
<< " output sockets found." << std::endl; << std::endl;
continue; continue;
} }
if (connection.m_target_socket_index if (connection.m_target_socket == nullptr) {
> target_node_accessor->m_inputs.size()) { std::cerr << "Invalid source socket for connection " << i << "."
std::cerr << "Invalid source socket index " << std::endl;
<< connection.m_target_socket_index << ". Only "
<< source_node_accessor->m_inputs.size()
<< " input sockets found." << std::endl;
continue; continue;
} }
if (source_node_accessor->m_outputs[connection.m_source_socket_index] source_socket_index = source_node_accessor->GetOutputIndex(
.m_type connection.m_source_socket->m_name);
!= target_node_accessor->m_inputs[connection.m_target_socket_index] if (source_socket_index == -1) {
.m_type) { std::cerr << "Invalid source socket "
std::cerr << "Invalid connection connecting nodes '" << source_node_name << connection.m_source_socket->m_name << " for node "
<< "' and '" << target_node_name << "'." << std::endl; << connection.m_source_node->m_name << "." << std::endl;
return result; continue;
} }
const Socket* source_socket =
&source_node_accessor->m_outputs[source_socket_index];
target_socket_index = target_node_accessor->GetInputIndex(
connection.m_target_socket->m_name);
if (target_socket_index == -1) {
std::cerr << "Invalid target socket "
<< connection.m_target_socket->m_name << " for node "
<< connection.m_target_node->m_name << "." << std::endl;
continue;
}
const Socket* target_socket =
&target_node_accessor->m_inputs[target_socket_index];
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) { if (source_socket->m_type != target_socket->m_type) {
std::cerr << "Cannot connect sockets: invalid types!" << std::endl; std::cerr << "Cannot connect sockets: invalid types!" << std::endl;
} }
//
// Wire up outputs to inputs.
//
(*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr; (*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
size_t target_node_index = target_node->m_index; size_t target_node_index = target_node->m_index;

View File

@ -36,30 +36,30 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input1") == 1); REQUIRE(blend_node.m_socket_accessor->GetInputIndex("Input1") == 1);
AnimGraphConnection walk_to_blend; AnimGraphConnection walk_to_blend;
walk_to_blend.m_source_node_index = walk_node_index; walk_to_blend.m_source_node = &walk_node;
walk_to_blend.m_source_socket_index = walk_to_blend.m_source_socket =
walk_node.m_socket_accessor->GetOutputIndex("Output"); walk_node.m_socket_accessor->FindOutputSocket("Output");
walk_to_blend.m_target_node_index = blend_node_index; walk_to_blend.m_target_node = &blend_node;
walk_to_blend.m_target_socket_index = walk_to_blend.m_target_socket =
blend_node.m_socket_accessor->GetInputIndex("Input0"); blend_node.m_socket_accessor->FindInputSocket("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_index = run_node_index; run_to_blend.m_source_node = &run_node;
run_to_blend.m_source_socket_index = run_to_blend.m_source_socket =
run_node.m_socket_accessor->GetOutputIndex("Output"); run_node.m_socket_accessor->FindOutputSocket("Output");
run_to_blend.m_target_node_index = blend_node_index; run_to_blend.m_target_node = &blend_node;
run_to_blend.m_target_socket_index = run_to_blend.m_target_socket =
blend_node.m_socket_accessor->GetInputIndex("Input1"); blend_node.m_socket_accessor->FindInputSocket("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_index = blend_node_index; blend_to_output.m_source_node = &blend_node;
blend_to_output.m_source_socket_index = blend_to_output.m_source_socket =
blend_node.m_socket_accessor->GetOutputIndex("Output"); blend_node.m_socket_accessor->FindOutputSocket("Output");
blend_to_output.m_target_node_index = 0; blend_to_output.m_target_node = &graph_resource.m_nodes[0];
blend_to_output.m_target_socket_index = blend_to_output.m_target_socket =
graph_node.m_socket_accessor->GetInputIndex("GraphOutput"); graph_node.m_socket_accessor->FindInputSocket("GraphOutput");
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");