8 Commits
5 changed files with 348 additions and 133 deletions
+2 -2
View File
@@ -161,7 +161,7 @@ struct Socket {
SocketValue m_value = {0}; SocketValue m_value = {0};
std::string m_value_string; std::string m_value_string;
union SocketReference { union SocketReference {
void* ptr; void* ptr = nullptr;
void** ptr_ptr; void** ptr_ptr;
}; };
SocketReference m_reference = {0}; SocketReference m_reference = {0};
@@ -418,7 +418,7 @@ struct NodeDescriptorBase {
return socket->GetValue<T>(); return socket->GetValue<T>();
} }
virtual void UpdateFlags(){}; virtual void UpdateFlags() {};
protected: protected:
Socket* FindSocket(const char* name, std::vector<Socket>& sockets) { Socket* FindSocket(const char* name, std::vector<Socket>& sockets) {
+247 -112
View File
@@ -15,8 +15,12 @@
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;
ImVec2 mousePopupStart = {};
}; };
static EditorState sEditorState; static EditorState sEditorState;
@@ -42,16 +46,23 @@ ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
return ImNodesPinShape_Quad; return ImNodesPinShape_Quad;
} }
void NodeSocketEditor(Socket& socket) { bool NodeSocketEditor(Socket& socket) {
bool modified = false;
int mode_current = static_cast<int>(socket.m_type); int mode_current = static_cast<int>(socket.m_type);
ImGui::InputText("Name", &socket.m_name); if (ImGui::InputText("Name", &socket.m_name)) {
modified = true;
}
if (ImGui::Combo( if (ImGui::Combo(
"Type", "Type",
&mode_current, &mode_current,
SocketTypeNames, SocketTypeNames,
sizeof(SocketTypeNames) / sizeof(char*))) { sizeof(SocketTypeNames) / sizeof(char*))) {
socket.m_type = static_cast<SocketType>(mode_current); socket.m_type = static_cast<SocketType>(mode_current);
modified = true;
} }
return modified;
} }
void RemoveBlendTreeConnectionsForSocket( void RemoveBlendTreeConnectionsForSocket(
@@ -156,7 +167,11 @@ void SkinnedMeshWidget(SkinnedMesh* skinned_mesh) {
void AnimGraphEditorRenderSidebar( void AnimGraphEditorRenderSidebar(
BlendTreeResource& blend_tree_resource, BlendTreeResource& blend_tree_resource,
AnimNodeResource* node_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]; char node_name_buffer[256];
memset(node_name_buffer, 0, sizeof(node_name_buffer)); memset(node_name_buffer, 0, sizeof(node_name_buffer));
@@ -219,7 +234,12 @@ void AnimGraphEditorRenderSidebar(
while (iter != outputs.end()) { while (iter != outputs.end()) {
Socket& output = *iter; Socket& output = *iter;
ImGui::PushID(&output); ImGui::PushID(&output);
NodeSocketEditor(output); if (NodeSocketEditor(output)) {
AnimGraphResource* current_graph_resource =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
current_graph_resource->m_socket_accessor->m_inputs = outputs;
}
if (ImGui::Button("X")) { if (ImGui::Button("X")) {
RemoveBlendTreeConnectionsForSocket( RemoveBlendTreeConnectionsForSocket(
blend_tree_resource, blend_tree_resource,
@@ -231,6 +251,13 @@ void AnimGraphEditorRenderSidebar(
} }
ImGui::PopID(); ImGui::PopID();
} }
if (ImGui::Button("+")) {
AnimGraphResource* current_graph_resource =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
current_graph_resource->RegisterBlendTreeOutputSocket<float>(
"GraphFloatOutput");
}
} }
if (node_resource == blend_tree_resource.GetGraphInputNode()) { if (node_resource == blend_tree_resource.GetGraphInputNode()) {
@@ -243,7 +270,11 @@ void AnimGraphEditorRenderSidebar(
while (iter != inputs.end()) { while (iter != inputs.end()) {
Socket& input = *iter; Socket& input = *iter;
ImGui::PushID(&input); ImGui::PushID(&input);
NodeSocketEditor(input); if (NodeSocketEditor(input)) {
AnimGraphResource* current_graph_resource =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
current_graph_resource->m_socket_accessor->m_inputs = inputs;
}
if (ImGui::Button("X")) { if (ImGui::Button("X")) {
RemoveBlendTreeConnectionsForSocket( RemoveBlendTreeConnectionsForSocket(
blend_tree_resource, blend_tree_resource,
@@ -255,27 +286,51 @@ void AnimGraphEditorRenderSidebar(
} }
ImGui::PopID(); ImGui::PopID();
} }
if (ImGui::Button("+")) {
AnimGraphResource* current_graph_resource =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex];
current_graph_resource->RegisterBlendTreeInputSocket<float>(
"GraphFloatInput");
}
} }
} }
void AnimGraphEditorClear() { void AnimGraphEditorClear() {
sEditorState.currentGraphResource = nullptr; if (ax::NodeEditor::GetCurrentEditor() != nullptr) {
ax::NodeEditor::ClearSelection();
}
if (sEditorState.rootGraphResource) {
delete sEditorState.rootGraphResource->m_socket_accessor;
}
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.rootGraphResource->m_socket_accessor = new NodeDescriptorBase;
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) { 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");
} }
if (ImGui::Button("Load")) { if (ImGui::Button("Load")) {
AnimGraphEditorClear();
sEditorState.rootGraphResource->LoadFromFile("editor_graph.json"); sEditorState.rootGraphResource->LoadFromFile("editor_graph.json");
sEditorState.isGraphLoadedThisFrame = true; sEditorState.isGraphLoadedThisFrame = true;
} }
@@ -289,14 +344,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);
// //
@@ -304,18 +392,15 @@ 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_index = 0,
n = sEditorState.currentGraphResource->m_blend_tree_resource n = sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
.GetNumNodes(); ->m_blend_tree_resource.GetNumNodes();
node_id < n; node_index < n;
node_id++) { node_index++) {
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_index);
ax::NodeEditor::NodeId node_id(node_resource);
if (node_id == 0 || node_id == 1) {
// continue;
}
if (sEditorState.isGraphLoadedThisFrame) { if (sEditorState.isGraphLoadedThisFrame) {
ax::NodeEditor::SetNodePosition( ax::NodeEditor::SetNodePosition(
@@ -327,13 +412,13 @@ 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(
NodeIndexAndSocketIndexToInputPinId( NodeIndexAndSocketIndexToInputPinId(
static_cast<int>(node_id), static_cast<int>(node_index),
static_cast<int>(j)), static_cast<int>(j)),
ax::NodeEditor::PinKind::Input); ax::NodeEditor::PinKind::Input);
ImGui::Text("%s", socket.m_name.c_str()); ImGui::Text("%s", socket.m_name.c_str());
@@ -342,13 +427,13 @@ 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(
NodeIndexAndSocketIndexToOutputPinId( NodeIndexAndSocketIndexToOutputPinId(
static_cast<int>(node_id), static_cast<int>(node_index),
static_cast<int>(j)), static_cast<int>(j)),
ax::NodeEditor::PinKind::Output); ax::NodeEditor::PinKind::Output);
ImGui::Text("%s", socket.m_name.c_str()); ImGui::Text("%s", socket.m_name.c_str());
@@ -364,24 +449,26 @@ 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]
connection_resource->source_node_index); ->m_blend_tree_resource.GetNode(
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]
connection_resource->target_node_index); ->m_blend_tree_resource.GetNode(
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(
connection_resource->target_socket_name.c_str()); connection_resource->target_socket_name.c_str());
@@ -393,78 +480,84 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
static_cast<int>(connection_resource->target_node_index), static_cast<int>(connection_resource->target_node_index),
target_socket_index); target_socket_index);
ax::NodeEditor::Link(link_id++, source_socket_pin_id, target_socket_pin_id); ax::NodeEditor::Link(
ax::NodeEditor::LinkId(connection_resource),
source_socket_pin_id,
target_socket_pin_id);
} }
// Create Connections // Create Connections
if (ax::NodeEditor::BeginCreate()) { if (ax::NodeEditor::BeginCreate()) {
ax::NodeEditor::PinId input_pin_id, output_pin_id; ax::NodeEditor::PinId input_pin_id, output_pin_id;
if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) { if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) {
if (input_pin_id && output_pin_id) { int source_node_index;
if (ax::NodeEditor::AcceptNewItem()) { int source_node_socket_index;
int source_node_index; const AnimNodeResource* source_node = nullptr;
int source_node_socket_index; const Socket* source_socket = nullptr;
OutputPinIdToNodeIndexAndSocketIndex( if (input_pin_id) {
input_pin_id.Get(), OutputPinIdToNodeIndexAndSocketIndex(
&source_node_index, input_pin_id.Get(),
&source_node_socket_index); &source_node_index,
&source_node_socket_index);
const AnimNodeResource* source_node = 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;
} } else {
source_socket =
int target_node_index; sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
int target_node_socket_index; ->m_blend_tree_resource.GetNodeOutputSocketByIndex(
InputPinIdToNodeIndexAndSocketIndex(
output_pin_id.Get(),
&target_node_index,
&target_node_socket_index);
const AnimNodeResource* target_node =
sEditorState.currentGraphResource->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(
source_node, source_node,
source_node_socket_index); source_node_socket_index);
const Socket* target_socket = }
sEditorState.currentGraphResource->m_blend_tree_resource }
.GetNodeInputSocketByIndex(
int target_node_index;
int target_node_socket_index;
const AnimNodeResource* target_node = nullptr;
const Socket* target_socket = nullptr;
if (output_pin_id) {
InputPinIdToNodeIndexAndSocketIndex(
output_pin_id.Get(),
&target_node_index,
&target_node_socket_index);
target_node =
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;
} else {
target_socket =
sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource.GetNodeInputSocketByIndex(
target_node, target_node,
target_node_socket_index); target_node_socket_index);
}
}
if (source_socket == nullptr || target_socket == nullptr) { if (input_pin_id && output_pin_id) {
ax::NodeEditor::RejectNewItem(); if (source_socket == nullptr || target_socket == nullptr
} else { || !sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
const std::string& source_socket_name = ->m_blend_tree_resource.IsConnectionValid(
source_node->m_socket_accessor source_node,
->m_outputs[source_node_socket_index] source_socket->m_name,
.m_name; target_node,
target_socket->m_name)) {
const std::string& target_socket_name = ax::NodeEditor::RejectNewItem();
target_node->m_socket_accessor } else if (ax::NodeEditor::AcceptNewItem()) {
->m_inputs[target_node_socket_index] sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
.m_name; ->m_blend_tree_resource.ConnectSockets(
source_node,
sEditorState.currentGraphResource->m_blend_tree_resource source_socket->m_name,
.ConnectSockets( target_node,
source_node, target_socket->m_name);
source_socket_name,
target_node,
target_socket_name);
}
} }
} }
} }
@@ -475,13 +568,12 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
{ {
const bool open_popup = ImGui::IsMouseReleased(ImGuiMouseButton_Right); const bool open_popup = ImGui::IsMouseReleased(ImGuiMouseButton_Right);
ImVec2 popup_mouse_position = ImGui::GetMousePos(); if (open_popup && ImGui::IsWindowHovered()) {
ax::NodeEditor::Suspend();
ax::NodeEditor::Suspend();
if (open_popup) {
ImGui::OpenPopup("add node"); ImGui::OpenPopup("add node");
ax::NodeEditor::Resume();
sEditorState.mousePopupStart = ImGui::GetMousePos();
} }
ax::NodeEditor::Resume();
ax::NodeEditor::Suspend(); ax::NodeEditor::Suspend();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
@@ -522,11 +614,11 @@ 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 ax::NodeEditor::SetNodePosition(
->m_blend_tree_resource.GetNumNodes(); ax::NodeEditor::NodeId(node_resource),
ax::NodeEditor::SetNodePosition(node_id, popup_mouse_position); sEditorState.mousePopupStart);
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,29 +641,72 @@ 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())); selected_node_id.AsPointer<AnimNodeResource>());
} }
} }
ImGui::Columns(1); 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::NodeId double_clicked_node_id =
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( double_clicked_node_id.AsPointer<AnimNodeResource>();
double_clicked_node_id.Get());
if (clicked_node_resource->m_node_type_name == "BlendTree") { if (clicked_node_resource != nullptr
sEditorState.currentGraphResource = && clicked_node_resource->m_node_type_name == "BlendTree") {
AnimGraphResource* clicked_graph_resource =
dynamic_cast<AnimGraphResource*>(clicked_node_resource); dynamic_cast<AnimGraphResource*>(clicked_node_resource);
assert(clicked_graph_resource != nullptr);
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++;
}
sEditorState.isGraphLoadedThisFrame = true;
ax::NodeEditor::ClearSelection(); ax::NodeEditor::ClearSelection();
} }
} }
ax::NodeEditor::LinkId hovered_link = ax::NodeEditor::GetHoveredLink();
if (!hovered_link.Invalid) {
BlendTreeConnectionResource* connection_resource =
hovered_link.AsPointer<BlendTreeConnectionResource>();
if (connection_resource && ImGui::IsKeyPressed(ImGuiKey_Delete)) {
BlendTreeResource* blend_tree_resource =
&sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]
->m_blend_tree_resource;
blend_tree_resource->DisconnectSockets(
blend_tree_resource->GetNode(connection_resource->source_node_index),
connection_resource->source_socket_name,
blend_tree_resource->GetNode(connection_resource->target_node_index),
connection_resource->target_socket_name);
ax::NodeEditor::DeleteLink(hovered_link);
}
}
ax::NodeEditor::SetCurrentEditor(nullptr); ax::NodeEditor::SetCurrentEditor(nullptr);
sEditorState.isGraphLoadedThisFrame = false;
} }
void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& blend_tree) { void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& blend_tree) {
+7 -4
View File
@@ -182,6 +182,7 @@ AnimNodeResource* sAnimGraphNodeFromJson(
if (node_type == "BlendTree") { if (node_type == "BlendTree") {
AnimGraphResource* result = new AnimGraphResource(); AnimGraphResource* result = new AnimGraphResource();
result->m_socket_accessor = new NodeDescriptorBase;
sAnimGraphResourceBlendTreeFromJson(json_node, result); sAnimGraphResourceBlendTreeFromJson(json_node, result);
return result; return result;
} }
@@ -256,6 +257,8 @@ static json sAnimGraphResourceBlendTreeToJson(
result["name"] = anim_graph_resource.m_name; result["name"] = anim_graph_resource.m_name;
result["type"] = "AnimNodeResource"; result["type"] = "AnimNodeResource";
result["node_type"] = "BlendTree"; 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 = const BlendTreeResource& blend_tree_resource =
anim_graph_resource.m_blend_tree_resource; anim_graph_resource.m_blend_tree_resource;
@@ -307,6 +310,8 @@ static bool sAnimGraphResourceBlendTreeFromJson(
result_graph_resource->m_graph_type_name = "BlendTree"; result_graph_resource->m_graph_type_name = "BlendTree";
result_graph_resource->m_node_type_name = "BlendTree"; result_graph_resource->m_node_type_name = "BlendTree";
result_graph_resource->m_name = json_data["name"]; 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 // Load nodes
for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) { for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) {
@@ -326,8 +331,7 @@ static bool sAnimGraphResourceBlendTreeFromJson(
if (json_data["nodes"][0].contains("inputs")) { if (json_data["nodes"][0].contains("inputs")) {
const json& graph_outputs = json_data["nodes"][0]["inputs"]; const json& graph_outputs = json_data["nodes"][0]["inputs"];
for (const auto& graph_output : graph_outputs) { for (const auto& graph_output : graph_outputs) {
AnimNodeResource* graph_node = blend_tree_resource.GetNode(0); result_graph_resource->RegisterBlendTreeOutputSocket(
graph_node->m_socket_accessor->m_inputs.push_back(
sJsonToSocket(graph_output)); sJsonToSocket(graph_output));
} }
} }
@@ -336,8 +340,7 @@ static bool sAnimGraphResourceBlendTreeFromJson(
if (json_data["nodes"][1].contains("outputs")) { if (json_data["nodes"][1].contains("outputs")) {
const json& graph_inputs = json_data["nodes"][1]["outputs"]; const json& graph_inputs = json_data["nodes"][1]["outputs"];
for (const auto& graph_input : graph_inputs) { for (const auto& graph_input : graph_inputs) {
AnimNodeResource* graph_node = blend_tree_resource.GetNode(1); result_graph_resource->RegisterBlendTreeInputSocket(
graph_node->m_socket_accessor->m_outputs.push_back(
sJsonToSocket(graph_input)); sJsonToSocket(graph_input));
} }
} }
+67
View File
@@ -276,6 +276,73 @@ struct AnimGraphResource : AnimNodeResource {
bool LoadFromFile(const char* filename); bool LoadFromFile(const char* filename);
void CreateBlendTreeInstance(AnimGraphBlendTree& result) const; void CreateBlendTreeInstance(AnimGraphBlendTree& result) const;
template <typename T>
bool RegisterBlendTreeInputSocket(const std::string& socket_name) {
Socket socket;
socket.m_name = socket_name;
socket.m_type = GetSocketType<T>();
socket.m_type_size = sizeof(T);
return RegisterBlendTreeInputSocket(socket);
}
bool RegisterBlendTreeInputSocket(const Socket& socket) {
AnimNodeResource* input_node = m_blend_tree_resource.GetGraphInputNode();
std::vector<Socket> input_sockets =
input_node->m_socket_accessor->m_outputs;
std::vector<Socket>::const_iterator iter = std::find_if(
input_sockets.begin(),
input_sockets.end(),
[&socket](const Socket& input_socket) {
return socket.m_name == input_socket.m_name;
});
if (iter != input_sockets.end()) {
std::cerr << "Error: cannot register input socket as socket with name '"
<< socket.m_name << "' already exists!" << std::endl;
return false;
}
input_node->m_socket_accessor->m_outputs.push_back(socket);
m_socket_accessor->m_inputs = input_node->m_socket_accessor->m_outputs;
return true;
}
template <typename T>
bool RegisterBlendTreeOutputSocket(const std::string& socket_name) {
Socket socket;
socket.m_name = socket_name;
socket.m_type = GetSocketType<T>();
socket.m_type_size = sizeof(T);
return RegisterBlendTreeOutputSocket(socket);
}
bool RegisterBlendTreeOutputSocket(const Socket& socket) {
AnimNodeResource* output_node = m_blend_tree_resource.GetGraphOutputNode();
std::vector<Socket> output_sockets =
output_node->m_socket_accessor->m_inputs;
std::vector<Socket>::const_iterator iter = std::find_if(
output_sockets.begin(),
output_sockets.end(),
[&socket](const Socket& input_socket) {
return socket.m_name == input_socket.m_name;
});
if (iter != output_sockets.end()) {
return false;
}
output_node->m_socket_accessor->m_inputs.push_back(socket);
m_socket_accessor->m_outputs = output_node->m_socket_accessor->m_inputs;
return true;
}
void CreateStateMachineInstance(AnimGraphStateMachine& result) const; void CreateStateMachineInstance(AnimGraphStateMachine& result) const;
private: private:
+25 -15
View File
@@ -304,21 +304,11 @@ class EmbeddedTreeBlend2GraphResource {
embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource; embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource;
// Embedded: outputs // Embedded: outputs
AnimNodeResource* embedded_outputs = embedded_graph->RegisterBlendTreeOutputSocket<AnimData>("AnimOutput");
embedded_blend_tree_resource->GetGraphOutputNode();
embedded_outputs->m_socket_accessor->RegisterInput<AnimData>(
"AnimOutput",
nullptr);
// Embedded: inputs // Embedded: inputs
AnimNodeResource* embedded_inputs = embedded_graph->RegisterBlendTreeInputSocket<AnimData>("AnimInput");
embedded_blend_tree_resource->GetGraphInputNode(); embedded_graph->RegisterBlendTreeInputSocket<float>("BlendWeight");
embedded_inputs->m_socket_accessor->RegisterOutput<AnimData>(
"AnimInput",
nullptr);
embedded_inputs->m_socket_accessor->RegisterOutput<float>(
"BlendWeight",
nullptr);
// Embedded nodes // Embedded nodes
embedded_blend2_node_index = embedded_blend_tree_resource->AddNode( embedded_blend2_node_index = embedded_blend_tree_resource->AddNode(
@@ -343,7 +333,7 @@ class EmbeddedTreeBlend2GraphResource {
// Embedded: setup connections // Embedded: setup connections
REQUIRE(embedded_blend_tree_resource->ConnectSockets( REQUIRE(embedded_blend_tree_resource->ConnectSockets(
embedded_inputs, embedded_blend_tree_resource->GetGraphInputNode(),
"AnimInput", "AnimInput",
embedded_blend2_node_resource, embedded_blend2_node_resource,
"Input0")); "Input0"));
@@ -358,7 +348,7 @@ class EmbeddedTreeBlend2GraphResource {
embedded_blend_tree_resource->GetGraphOutputNode(), embedded_blend_tree_resource->GetGraphOutputNode(),
"AnimOutput")); "AnimOutput"));
REQUIRE(embedded_blend_tree_resource->ConnectSockets( REQUIRE(embedded_blend_tree_resource->ConnectSockets(
embedded_inputs, embedded_blend_tree_resource->GetGraphInputNode(),
"BlendWeight", "BlendWeight",
embedded_blend2_node_resource, embedded_blend2_node_resource,
"Weight")); "Weight"));
@@ -1341,4 +1331,24 @@ TEST_CASE_METHOD(
} }
graph_context.freeAnimations(); graph_context.freeAnimations();
}
TEST_CASE(
"Register AnimGraphResource Blendtree Sockets",
"[AnimGraphResource]") {
AnimNodeResource* blend_tree_anim_node_resource =
AnimNodeResourceFactory("BlendTree");
AnimGraphResource* blend_tree_graph_resource =
dynamic_cast<AnimGraphResource*>(blend_tree_anim_node_resource);
Socket socket;
socket.m_name = "FloatSocket";
socket.m_type = SocketType::SocketTypeFloat;
socket.m_reference.ptr = nullptr;
CHECK(blend_tree_graph_resource->RegisterBlendTreeInputSocket(socket));
CHECK(!blend_tree_graph_resource->RegisterBlendTreeInputSocket(socket));
CHECK(blend_tree_graph_resource->RegisterBlendTreeOutputSocket(socket));
CHECK(!blend_tree_graph_resource->RegisterBlendTreeOutputSocket(socket));
} }