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
//
json sAnimGraphConnectionToJson(const AnimGraphConnection& connection) {
json sAnimGraphConnectionToJson(const AnimGraphResource& graph_resource, const AnimGraphConnection& connection) {
json result;
result["type"] = "AnimGraphConnection";
result["source_node_index"] = connection.m_source_node_index;
result["source_socket_index"] = connection.m_source_socket_index;
const AnimNodeResource* source_node = connection.m_source_node;
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;
result["target_socket_index"] = connection.m_target_socket_index;
const AnimNodeResource* target_node = connection.m_source_node;
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;
}
AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) {
AnimGraphConnection sAnimGraphConnectionFromJson(const AnimGraphResource& graph_resource, const json& json_node) {
AnimGraphConnection connection;
connection.m_source_node_index = json_node["source_node_index"];
connection.m_source_socket_index = json_node["source_socket_index"];
int source_node_index = json_node["source_node_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;
}
@ -238,7 +246,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const {
for (size_t i = 0; i < m_connections.size(); i++) {
const AnimGraphConnection& connection = m_connections[i];
result["connections"][i] = sAnimGraphConnectionToJson(connection);
result["connections"][i] = sAnimGraphConnectionToJson(*this, connection);
}
// Graph inputs and outputs
@ -288,6 +296,8 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
clearNodes();
m_name = json_data["name"];
// Load nodes
for (size_t i = 0; i < json_data["nodes"].size(); i++) {
const json& json_node = json_data["nodes"][i];
if (json_node["type"] != "AnimNodeResource") {
@ -301,20 +311,7 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
m_nodes.push_back(node);
}
for (size_t i = 0; i < json_data["connections"].size(); i++) {
const json& json_connection = json_data["connections"][i];
if (json_connection["type"] != "AnimGraphConnection") {
std::cerr << "Invalid json object. Expected type 'AnimGraphConnection' "
"but got '"
<< json_connection["type"] << "'." << std::endl;
return false;
}
AnimGraphConnection connection =
sAnimGraphConnectionFromJson(json_connection);
m_connections.push_back(connection);
}
// 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];
@ -329,6 +326,21 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
sJsonToSocket(graph_inputs[i]));
}
// Load connections
for (size_t i = 0; i < json_data["connections"].size(); i++) {
const json& json_connection = json_data["connections"][i];
if (json_connection["type"] != "AnimGraphConnection") {
std::cerr << "Invalid json object. Expected type 'AnimGraphConnection' "
"but got '"
<< json_connection["type"] << "'." << std::endl;
return false;
}
AnimGraphConnection connection =
sAnimGraphConnectionFromJson(*this, json_connection);
m_connections.push_back(connection);
}
return true;
}

View File

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