Added breadcrumb navigation for embedded graphs.

RefactorUnifiedBlendTreeStateMachineHandling
Martin Felis 2024-05-01 10:58:33 +02:00
parent 44087d7a7c
commit e3baa65c3b
1 changed files with 100 additions and 41 deletions

View File

@ -15,7 +15,10 @@
struct EditorState {
AnimGraphResource* rootGraphResource = nullptr;
AnimGraphResource* currentGraphResource = nullptr;
std::vector<AnimGraphResource*> hierarchyStack;
size_t hierarchyStackIndex = 0;
bool isGraphLoadedThisFrame = false;
};
@ -259,18 +262,25 @@ void AnimGraphEditorRenderSidebar(
}
void AnimGraphEditorClear() {
sEditorState.currentGraphResource = nullptr;
sEditorState.hierarchyStack.clear();
delete sEditorState.rootGraphResource;
sEditorState.rootGraphResource = new AnimGraphResource();
sEditorState.rootGraphResource->m_name = "Root";
sEditorState.rootGraphResource->m_graph_type_name = "BlendTree";
sEditorState.rootGraphResource->m_blend_tree_resource.InitGraphConnectors();
sEditorState.currentGraphResource = sEditorState.rootGraphResource;
sEditorState.hierarchyStack.push_back(sEditorState.rootGraphResource);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex] =
sEditorState.hierarchyStack.back();
}
void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
ax::NodeEditor::SetCurrentEditor(context);
//
// Menu bar
//
ImGui::BeginMenuBar();
if (ImGui::Button("Save")) {
sEditorState.rootGraphResource->SaveToFile("editor_graph.json");
@ -289,14 +299,47 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
memset(graph_name_buffer, 0, sizeof(graph_name_buffer));
strncpy(
graph_name_buffer,
sEditorState.currentGraphResource->m_name.c_str(),
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_name.c_str(),
sizeof(graph_name_buffer));
if (ImGui::InputText("Name", graph_name_buffer, sizeof(graph_name_buffer))) {
sEditorState.currentGraphResource->m_name = graph_name_buffer;
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]->m_name =
graph_name_buffer;
}
ImGui::EndMenuBar();
//
// Breadcrumb navigation
//
for (size_t i = 0, n = sEditorState.hierarchyStack.size(); i < n; i++) {
AnimGraphResource* graph_resource =
dynamic_cast<AnimGraphResource*>(sEditorState.hierarchyStack[i]);
ImGui::PushID(graph_resource);
bool highlight_button = i == sEditorState.hierarchyStackIndex;
if (highlight_button) {
ImGui::PushStyleColor(
ImGuiCol_Button,
(ImVec4)ImColor::HSV(1. / 7.0f, 0.6f, 0.6f));
}
if (ImGui::Button(graph_resource->m_name.c_str())) {
sEditorState.hierarchyStackIndex = i;
}
if (highlight_button) {
ImGui::PopStyleColor(1);
}
ImGui::PopID();
if (i < n - 1) {
ImGui::SameLine();
}
}
ImGui::Columns(2);
//
@ -305,13 +348,13 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
ax::NodeEditor::Begin("Graph Editor");
for (size_t node_id = 0,
n = sEditorState.currentGraphResource->m_blend_tree_resource
.GetNumNodes();
n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNumNodes();
node_id < n;
node_id++) {
AnimNodeResource* node_resource =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
node_id);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(node_id);
if (node_id == 0 || node_id == 1) {
// continue;
@ -327,8 +370,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
// Inputs
std::vector<Socket> node_inputs =
sEditorState.currentGraphResource->m_blend_tree_resource
.GetNodeInputSockets(node_resource);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNodeInputSockets(node_resource);
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
Socket& socket = node_inputs[j];
ax::NodeEditor::BeginPin(
@ -342,8 +385,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
// Outputs
std::vector<Socket> node_outputs =
sEditorState.currentGraphResource->m_blend_tree_resource
.GetNodeOutputSockets(node_resource);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNodeOutputSockets(node_resource);
for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) {
Socket& socket = node_outputs[j];
ax::NodeEditor::BeginPin(
@ -364,24 +407,26 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
int link_id = 0;
for (size_t connection_id = 0,
n = sEditorState.currentGraphResource->m_blend_tree_resource
.GetNumConnections();
n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNumConnections();
connection_id < n;
connection_id++) {
const BlendTreeConnectionResource* connection_resource =
sEditorState.currentGraphResource->m_blend_tree_resource.GetConnection(
connection_id);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetConnection(connection_id);
const AnimNodeResource* source_node_resource =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
connection_resource->source_node_index);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(
connection_resource->source_node_index);
int source_socket_index =
source_node_resource->m_socket_accessor->GetOutputIndex(
connection_resource->source_socket_name.c_str());
const AnimNodeResource* target_node_resource =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
connection_resource->target_node_index);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(
connection_resource->target_node_index);
int target_socket_index =
target_node_resource->m_socket_accessor->GetInputIndex(
connection_resource->target_socket_name.c_str());
@ -411,8 +456,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
&source_node_socket_index);
const AnimNodeResource* source_node =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
source_node_index);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(source_node_index);
if (source_node->m_socket_accessor->m_outputs.size()
< source_node_socket_index) {
source_node_socket_index = -1;
@ -427,21 +472,21 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
&target_node_socket_index);
const AnimNodeResource* target_node =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
target_node_index);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(target_node_index);
if (target_node->m_socket_accessor->m_inputs.size()
< target_node_socket_index) {
target_node_socket_index = -1;
}
const Socket* source_socket =
sEditorState.currentGraphResource->m_blend_tree_resource
.GetNodeOutputSocketByIndex(
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNodeOutputSocketByIndex(
source_node,
source_node_socket_index);
const Socket* target_socket =
sEditorState.currentGraphResource->m_blend_tree_resource
.GetNodeInputSocketByIndex(
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNodeInputSocketByIndex(
target_node,
target_node_socket_index);
@ -458,8 +503,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
->m_inputs[target_node_socket_index]
.m_name;
sEditorState.currentGraphResource->m_blend_tree_resource
.ConnectSockets(
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.ConnectSockets(
source_node,
source_socket_name,
target_node,
@ -522,11 +567,12 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
if (!node_type_name.empty()) {
AnimNodeResource* node_resource =
AnimNodeResourceFactory(node_type_name);
size_t node_id = sEditorState.currentGraphResource
->m_blend_tree_resource.GetNumNodes();
size_t node_id =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNumNodes();
ax::NodeEditor::SetNodePosition(node_id, popup_mouse_position);
sEditorState.currentGraphResource->m_blend_tree_resource.AddNode(
node_resource);
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.AddNode(node_resource);
}
ImGui::EndPopup();
@ -549,9 +595,10 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
if (selected_node_id.Get() != 0) {
AnimGraphEditorRenderSidebar(
sEditorState.currentGraphResource->m_blend_tree_resource,
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
selected_node_id.Get()));
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource,
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(selected_node_id.Get()));
}
}
@ -561,11 +608,23 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
ax::NodeEditor::GetDoubleClickedNode();
if (!double_clicked_node_id.Invalid) {
AnimNodeResource* clicked_node_resource =
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
double_clicked_node_id.Get());
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNode(double_clicked_node_id.Get());
if (clicked_node_resource->m_node_type_name == "BlendTree") {
sEditorState.currentGraphResource =
AnimGraphResource* clicked_graph_resource =
dynamic_cast<AnimGraphResource*>(clicked_node_resource);
if (sEditorState.hierarchyStack.size()
> sEditorState.hierarchyStackIndex + 1
&& sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex + 1]
== clicked_graph_resource) {
sEditorState.hierarchyStackIndex++;
} else {
sEditorState.hierarchyStack.resize(
sEditorState.hierarchyStackIndex + 1);
sEditorState.hierarchyStack.push_back(clicked_graph_resource);
sEditorState.hierarchyStackIndex++;
}
ax::NodeEditor::ClearSelection();
}
}