Nodes can now be deleted in the blend tree editor.
This commit is contained in:
@@ -192,9 +192,6 @@ AnimNodeResource* sAnimGraphNodeFromJson(
|
||||
result->m_position[0] = json_node["position"][0];
|
||||
result->m_position[1] = json_node["position"][1];
|
||||
|
||||
result->m_virtual_socket_accessor =
|
||||
VirtualAnimNodeDescriptorFactory(result->m_node_type_name);
|
||||
|
||||
for (auto& property : result->m_virtual_socket_accessor->m_properties) {
|
||||
property = sJsonToSocket(json_node["properties"][property.m_name]);
|
||||
}
|
||||
@@ -310,6 +307,9 @@ static bool sAnimGraphResourceBlendTreeFromJson(
|
||||
result_graph_resource->m_position[0] = json_data["position"][0];
|
||||
result_graph_resource->m_position[1] = json_data["position"][1];
|
||||
|
||||
// Clear all nodes as we overwrite them here anyway.
|
||||
blend_tree_resource.ClearAllNodes();
|
||||
|
||||
// Load nodes
|
||||
for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) {
|
||||
const json& json_node = json_data["nodes"][i];
|
||||
@@ -367,6 +367,76 @@ static bool sAnimGraphResourceBlendTreeFromJson(
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sAnimGraphResourceStateMachineFromJson(
|
||||
const json& json_data,
|
||||
AnimGraphResource* result_graph_resource) {
|
||||
assert(false && !"Not yet implemented!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlendTreeResource::RemoveConnectionsForSocket(
|
||||
const AnimNodeResource* node_resource,
|
||||
const Socket& socket) {
|
||||
const BlendTreeConnectionResource* connection =
|
||||
FindConnectionForSocket(node_resource, socket.m_name);
|
||||
while (connection != nullptr) {
|
||||
DisconnectSockets(
|
||||
GetNode(connection->source_node_index),
|
||||
connection->source_socket_name,
|
||||
GetNode(connection->target_node_index),
|
||||
connection->target_socket_name);
|
||||
|
||||
connection = FindConnectionForSocket(node_resource, socket.m_name);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendTreeResource::RemoveNodeConnections(AnimNodeResource* node_resource) {
|
||||
for (const Socket& socket :
|
||||
node_resource->m_virtual_socket_accessor->m_inputs) {
|
||||
RemoveConnectionsForSocket(node_resource, socket);
|
||||
}
|
||||
|
||||
for (const Socket& socket :
|
||||
node_resource->m_virtual_socket_accessor->m_outputs) {
|
||||
RemoveConnectionsForSocket(node_resource, socket);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlendTreeResource::RemoveNode(AnimNodeResource* node_resource) {
|
||||
std::vector<AnimNodeResource*>::iterator node_iterator =
|
||||
std::find(m_nodes.begin(), m_nodes.end(), node_resource);
|
||||
|
||||
if (node_iterator == m_nodes.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t node_index = node_iterator - m_nodes.begin();
|
||||
|
||||
if (m_node_input_connection_indices[node_index].size() > 0) {
|
||||
std::cerr << "Cannot remove node, node still has input connections!"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
m_node_input_connection_indices.erase(
|
||||
m_node_input_connection_indices.begin() + node_index);
|
||||
m_nodes.erase(node_iterator);
|
||||
|
||||
for (BlendTreeConnectionResource& connection : m_connections) {
|
||||
if (connection.source_node_index > node_index) {
|
||||
connection.source_node_index--;
|
||||
}
|
||||
if (connection.target_node_index > node_index) {
|
||||
connection.target_node_index--;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateNodeEvalOrder();
|
||||
UpdateTreeTopologyInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlendTreeResource::ConnectSockets(
|
||||
const AnimNodeResource* source_node,
|
||||
const std::string& source_socket_name,
|
||||
@@ -760,7 +830,8 @@ AnimGraphResource::AnimGraphResource(AnimGraphType graph_type) {
|
||||
m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree");
|
||||
|
||||
m_blend_tree_resource.InitGraphConnectors();
|
||||
RegisterBlendTreeOutputSocket<AnimData>("Output");
|
||||
RegisterBlendTreeOutputSocket<AnimData>(
|
||||
AnimGraphResource::DefaultAnimOutput);
|
||||
} else {
|
||||
std::cerr
|
||||
<< "Warning: construction of state machine graphs not yet implemented!"
|
||||
@@ -768,9 +839,7 @@ AnimGraphResource::AnimGraphResource(AnimGraphType graph_type) {
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimGraphResource::LoadFromFile(const char* filename) {
|
||||
Clear();
|
||||
|
||||
AnimGraphResource* AnimGraphResource::CreateFromFile(const char* filename) {
|
||||
std::ifstream input_file;
|
||||
input_file.open(filename);
|
||||
std::stringstream buffer;
|
||||
@@ -781,7 +850,7 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
|
||||
std::cerr << "Error parsing json of file '" << filename << "'."
|
||||
<< std::endl;
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (json_data["type"] != "AnimNodeResource") {
|
||||
@@ -789,20 +858,23 @@ bool AnimGraphResource::LoadFromFile(const char* filename) {
|
||||
<< "Invalid json object. Expected type 'AnimNodeResource' but got '"
|
||||
<< json_data["type"] << "'." << std::endl;
|
||||
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnimGraphResource* result = nullptr;
|
||||
if (json_data["node_type"] == "BlendTree") {
|
||||
return sAnimGraphResourceBlendTreeFromJson(json_data, this);
|
||||
result =
|
||||
dynamic_cast<AnimGraphResource*>(AnimNodeResourceFactory("BlendTree"));
|
||||
sAnimGraphResourceBlendTreeFromJson(json_data, result);
|
||||
} else if (json_data["node_type"] == "StateMachine") {
|
||||
return LoadStateMachineResourceFromJson(json_data);
|
||||
sAnimGraphResourceStateMachineFromJson(json_data, result);
|
||||
} else {
|
||||
std::cerr << "Invalid node_type. Expected type 'BlendTree' or "
|
||||
"'StateMachine' but got '"
|
||||
<< json_data["node_type"] << "'." << std::endl;
|
||||
}
|
||||
|
||||
std::cerr << "Invalid node_type. Expected type 'BlendTree' or "
|
||||
"'StateMachine' but got '"
|
||||
<< json_data["node_type"] << "'." << std::endl;
|
||||
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AnimGraphResource::SaveToFile(const char* filename) const {
|
||||
|
||||
@@ -43,10 +43,10 @@ struct BlendTreeResource {
|
||||
std::vector<std::vector<size_t> > m_node_input_connection_indices;
|
||||
std::vector<std::vector<size_t> > m_node_inputs_subtree;
|
||||
|
||||
~BlendTreeResource() { CleanupNodes(); }
|
||||
~BlendTreeResource() { ClearAllNodes(); }
|
||||
|
||||
void Reset() {
|
||||
CleanupNodes();
|
||||
ClearAllNodes();
|
||||
|
||||
m_connections.clear();
|
||||
|
||||
@@ -54,7 +54,7 @@ struct BlendTreeResource {
|
||||
m_node_inputs_subtree.clear();
|
||||
}
|
||||
|
||||
void CleanupNodes() {
|
||||
void ClearAllNodes() {
|
||||
for (AnimNodeResource* node_resource : m_nodes) {
|
||||
delete node_resource;
|
||||
}
|
||||
@@ -62,18 +62,6 @@ struct BlendTreeResource {
|
||||
m_nodes.clear();
|
||||
}
|
||||
|
||||
void InitGraphConnectors() {
|
||||
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
|
||||
AnimNodeResource* output_node = GetGraphOutputNode();
|
||||
output_node->m_name = "Outputs";
|
||||
output_node->m_position[0] = 200;
|
||||
|
||||
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
|
||||
AnimNodeResource* input_node = GetGraphInputNode();
|
||||
input_node->m_name = "Inputs";
|
||||
input_node->m_position[0] = -200;
|
||||
}
|
||||
|
||||
[[nodiscard]] AnimNodeResource* GetGraphOutputNode() const {
|
||||
return m_nodes[0];
|
||||
}
|
||||
@@ -134,6 +122,12 @@ struct BlendTreeResource {
|
||||
return m_nodes.size() - 1;
|
||||
}
|
||||
|
||||
void RemoveConnectionsForSocket(
|
||||
const AnimNodeResource* node_resource,
|
||||
const Socket& socket);
|
||||
void RemoveNodeConnections(AnimNodeResource* node_resource);
|
||||
[[maybe_unused]] bool RemoveNode(AnimNodeResource* node_resource);
|
||||
|
||||
[[nodiscard]] size_t GetNumNodes() const { return m_nodes.size(); }
|
||||
[[nodiscard]] AnimNodeResource* GetNode(size_t i) { return m_nodes[i]; }
|
||||
[[nodiscard]] const AnimNodeResource* GetNode(size_t i) const {
|
||||
@@ -271,6 +265,18 @@ struct BlendTreeResource {
|
||||
}
|
||||
|
||||
private:
|
||||
void InitGraphConnectors() {
|
||||
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
|
||||
AnimNodeResource* output_node = GetGraphOutputNode();
|
||||
output_node->m_name = "Outputs";
|
||||
output_node->m_position[0] = 200;
|
||||
|
||||
AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
|
||||
AnimNodeResource* input_node = GetGraphInputNode();
|
||||
input_node->m_name = "Inputs";
|
||||
input_node->m_position[0] = -200;
|
||||
}
|
||||
|
||||
void UpdateNodeEvalOrder() {
|
||||
m_node_eval_order.clear();
|
||||
UpdateNodeEvalOrderRecursive(0);
|
||||
@@ -281,6 +287,8 @@ struct BlendTreeResource {
|
||||
std::vector<AnimNodeResource*> m_nodes;
|
||||
std::vector<BlendTreeConnectionResource> m_connections;
|
||||
std::vector<size_t> m_node_eval_order;
|
||||
|
||||
friend class AnimGraphResource;
|
||||
};
|
||||
|
||||
struct StateMachineTransitionResources {
|
||||
@@ -299,6 +307,8 @@ struct AnimGraphResource : AnimNodeResource {
|
||||
explicit AnimGraphResource(AnimGraphType graph_type);
|
||||
virtual ~AnimGraphResource() { Clear(); };
|
||||
|
||||
static constexpr char DefaultAnimOutput[] = "Output";
|
||||
|
||||
std::string m_graph_type_name;
|
||||
|
||||
BlendTreeResource m_blend_tree_resource;
|
||||
@@ -308,8 +318,8 @@ struct AnimGraphResource : AnimNodeResource {
|
||||
StateMachineResource m_state_machine_resource;
|
||||
|
||||
void Clear() { m_blend_tree_resource.Reset(); }
|
||||
bool SaveToFile(const char* filename) const;
|
||||
bool LoadFromFile(const char* filename);
|
||||
[[maybe_unused]] bool SaveToFile(const char* filename) const;
|
||||
static AnimGraphResource* CreateFromFile(const char* filename);
|
||||
|
||||
void CreateBlendTreeInstance(AnimGraphBlendTree& result) const;
|
||||
|
||||
@@ -389,7 +399,9 @@ struct AnimGraphResource : AnimNodeResource {
|
||||
bool LoadStateMachineResourceFromJson(nlohmann::json const& json_data);
|
||||
};
|
||||
|
||||
static inline AnimNodeResource* AnimNodeResourceFactory(
|
||||
typedef std::unique_ptr<AnimGraphResource> AnimGraphResourcePtr;
|
||||
|
||||
inline AnimNodeResource* AnimNodeResourceFactory(
|
||||
const std::string& node_type_name) {
|
||||
AnimNodeResource* result;
|
||||
|
||||
|
||||
@@ -132,25 +132,6 @@ bool NodeSocketEditor(Socket& socket) {
|
||||
return modified;
|
||||
}
|
||||
|
||||
void RemoveBlendTreeConnectionsForSocket(
|
||||
BlendTreeResource& blend_tree_resource,
|
||||
AnimNodeResource* node_resource,
|
||||
Socket& socket) {
|
||||
const BlendTreeConnectionResource* connection =
|
||||
blend_tree_resource.FindConnectionForSocket(node_resource, socket.m_name);
|
||||
while (connection != nullptr) {
|
||||
blend_tree_resource.DisconnectSockets(
|
||||
blend_tree_resource.GetNode(connection->source_node_index),
|
||||
connection->source_socket_name,
|
||||
blend_tree_resource.GetNode(connection->target_node_index),
|
||||
connection->target_socket_name);
|
||||
|
||||
connection = blend_tree_resource.FindConnectionForSocket(
|
||||
node_resource,
|
||||
socket.m_name);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncTrackEditor(SyncTrack* sync_track) {
|
||||
ImGui::SliderFloat("duration", &sync_track->m_duration, 0.001f, 10.f);
|
||||
|
||||
@@ -363,10 +344,7 @@ void AnimGraphEditorRenderSidebar(
|
||||
current_graph_resource->m_virtual_socket_accessor->m_inputs = inputs;
|
||||
}
|
||||
if (ImGui::Button("X")) {
|
||||
RemoveBlendTreeConnectionsForSocket(
|
||||
blend_tree_resource,
|
||||
node_resource,
|
||||
input);
|
||||
blend_tree_resource.RemoveConnectionsForSocket(node_resource, input);
|
||||
iter = inputs.erase(iter);
|
||||
} else {
|
||||
iter++;
|
||||
@@ -947,6 +925,21 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||
}
|
||||
}
|
||||
|
||||
ax::NodeEditor::NodeId hovered_node = ax::NodeEditor::GetHoveredNode();
|
||||
if (!hovered_node.Invalid) {
|
||||
AnimNodeResource* node_resource =
|
||||
hovered_node.AsPointer<AnimNodeResource>();
|
||||
|
||||
if (node_resource && ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
||||
AnimGraphResource* current_graph_resource =
|
||||
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
|
||||
|
||||
current_graph_resource->m_blend_tree_resource.RemoveNodeConnections(
|
||||
node_resource);
|
||||
current_graph_resource->m_blend_tree_resource.RemoveNode(node_resource);
|
||||
}
|
||||
}
|
||||
|
||||
ax::NodeEditor::SetCurrentEditor(nullptr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user