Added breadcrumb navigation for embedded graphs.
parent
44087d7a7c
commit
e3baa65c3b
|
@ -15,7 +15,10 @@
|
||||||
|
|
||||||
struct EditorState {
|
struct EditorState {
|
||||||
AnimGraphResource* rootGraphResource = nullptr;
|
AnimGraphResource* rootGraphResource = nullptr;
|
||||||
AnimGraphResource* currentGraphResource = nullptr;
|
|
||||||
|
std::vector<AnimGraphResource*> hierarchyStack;
|
||||||
|
size_t hierarchyStackIndex = 0;
|
||||||
|
|
||||||
bool isGraphLoadedThisFrame = false;
|
bool isGraphLoadedThisFrame = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,18 +262,25 @@ void AnimGraphEditorRenderSidebar(
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphEditorClear() {
|
void AnimGraphEditorClear() {
|
||||||
sEditorState.currentGraphResource = nullptr;
|
sEditorState.hierarchyStack.clear();
|
||||||
delete sEditorState.rootGraphResource;
|
delete sEditorState.rootGraphResource;
|
||||||
|
|
||||||
sEditorState.rootGraphResource = new AnimGraphResource();
|
sEditorState.rootGraphResource = new AnimGraphResource();
|
||||||
|
sEditorState.rootGraphResource->m_name = "Root";
|
||||||
sEditorState.rootGraphResource->m_graph_type_name = "BlendTree";
|
sEditorState.rootGraphResource->m_graph_type_name = "BlendTree";
|
||||||
sEditorState.rootGraphResource->m_blend_tree_resource.InitGraphConnectors();
|
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) {
|
void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
ax::NodeEditor::SetCurrentEditor(context);
|
ax::NodeEditor::SetCurrentEditor(context);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Menu bar
|
||||||
|
//
|
||||||
ImGui::BeginMenuBar();
|
ImGui::BeginMenuBar();
|
||||||
if (ImGui::Button("Save")) {
|
if (ImGui::Button("Save")) {
|
||||||
sEditorState.rootGraphResource->SaveToFile("editor_graph.json");
|
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));
|
memset(graph_name_buffer, 0, sizeof(graph_name_buffer));
|
||||||
strncpy(
|
strncpy(
|
||||||
graph_name_buffer,
|
graph_name_buffer,
|
||||||
sEditorState.currentGraphResource->m_name.c_str(),
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
|
->m_name.c_str(),
|
||||||
sizeof(graph_name_buffer));
|
sizeof(graph_name_buffer));
|
||||||
if (ImGui::InputText("Name", graph_name_buffer, 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();
|
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);
|
ImGui::Columns(2);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -305,13 +348,13 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
ax::NodeEditor::Begin("Graph Editor");
|
ax::NodeEditor::Begin("Graph Editor");
|
||||||
|
|
||||||
for (size_t node_id = 0,
|
for (size_t node_id = 0,
|
||||||
n = sEditorState.currentGraphResource->m_blend_tree_resource
|
n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNumNodes();
|
->m_blend_tree_resource.GetNumNodes();
|
||||||
node_id < n;
|
node_id < n;
|
||||||
node_id++) {
|
node_id++) {
|
||||||
AnimNodeResource* node_resource =
|
AnimNodeResource* node_resource =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
node_id);
|
->m_blend_tree_resource.GetNode(node_id);
|
||||||
|
|
||||||
if (node_id == 0 || node_id == 1) {
|
if (node_id == 0 || node_id == 1) {
|
||||||
// continue;
|
// continue;
|
||||||
|
@ -327,8 +370,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
std::vector<Socket> node_inputs =
|
std::vector<Socket> node_inputs =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNodeInputSockets(node_resource);
|
->m_blend_tree_resource.GetNodeInputSockets(node_resource);
|
||||||
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
||||||
Socket& socket = node_inputs[j];
|
Socket& socket = node_inputs[j];
|
||||||
ax::NodeEditor::BeginPin(
|
ax::NodeEditor::BeginPin(
|
||||||
|
@ -342,8 +385,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
|
|
||||||
// Outputs
|
// Outputs
|
||||||
std::vector<Socket> node_outputs =
|
std::vector<Socket> node_outputs =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNodeOutputSockets(node_resource);
|
->m_blend_tree_resource.GetNodeOutputSockets(node_resource);
|
||||||
for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) {
|
for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) {
|
||||||
Socket& socket = node_outputs[j];
|
Socket& socket = node_outputs[j];
|
||||||
ax::NodeEditor::BeginPin(
|
ax::NodeEditor::BeginPin(
|
||||||
|
@ -364,23 +407,25 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
|
|
||||||
int link_id = 0;
|
int link_id = 0;
|
||||||
for (size_t connection_id = 0,
|
for (size_t connection_id = 0,
|
||||||
n = sEditorState.currentGraphResource->m_blend_tree_resource
|
n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNumConnections();
|
->m_blend_tree_resource.GetNumConnections();
|
||||||
connection_id < n;
|
connection_id < n;
|
||||||
connection_id++) {
|
connection_id++) {
|
||||||
const BlendTreeConnectionResource* connection_resource =
|
const BlendTreeConnectionResource* connection_resource =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetConnection(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
connection_id);
|
->m_blend_tree_resource.GetConnection(connection_id);
|
||||||
|
|
||||||
const AnimNodeResource* source_node_resource =
|
const AnimNodeResource* source_node_resource =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
|
->m_blend_tree_resource.GetNode(
|
||||||
connection_resource->source_node_index);
|
connection_resource->source_node_index);
|
||||||
int source_socket_index =
|
int source_socket_index =
|
||||||
source_node_resource->m_socket_accessor->GetOutputIndex(
|
source_node_resource->m_socket_accessor->GetOutputIndex(
|
||||||
connection_resource->source_socket_name.c_str());
|
connection_resource->source_socket_name.c_str());
|
||||||
|
|
||||||
const AnimNodeResource* target_node_resource =
|
const AnimNodeResource* target_node_resource =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
|
->m_blend_tree_resource.GetNode(
|
||||||
connection_resource->target_node_index);
|
connection_resource->target_node_index);
|
||||||
int target_socket_index =
|
int target_socket_index =
|
||||||
target_node_resource->m_socket_accessor->GetInputIndex(
|
target_node_resource->m_socket_accessor->GetInputIndex(
|
||||||
|
@ -411,8 +456,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
&source_node_socket_index);
|
&source_node_socket_index);
|
||||||
|
|
||||||
const AnimNodeResource* source_node =
|
const AnimNodeResource* source_node =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
source_node_index);
|
->m_blend_tree_resource.GetNode(source_node_index);
|
||||||
if (source_node->m_socket_accessor->m_outputs.size()
|
if (source_node->m_socket_accessor->m_outputs.size()
|
||||||
< source_node_socket_index) {
|
< source_node_socket_index) {
|
||||||
source_node_socket_index = -1;
|
source_node_socket_index = -1;
|
||||||
|
@ -427,21 +472,21 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
&target_node_socket_index);
|
&target_node_socket_index);
|
||||||
|
|
||||||
const AnimNodeResource* target_node =
|
const AnimNodeResource* target_node =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
target_node_index);
|
->m_blend_tree_resource.GetNode(target_node_index);
|
||||||
if (target_node->m_socket_accessor->m_inputs.size()
|
if (target_node->m_socket_accessor->m_inputs.size()
|
||||||
< target_node_socket_index) {
|
< target_node_socket_index) {
|
||||||
target_node_socket_index = -1;
|
target_node_socket_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Socket* source_socket =
|
const Socket* source_socket =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNodeOutputSocketByIndex(
|
->m_blend_tree_resource.GetNodeOutputSocketByIndex(
|
||||||
source_node,
|
source_node,
|
||||||
source_node_socket_index);
|
source_node_socket_index);
|
||||||
const Socket* target_socket =
|
const Socket* target_socket =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.GetNodeInputSocketByIndex(
|
->m_blend_tree_resource.GetNodeInputSocketByIndex(
|
||||||
target_node,
|
target_node,
|
||||||
target_node_socket_index);
|
target_node_socket_index);
|
||||||
|
|
||||||
|
@ -458,8 +503,8 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
->m_inputs[target_node_socket_index]
|
->m_inputs[target_node_socket_index]
|
||||||
.m_name;
|
.m_name;
|
||||||
|
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
.ConnectSockets(
|
->m_blend_tree_resource.ConnectSockets(
|
||||||
source_node,
|
source_node,
|
||||||
source_socket_name,
|
source_socket_name,
|
||||||
target_node,
|
target_node,
|
||||||
|
@ -522,11 +567,12 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
if (!node_type_name.empty()) {
|
if (!node_type_name.empty()) {
|
||||||
AnimNodeResource* node_resource =
|
AnimNodeResource* node_resource =
|
||||||
AnimNodeResourceFactory(node_type_name);
|
AnimNodeResourceFactory(node_type_name);
|
||||||
size_t node_id = sEditorState.currentGraphResource
|
size_t node_id =
|
||||||
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
->m_blend_tree_resource.GetNumNodes();
|
->m_blend_tree_resource.GetNumNodes();
|
||||||
ax::NodeEditor::SetNodePosition(node_id, popup_mouse_position);
|
ax::NodeEditor::SetNodePosition(node_id, popup_mouse_position);
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.AddNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
node_resource);
|
->m_blend_tree_resource.AddNode(node_resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
@ -549,9 +595,10 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
||||||
|
|
||||||
if (selected_node_id.Get() != 0) {
|
if (selected_node_id.Get() != 0) {
|
||||||
AnimGraphEditorRenderSidebar(
|
AnimGraphEditorRenderSidebar(
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource,
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
->m_blend_tree_resource,
|
||||||
selected_node_id.Get()));
|
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();
|
ax::NodeEditor::GetDoubleClickedNode();
|
||||||
if (!double_clicked_node_id.Invalid) {
|
if (!double_clicked_node_id.Invalid) {
|
||||||
AnimNodeResource* clicked_node_resource =
|
AnimNodeResource* clicked_node_resource =
|
||||||
sEditorState.currentGraphResource->m_blend_tree_resource.GetNode(
|
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
|
||||||
double_clicked_node_id.Get());
|
->m_blend_tree_resource.GetNode(double_clicked_node_id.Get());
|
||||||
if (clicked_node_resource->m_node_type_name == "BlendTree") {
|
if (clicked_node_resource->m_node_type_name == "BlendTree") {
|
||||||
sEditorState.currentGraphResource =
|
AnimGraphResource* clicked_graph_resource =
|
||||||
dynamic_cast<AnimGraphResource*>(clicked_node_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();
|
ax::NodeEditor::ClearSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue