From 84fc49af300f4249c90a8e193ee2c8ef5da442ea Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Wed, 1 May 2024 12:50:16 +0200 Subject: [PATCH] Properly store and restore node positions in editor. --- src/AnimGraph/AnimGraphEditor.cc | 53 ++++++++++++++++++++---------- src/AnimGraph/AnimGraphResource.cc | 4 +++ 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/AnimGraph/AnimGraphEditor.cc b/src/AnimGraph/AnimGraphEditor.cc index 3242b71..83b338f 100644 --- a/src/AnimGraph/AnimGraphEditor.cc +++ b/src/AnimGraph/AnimGraphEditor.cc @@ -160,7 +160,11 @@ void SkinnedMeshWidget(SkinnedMesh* skinned_mesh) { void AnimGraphEditorRenderSidebar( BlendTreeResource& blend_tree_resource, AnimNodeResource* node_resource) { - ImGui::Text("[%s]", node_resource->m_node_type_name.c_str()); + ImGui::Text( + "[%s (%2.2f, %2.2f)]", + node_resource->m_node_type_name.c_str(), + node_resource->m_position[0], + node_resource->m_position[1]); char node_name_buffer[256]; memset(node_name_buffer, 0, sizeof(node_name_buffer)); @@ -263,7 +267,10 @@ void AnimGraphEditorRenderSidebar( } void AnimGraphEditorClear() { - sEditorState.hierarchyStack.clear(); + if (ax::NodeEditor::GetCurrentEditor() != nullptr) { + ax::NodeEditor::ClearSelection(); + } + delete sEditorState.rootGraphResource; sEditorState.rootGraphResource = new AnimGraphResource(); @@ -271,9 +278,11 @@ void AnimGraphEditorClear() { sEditorState.rootGraphResource->m_graph_type_name = "BlendTree"; sEditorState.rootGraphResource->m_blend_tree_resource.InitGraphConnectors(); + sEditorState.hierarchyStack.clear(); sEditorState.hierarchyStack.push_back(sEditorState.rootGraphResource); sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] = sEditorState.hierarchyStack.back(); + sEditorState.hierarchyStackIndex = 0; } void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { @@ -287,6 +296,7 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { sEditorState.rootGraphResource->SaveToFile("editor_graph.json"); } if (ImGui::Button("Load")) { + AnimGraphEditorClear(); sEditorState.rootGraphResource->LoadFromFile("editor_graph.json"); sEditorState.isGraphLoadedThisFrame = true; } @@ -348,18 +358,15 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { // ax::NodeEditor::Begin("Graph Editor"); - for (size_t node_id = 0, + for (size_t node_index = 0, n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] ->m_blend_tree_resource.GetNumNodes(); - node_id < n; - node_id++) { + node_index < n; + node_index++) { AnimNodeResource* node_resource = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource.GetNode(node_id); - - if (node_id == 0 || node_id == 1) { - // continue; - } + ->m_blend_tree_resource.GetNode(node_index); + ax::NodeEditor::NodeId node_id(node_resource); if (sEditorState.isGraphLoadedThisFrame) { ax::NodeEditor::SetNodePosition( @@ -377,7 +384,7 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { Socket& socket = node_inputs[j]; ax::NodeEditor::BeginPin( NodeIndexAndSocketIndexToInputPinId( - static_cast(node_id), + static_cast(node_index), static_cast(j)), ax::NodeEditor::PinKind::Input); ImGui::Text("%s", socket.m_name.c_str()); @@ -392,7 +399,7 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { Socket& socket = node_outputs[j]; ax::NodeEditor::BeginPin( NodeIndexAndSocketIndexToOutputPinId( - static_cast(node_id), + static_cast(node_index), static_cast(j)), ax::NodeEditor::PinKind::Output); ImGui::Text("%s", socket.m_name.c_str()); @@ -597,22 +604,32 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { AnimGraphEditorRenderSidebar( sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] ->m_blend_tree_resource, - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource.GetNode(selected_node_id.Get())); + selected_node_id.AsPointer()); } } ImGui::Columns(1); + // Clear flag, however it may be re-set further down when handling double + // clicking into subgraphs. + sEditorState.isGraphLoadedThisFrame = false; + + // + // Handle double click into subgraphs + // ax::NodeEditor::NodeId double_clicked_node_id = ax::NodeEditor::GetDoubleClickedNode(); if (!double_clicked_node_id.Invalid) { AnimNodeResource* clicked_node_resource = - sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] - ->m_blend_tree_resource.GetNode(double_clicked_node_id.Get()); - if (clicked_node_resource->m_node_type_name == "BlendTree") { + double_clicked_node_id.AsPointer(); + + if (clicked_node_resource != nullptr + && clicked_node_resource->m_node_type_name == "BlendTree") { AnimGraphResource* clicked_graph_resource = dynamic_cast(clicked_node_resource); + + assert(clicked_graph_resource != nullptr); + if (sEditorState.hierarchyStack.size() > sEditorState.hierarchyStackIndex + 1 && sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex + 1] @@ -625,12 +642,12 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { sEditorState.hierarchyStackIndex++; } + sEditorState.isGraphLoadedThisFrame = true; ax::NodeEditor::ClearSelection(); } } ax::NodeEditor::SetCurrentEditor(nullptr); - sEditorState.isGraphLoadedThisFrame = false; } void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& blend_tree) { diff --git a/src/AnimGraph/AnimGraphResource.cc b/src/AnimGraph/AnimGraphResource.cc index 991ddb9..1a840d1 100644 --- a/src/AnimGraph/AnimGraphResource.cc +++ b/src/AnimGraph/AnimGraphResource.cc @@ -256,6 +256,8 @@ static json sAnimGraphResourceBlendTreeToJson( result["name"] = anim_graph_resource.m_name; result["type"] = "AnimNodeResource"; result["node_type"] = "BlendTree"; + result["position"][0] = anim_graph_resource.m_position[0]; + result["position"][1] = anim_graph_resource.m_position[1]; const BlendTreeResource& blend_tree_resource = anim_graph_resource.m_blend_tree_resource; @@ -307,6 +309,8 @@ static bool sAnimGraphResourceBlendTreeFromJson( result_graph_resource->m_graph_type_name = "BlendTree"; result_graph_resource->m_node_type_name = "BlendTree"; result_graph_resource->m_name = json_data["name"]; + result_graph_resource->m_position[0] = json_data["position"][0]; + result_graph_resource->m_position[1] = json_data["position"][1]; // Load nodes for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) {