2022-02-11 16:51:18 +01:00
|
|
|
//
|
|
|
|
// Created by martin on 11.02.22.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "AnimGraphEditor.h"
|
|
|
|
|
2023-03-30 18:11:54 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
2024-03-01 14:26:52 +01:00
|
|
|
#include "3rdparty/imgui-node-editor/imgui_node_editor.h"
|
2024-04-01 12:33:23 +02:00
|
|
|
#include "AnimGraphResource.h"
|
2023-03-30 18:11:54 +02:00
|
|
|
#include "SkinnedMesh.h"
|
2022-03-25 11:46:44 +01:00
|
|
|
#include "imgui.h"
|
2022-02-12 12:06:25 +01:00
|
|
|
#include "imnodes.h"
|
2022-03-25 11:46:44 +01:00
|
|
|
#include "misc/cpp/imgui_stdlib.h"
|
2022-02-18 23:33:30 +01:00
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
static AnimGraphResource sGraphGresource = AnimGraphResource();
|
2024-03-03 20:20:24 +01:00
|
|
|
static bool sGraphLoadedThisFrame = false;
|
2023-03-26 23:39:11 +02:00
|
|
|
|
2022-02-14 22:37:19 +01:00
|
|
|
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
|
|
|
switch (socket_type) {
|
|
|
|
case SocketType::SocketTypeAnimation:
|
|
|
|
return ImNodesPinShape_QuadFilled;
|
2023-04-02 21:40:49 +02:00
|
|
|
case SocketType::SocketTypeInt:
|
|
|
|
return ImNodesPinShape_CircleFilled;
|
2022-02-14 22:37:19 +01:00
|
|
|
case SocketType::SocketTypeFloat:
|
|
|
|
return ImNodesPinShape_CircleFilled;
|
|
|
|
case SocketType::SocketTypeVec3:
|
|
|
|
return ImNodesPinShape_TriangleFilled;
|
|
|
|
case SocketType::SocketTypeQuat:
|
|
|
|
return ImNodesPinShape_Triangle;
|
|
|
|
case SocketType::SocketTypeBool:
|
|
|
|
return ImNodesPinShape_Circle;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ImNodesPinShape_Quad;
|
|
|
|
}
|
2022-02-11 16:51:18 +01:00
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
void NodeSocketEditor(Socket& socket) {
|
|
|
|
int mode_current = static_cast<int>(socket.m_type);
|
|
|
|
ImGui::InputText("Name", &socket.m_name);
|
|
|
|
if (ImGui::Combo(
|
|
|
|
"Type",
|
|
|
|
&mode_current,
|
|
|
|
SocketTypeNames,
|
|
|
|
sizeof(SocketTypeNames) / sizeof(char*))) {
|
|
|
|
socket.m_type = static_cast<SocketType>(mode_current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
void RemoveBlendTreeConnectionsForSocket(
|
|
|
|
BlendTreeResource& blend_tree_resource,
|
|
|
|
AnimNodeResource* node_resource,
|
2022-03-25 11:46:44 +01:00
|
|
|
Socket& socket) {
|
2024-04-25 21:12:08 +02:00
|
|
|
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);
|
2022-03-25 11:46:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-30 18:11:54 +02:00
|
|
|
void SyncTrackEditor(SyncTrack* sync_track) {
|
|
|
|
ImGui::SliderFloat("duration", &sync_track->m_duration, 0.001f, 10.f);
|
|
|
|
|
|
|
|
ImGui::Text("Marker");
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::Text("%d", sync_track->m_num_intervals);
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("+")) {
|
|
|
|
if (sync_track->m_num_intervals < cSyncTrackMaxIntervals) {
|
2023-04-01 14:16:20 +02:00
|
|
|
sync_track->m_num_intervals++;
|
2023-03-30 18:11:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("-")) {
|
|
|
|
if (sync_track->m_num_intervals > 0) {
|
2023-04-01 14:16:20 +02:00
|
|
|
sync_track->m_num_intervals--;
|
2023-03-30 18:11:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Text("Marker:");
|
|
|
|
for (int i = 0; i < sync_track->m_num_intervals; i++) {
|
|
|
|
ImGui::Text("%2d:", i);
|
|
|
|
ImGui::SameLine();
|
|
|
|
std::ostringstream marker_stream;
|
|
|
|
marker_stream << i;
|
|
|
|
ImGui::SliderFloat(
|
|
|
|
marker_stream.str().c_str(),
|
|
|
|
&sync_track->m_sync_markers[i],
|
|
|
|
0.f,
|
|
|
|
1.f);
|
|
|
|
}
|
|
|
|
|
2023-04-01 14:16:20 +02:00
|
|
|
if (ImGui::Button("Update Intervals")) {
|
2023-03-30 18:11:54 +02:00
|
|
|
sync_track->CalcIntervals();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkinnedMeshWidget(SkinnedMesh* skinned_mesh) {
|
|
|
|
if (ImGui::TreeNode("Bones")) {
|
|
|
|
for (int i = 0; i < skinned_mesh->m_skeleton.num_joints(); i++) {
|
|
|
|
ImGui::Text("%s", skinned_mesh->m_skeleton.joint_names()[i]);
|
|
|
|
}
|
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::Text("Animations");
|
|
|
|
|
|
|
|
const char* items[255] = {0};
|
|
|
|
static int selected = -1;
|
|
|
|
for (int i = 0; i < skinned_mesh->m_animations.size(); i++) {
|
|
|
|
items[i] = skinned_mesh->m_animation_names[i].c_str();
|
|
|
|
}
|
|
|
|
|
2023-04-01 14:16:20 +02:00
|
|
|
ImGui::Combo(
|
|
|
|
"Animation",
|
|
|
|
&selected,
|
|
|
|
items,
|
|
|
|
skinned_mesh->m_animations.size());
|
2023-03-30 18:11:54 +02:00
|
|
|
|
|
|
|
ImGui::Text("Sync Track");
|
|
|
|
if (selected >= 0 && selected < skinned_mesh->m_animations.size()) {
|
|
|
|
SyncTrackEditor(&skinned_mesh->m_animation_sync_track[selected]);
|
|
|
|
skinned_mesh->m_override_anim = selected;
|
|
|
|
|
|
|
|
ImGui::Checkbox("Override Animation", &skinned_mesh->m_sync_track_override);
|
|
|
|
if (skinned_mesh->m_sync_track_override) {
|
|
|
|
ImGui::SliderFloat("Ratio", &skinned_mesh->m_override_ratio, 0.f, 1.f);
|
|
|
|
|
|
|
|
ozz::animation::SamplingJob sampling_job;
|
|
|
|
sampling_job.animation = skinned_mesh->m_animations[selected];
|
|
|
|
sampling_job.context = &skinned_mesh->m_sampling_context;
|
|
|
|
sampling_job.ratio = skinned_mesh->m_override_ratio;
|
|
|
|
sampling_job.output = make_span(skinned_mesh->m_local_matrices);
|
|
|
|
if (!sampling_job.Run()) {
|
|
|
|
ozz::log::Err() << "Error sampling animation." << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
void AnimGraphEditorRenderSidebar(
|
2024-04-05 00:44:37 +02:00
|
|
|
BlendTreeResource& blend_tree_resource,
|
|
|
|
AnimNodeResource* node_resource) {
|
|
|
|
ImGui::Text("[%s]", node_resource->m_node_type_name.c_str());
|
2022-02-18 22:24:19 +01:00
|
|
|
|
|
|
|
char node_name_buffer[256];
|
|
|
|
memset(node_name_buffer, 0, sizeof(node_name_buffer));
|
|
|
|
strncpy(
|
|
|
|
node_name_buffer,
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_name.c_str(),
|
|
|
|
std::min(node_resource->m_name.size(), sizeof(node_name_buffer)));
|
2022-02-18 22:24:19 +01:00
|
|
|
|
|
|
|
if (ImGui::InputText("Name", node_name_buffer, sizeof(node_name_buffer))) {
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_name = node_name_buffer;
|
2022-02-18 22:24:19 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
int num_properties = node_resource->m_socket_accessor->m_properties.size();
|
2022-02-18 22:24:19 +01:00
|
|
|
for (int i = 0; i < num_properties; i++) {
|
2024-04-05 00:44:37 +02:00
|
|
|
Socket& property = node_resource->m_socket_accessor->m_properties[i];
|
2023-04-02 21:40:49 +02:00
|
|
|
if (property.m_type == SocketType::SocketTypeInt) {
|
|
|
|
ImGui::InputInt(
|
|
|
|
property.m_name.c_str(),
|
|
|
|
reinterpret_cast<int*>(&property.m_value.int_value),
|
|
|
|
1);
|
|
|
|
} else if (property.m_type == SocketType::SocketTypeFloat) {
|
2022-02-18 22:24:19 +01:00
|
|
|
ImGui::SliderFloat(
|
|
|
|
property.m_name.c_str(),
|
2023-03-28 22:00:58 +02:00
|
|
|
reinterpret_cast<float*>(&property.m_value.float_value),
|
2022-02-18 22:24:19 +01:00
|
|
|
-100.f,
|
|
|
|
100.f);
|
|
|
|
} else if (property.m_type == SocketType::SocketTypeBool) {
|
2023-04-02 21:24:12 +02:00
|
|
|
bool flag_value = property.GetValue<bool>();
|
2024-03-03 20:20:24 +01:00
|
|
|
if (ImGui::Checkbox(property.m_name.c_str(), &flag_value)) {
|
2023-04-02 21:24:12 +02:00
|
|
|
property.SetValue(flag_value);
|
|
|
|
}
|
2022-02-18 22:24:19 +01:00
|
|
|
} else if (property.m_type == SocketType::SocketTypeString) {
|
2023-03-26 23:39:11 +02:00
|
|
|
char string_buf[1024];
|
2023-04-01 14:16:20 +02:00
|
|
|
memset(string_buf, '\0', sizeof(string_buf));
|
|
|
|
memcpy(
|
|
|
|
string_buf,
|
|
|
|
property.m_value_string.c_str(),
|
|
|
|
std::min(
|
|
|
|
static_cast<size_t>(1024),
|
|
|
|
property.m_value_string.size() + 1));
|
2022-02-18 22:24:19 +01:00
|
|
|
if (ImGui::InputText(
|
|
|
|
property.m_name.c_str(),
|
|
|
|
string_buf,
|
|
|
|
sizeof(string_buf))) {
|
2023-04-01 14:16:20 +02:00
|
|
|
property.m_value_string = string_buf;
|
2022-02-18 22:24:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-25 11:46:44 +01:00
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
if (node_resource == blend_tree_resource.GetGraphOutputNode()) {
|
2022-03-25 11:46:44 +01:00
|
|
|
ImGui::Text("Outputs");
|
|
|
|
|
|
|
|
// Graph outputs are the inputs of the output node!
|
2024-04-05 00:44:37 +02:00
|
|
|
std::vector<Socket>& outputs = node_resource->m_socket_accessor->m_inputs;
|
2022-03-25 11:46:44 +01:00
|
|
|
|
|
|
|
std::vector<Socket>::iterator iter = outputs.begin();
|
|
|
|
while (iter != outputs.end()) {
|
|
|
|
Socket& output = *iter;
|
|
|
|
ImGui::PushID(&output);
|
|
|
|
NodeSocketEditor(output);
|
|
|
|
if (ImGui::Button("X")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
RemoveBlendTreeConnectionsForSocket(
|
|
|
|
blend_tree_resource,
|
|
|
|
node_resource,
|
|
|
|
output);
|
2022-03-25 11:46:44 +01:00
|
|
|
iter = outputs.erase(iter);
|
|
|
|
} else {
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
if (node_resource == blend_tree_resource.GetGraphInputNode()) {
|
2022-03-25 11:46:44 +01:00
|
|
|
ImGui::Text("Inputs");
|
|
|
|
|
|
|
|
// Graph inputs are the outputs of the input node!
|
2024-04-05 00:44:37 +02:00
|
|
|
std::vector<Socket>& inputs = node_resource->m_socket_accessor->m_outputs;
|
2022-03-25 11:46:44 +01:00
|
|
|
|
|
|
|
std::vector<Socket>::iterator iter = inputs.begin();
|
|
|
|
while (iter != inputs.end()) {
|
|
|
|
Socket& input = *iter;
|
|
|
|
ImGui::PushID(&input);
|
|
|
|
NodeSocketEditor(input);
|
|
|
|
if (ImGui::Button("X")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
RemoveBlendTreeConnectionsForSocket(
|
|
|
|
blend_tree_resource,
|
|
|
|
node_resource,
|
|
|
|
input);
|
2022-03-25 11:46:44 +01:00
|
|
|
iter = inputs.erase(iter);
|
|
|
|
} else {
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
|
|
|
}
|
|
|
|
}
|
2022-02-18 22:24:19 +01:00
|
|
|
}
|
|
|
|
|
2024-04-25 21:12:08 +02:00
|
|
|
void AnimGraphEditorClear() {
|
|
|
|
sGraphGresource.Clear();
|
|
|
|
sGraphGresource.m_blend_tree_resource.InitGraphConnectors();
|
|
|
|
sGraphGresource.m_graph_type_name = "BlendTree";
|
|
|
|
}
|
|
|
|
|
2024-03-01 14:26:52 +01:00
|
|
|
void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) {
|
|
|
|
ImGui::BeginMenuBar();
|
|
|
|
if (ImGui::Button("Save")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.SaveToFile("editor_graph.json");
|
2024-03-01 14:26:52 +01:00
|
|
|
}
|
|
|
|
if (ImGui::Button("Load")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.LoadFromFile("editor_graph.json");
|
2024-03-03 20:20:24 +01:00
|
|
|
sGraphLoadedThisFrame = true;
|
2024-03-01 14:26:52 +01:00
|
|
|
}
|
|
|
|
if (ImGui::Button("Clear")) {
|
2024-04-25 21:12:08 +02:00
|
|
|
AnimGraphEditorClear();
|
2024-03-01 14:26:52 +01:00
|
|
|
}
|
|
|
|
char graph_name_buffer[256];
|
|
|
|
memset(graph_name_buffer, 0, sizeof(graph_name_buffer));
|
|
|
|
strncpy(
|
|
|
|
graph_name_buffer,
|
|
|
|
sGraphGresource.m_name.c_str(),
|
|
|
|
sizeof(graph_name_buffer));
|
|
|
|
if (ImGui::InputText("Name", graph_name_buffer, sizeof(graph_name_buffer))) {
|
|
|
|
sGraphGresource.m_name = graph_name_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndMenuBar();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Node editor canvas
|
|
|
|
//
|
|
|
|
ax::NodeEditor::SetCurrentEditor(context);
|
|
|
|
ax::NodeEditor::Begin("Graph Editor");
|
|
|
|
|
2024-03-03 20:20:24 +01:00
|
|
|
#if 1
|
2024-04-05 00:44:37 +02:00
|
|
|
for (size_t node_id = 0,
|
2024-04-24 21:58:47 +02:00
|
|
|
n = sGraphGresource.m_blend_tree_resource.GetNumNodes();
|
2024-04-05 00:44:37 +02:00
|
|
|
node_id < n;
|
2024-03-01 14:26:52 +01:00
|
|
|
node_id++) {
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimNodeResource* node_resource =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(node_id);
|
2024-03-01 14:26:52 +01:00
|
|
|
|
|
|
|
if (node_id == 0 || node_id == 1) {
|
|
|
|
// continue;
|
|
|
|
}
|
|
|
|
|
2024-03-03 20:20:24 +01:00
|
|
|
if (sGraphLoadedThisFrame) {
|
|
|
|
ax::NodeEditor::SetNodePosition(
|
|
|
|
node_id,
|
2024-04-05 00:44:37 +02:00
|
|
|
ImVec2(node_resource->m_position[0], node_resource->m_position[1]));
|
2024-03-03 20:20:24 +01:00
|
|
|
}
|
2024-03-01 14:26:52 +01:00
|
|
|
ax::NodeEditor::BeginNode(node_id);
|
2024-04-05 00:44:37 +02:00
|
|
|
ImGui::Text("%s", node_resource->m_node_type_name.c_str());
|
2024-03-01 14:26:52 +01:00
|
|
|
|
|
|
|
// Inputs
|
|
|
|
std::vector<Socket>& node_inputs =
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_socket_accessor->m_inputs;
|
2024-03-01 14:26:52 +01:00
|
|
|
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
|
|
|
Socket& socket = node_inputs[j];
|
2024-03-03 20:20:24 +01:00
|
|
|
ax::NodeEditor::BeginPin(
|
2024-04-25 21:12:08 +02:00
|
|
|
NodeIndexAndSocketIndexToInputPinId(
|
|
|
|
static_cast<int>(node_id),
|
|
|
|
static_cast<int>(j)),
|
2024-03-03 20:20:24 +01:00
|
|
|
ax::NodeEditor::PinKind::Input);
|
2024-03-01 14:26:52 +01:00
|
|
|
ImGui::Text("%s", socket.m_name.c_str());
|
|
|
|
ax::NodeEditor::EndPin();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outputs
|
2024-03-03 20:20:24 +01:00
|
|
|
std::vector<Socket>& node_outputs =
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_socket_accessor->m_outputs;
|
2024-03-01 14:26:52 +01:00
|
|
|
for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) {
|
2024-03-03 20:20:24 +01:00
|
|
|
Socket& socket = node_outputs[j];
|
|
|
|
ax::NodeEditor::BeginPin(
|
2024-04-25 21:12:08 +02:00
|
|
|
NodeIndexAndSocketIndexToOutputPinId(
|
|
|
|
static_cast<int>(node_id),
|
|
|
|
static_cast<int>(j)),
|
2024-03-03 20:20:24 +01:00
|
|
|
ax::NodeEditor::PinKind::Output);
|
2024-03-01 14:26:52 +01:00
|
|
|
ImGui::Text("%s", socket.m_name.c_str());
|
|
|
|
ax::NodeEditor::EndPin();
|
|
|
|
}
|
|
|
|
|
|
|
|
ax::NodeEditor::EndNode();
|
2024-04-25 21:12:08 +02:00
|
|
|
|
|
|
|
ImVec2 node_position = ax::NodeEditor::GetNodePosition(node_id);
|
|
|
|
node_resource->m_position[0] = node_position.x;
|
|
|
|
node_resource->m_position[1] = node_position.y;
|
2024-03-01 14:26:52 +01:00
|
|
|
}
|
|
|
|
|
2024-03-03 20:20:24 +01:00
|
|
|
int link_id = 0;
|
2024-04-05 00:44:37 +02:00
|
|
|
for (size_t connection_id = 0,
|
2024-04-24 21:58:47 +02:00
|
|
|
n = sGraphGresource.m_blend_tree_resource.GetNumConnections();
|
2024-04-05 00:44:37 +02:00
|
|
|
connection_id < n;
|
2024-03-03 20:20:24 +01:00
|
|
|
connection_id++) {
|
2024-04-24 21:58:47 +02:00
|
|
|
const BlendTreeConnectionResource* connection_resource =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetConnection(connection_id);
|
2024-04-05 00:44:37 +02:00
|
|
|
|
|
|
|
const AnimNodeResource* source_node_resource =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection_resource->source_node_index);
|
2024-04-05 00:44:37 +02:00
|
|
|
int source_socket_index =
|
|
|
|
source_node_resource->m_socket_accessor->GetOutputIndex(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection_resource->source_socket_name.c_str());
|
2024-04-05 00:44:37 +02:00
|
|
|
|
|
|
|
const AnimNodeResource* target_node_resource =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection_resource->target_node_index);
|
2024-04-05 00:44:37 +02:00
|
|
|
int target_socket_index =
|
|
|
|
target_node_resource->m_socket_accessor->GetInputIndex(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection_resource->target_socket_name.c_str());
|
2024-04-05 00:44:37 +02:00
|
|
|
|
2024-04-25 21:12:08 +02:00
|
|
|
int source_socket_pin_id = NodeIndexAndSocketIndexToOutputPinId(
|
2024-04-24 21:58:47 +02:00
|
|
|
static_cast<int>(connection_resource->source_node_index),
|
2024-04-05 00:44:37 +02:00
|
|
|
source_socket_index);
|
2024-04-25 21:12:08 +02:00
|
|
|
int target_socket_pin_id = NodeIndexAndSocketIndexToInputPinId(
|
2024-04-24 21:58:47 +02:00
|
|
|
static_cast<int>(connection_resource->target_node_index),
|
2024-04-05 00:44:37 +02:00
|
|
|
target_socket_index);
|
2024-03-03 20:20:24 +01:00
|
|
|
|
2024-04-25 21:12:08 +02:00
|
|
|
ax::NodeEditor::Link(link_id++, source_socket_pin_id, target_socket_pin_id);
|
2024-03-03 20:20:24 +01:00
|
|
|
}
|
2024-03-01 14:26:52 +01:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2024-03-03 20:20:24 +01:00
|
|
|
#if 1
|
2024-03-01 14:26:52 +01:00
|
|
|
// Create Connections
|
|
|
|
if (ax::NodeEditor::BeginCreate()) {
|
|
|
|
ax::NodeEditor::PinId input_pin_id, output_pin_id;
|
|
|
|
if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) {
|
|
|
|
if (input_pin_id && output_pin_id) {
|
|
|
|
if (ax::NodeEditor::AcceptNewItem()) {
|
2024-04-25 21:12:08 +02:00
|
|
|
int source_node_index;
|
|
|
|
int source_node_socket_index;
|
|
|
|
|
|
|
|
OutputPinIdToNodeIndexAndSocketIndex(
|
|
|
|
input_pin_id.Get(),
|
|
|
|
&source_node_index,
|
|
|
|
&source_node_socket_index);
|
|
|
|
|
|
|
|
const AnimNodeResource* source_node =
|
|
|
|
sGraphGresource.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int target_node_index;
|
|
|
|
int target_node_socket_index;
|
|
|
|
|
|
|
|
InputPinIdToNodeIndexAndSocketIndex(
|
|
|
|
output_pin_id.Get(),
|
|
|
|
&target_node_index,
|
|
|
|
&target_node_socket_index);
|
|
|
|
|
|
|
|
const AnimNodeResource* target_node =
|
|
|
|
sGraphGresource.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source_node_socket_index == -1
|
|
|
|
|| target_node_socket_index == -1) {
|
|
|
|
ax::NodeEditor::RejectNewItem();
|
|
|
|
} else {
|
|
|
|
const std::string& source_socket_name =
|
|
|
|
source_node->m_socket_accessor
|
|
|
|
->m_outputs[source_node_socket_index]
|
|
|
|
.m_name;
|
|
|
|
|
|
|
|
const std::string& target_socket_name =
|
|
|
|
target_node->m_socket_accessor
|
|
|
|
->m_inputs[target_node_socket_index]
|
|
|
|
.m_name;
|
|
|
|
|
|
|
|
sGraphGresource.m_blend_tree_resource.ConnectSockets(
|
|
|
|
source_node,
|
|
|
|
source_socket_name,
|
|
|
|
target_node,
|
|
|
|
target_socket_name);
|
|
|
|
}
|
2024-03-01 14:26:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ax::NodeEditor::EndCreate();
|
2024-03-03 20:20:24 +01:00
|
|
|
#endif
|
2024-03-01 14:26:52 +01:00
|
|
|
|
2024-04-25 21:12:08 +02:00
|
|
|
// Popup menu
|
|
|
|
{
|
|
|
|
const bool open_popup = ImGui::IsMouseReleased(ImGuiMouseButton_Right);
|
|
|
|
|
|
|
|
ImVec2 popup_mouse_position = ImGui::GetMousePos();
|
|
|
|
|
|
|
|
ax::NodeEditor::Suspend();
|
|
|
|
if (open_popup) {
|
|
|
|
ImGui::OpenPopup("add node");
|
|
|
|
}
|
|
|
|
ax::NodeEditor::Resume();
|
|
|
|
|
|
|
|
ax::NodeEditor::Suspend();
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
|
|
|
|
if (ImGui::BeginPopup("add node")) {
|
|
|
|
std::string node_type_name = "";
|
|
|
|
if (ImGui::MenuItem("AnimSampler")) {
|
|
|
|
node_type_name = "AnimSampler";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Blend2")) {
|
|
|
|
node_type_name = "Blend2";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("SpeedScale")) {
|
|
|
|
node_type_name = "SpeedScale";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("LockTranslationNode")) {
|
|
|
|
node_type_name = "LockTranslationNode";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("MathAddNode")) {
|
|
|
|
node_type_name = "MathAddNode";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("MathFloatToVec3Node")) {
|
|
|
|
node_type_name = "MathFloatToVec3Node";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("ConstScalarNode")) {
|
|
|
|
node_type_name = "ConstScalarNode";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node_type_name.empty()) {
|
|
|
|
AnimNodeResource* node_resource =
|
|
|
|
AnimNodeResourceFactory(node_type_name);
|
|
|
|
size_t node_id = sGraphGresource.m_blend_tree_resource.GetNumNodes();
|
|
|
|
ax::NodeEditor::SetNodePosition(node_id, popup_mouse_position);
|
|
|
|
sGraphGresource.m_blend_tree_resource.AddNode(node_resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
ImGui::PopStyleVar();
|
|
|
|
ax::NodeEditor::Resume();
|
|
|
|
}
|
|
|
|
|
2024-03-01 14:26:52 +01:00
|
|
|
ax::NodeEditor::End();
|
|
|
|
|
2024-03-03 20:20:24 +01:00
|
|
|
sGraphLoadedThisFrame = false;
|
|
|
|
|
2024-03-01 14:26:52 +01:00
|
|
|
ax::NodeEditor::SetCurrentEditor(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LegacyAnimGraphEditorUpdate() {
|
2022-02-11 16:51:18 +01:00
|
|
|
ImGui::BeginMenuBar();
|
|
|
|
if (ImGui::Button("Save")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.SaveToFile("editor_graph.json");
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
if (ImGui::Button("Load")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.LoadFromFile("editor_graph.json");
|
2022-02-11 16:51:18 +01:00
|
|
|
|
2024-04-24 21:58:47 +02:00
|
|
|
for (size_t i = 0, n = sGraphGresource.m_blend_tree_resource.GetNumNodes();
|
2024-04-05 00:44:37 +02:00
|
|
|
i < n;
|
|
|
|
i++) {
|
|
|
|
const AnimNodeResource* node_resource =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(i);
|
2022-02-12 12:06:25 +01:00
|
|
|
ImNodes::SetNodeGridSpacePos(
|
|
|
|
i,
|
2024-04-05 00:44:37 +02:00
|
|
|
ImVec2(node_resource->m_position[0], node_resource->m_position[1]));
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ImGui::Button("Clear")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.Clear();
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
char graph_name_buffer[256];
|
2022-02-12 12:06:25 +01:00
|
|
|
memset(graph_name_buffer, 0, sizeof(graph_name_buffer));
|
|
|
|
strncpy(
|
|
|
|
graph_name_buffer,
|
2023-03-26 23:39:11 +02:00
|
|
|
sGraphGresource.m_name.c_str(),
|
2022-02-12 12:06:25 +01:00
|
|
|
sizeof(graph_name_buffer));
|
2022-02-11 16:51:18 +01:00
|
|
|
if (ImGui::InputText("Name", graph_name_buffer, sizeof(graph_name_buffer))) {
|
2023-03-26 23:39:11 +02:00
|
|
|
sGraphGresource.m_name = graph_name_buffer;
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndMenuBar();
|
|
|
|
|
2022-02-18 22:24:19 +01:00
|
|
|
ImGui::Columns(2);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Node editor canvas
|
|
|
|
//
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::BeginNodeEditor();
|
|
|
|
|
2022-02-12 12:06:25 +01:00
|
|
|
// Popup menu
|
|
|
|
{
|
|
|
|
const bool open_popup =
|
|
|
|
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
|
|
|
|
&& ImNodes::IsEditorHovered()
|
|
|
|
&& ImGui::IsMouseReleased(ImGuiMouseButton_Right);
|
|
|
|
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
|
|
|
|
if (!ImGui::IsAnyItemHovered() && open_popup) {
|
|
|
|
ImGui::OpenPopup("add node");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::BeginPopup("add node")) {
|
|
|
|
const ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
|
|
|
|
std::string node_type_name = "";
|
|
|
|
if (ImGui::MenuItem("AnimSampler")) {
|
|
|
|
node_type_name = "AnimSampler";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Blend2")) {
|
|
|
|
node_type_name = "Blend2";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("SpeedScale")) {
|
|
|
|
node_type_name = "SpeedScale";
|
|
|
|
}
|
|
|
|
|
2023-04-02 21:40:49 +02:00
|
|
|
if (ImGui::MenuItem("LockTranslationNode")) {
|
|
|
|
node_type_name = "LockTranslationNode";
|
|
|
|
}
|
|
|
|
|
2022-04-03 21:05:11 +02:00
|
|
|
if (ImGui::MenuItem("MathAddNode")) {
|
|
|
|
node_type_name = "MathAddNode";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("MathFloatToVec3Node")) {
|
|
|
|
node_type_name = "MathFloatToVec3Node";
|
|
|
|
}
|
|
|
|
|
2023-03-28 22:00:58 +02:00
|
|
|
if (ImGui::MenuItem("ConstScalarNode")) {
|
|
|
|
node_type_name = "ConstScalarNode";
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:06:25 +01:00
|
|
|
if (node_type_name != "") {
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimNodeResource* node_resource =
|
2022-02-12 12:06:25 +01:00
|
|
|
AnimNodeResourceFactory(node_type_name);
|
2024-04-24 21:58:47 +02:00
|
|
|
size_t node_id = sGraphGresource.m_blend_tree_resource.GetNumNodes();
|
2022-02-12 12:06:25 +01:00
|
|
|
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.AddNode(node_resource);
|
2022-02-12 12:06:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::PopStyleVar(ImGuiStyleVar_WindowPadding);
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
|
2024-04-24 21:58:47 +02:00
|
|
|
for (size_t i = 0, n = sGraphGresource.m_blend_tree_resource.GetNumNodes();
|
2024-04-05 00:44:37 +02:00
|
|
|
i < n;
|
|
|
|
i++) {
|
|
|
|
AnimNodeResource* node_resource =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(i);
|
2022-02-11 16:51:18 +01:00
|
|
|
|
|
|
|
ImNodes::BeginNode(i);
|
2022-04-03 21:05:11 +02:00
|
|
|
ImGui::PushItemWidth(110.0f);
|
2022-02-11 16:51:18 +01:00
|
|
|
|
|
|
|
// Header
|
|
|
|
ImNodes::BeginNodeTitleBar();
|
2024-04-05 00:44:37 +02:00
|
|
|
if (node_resource
|
|
|
|
== sGraphGresource.m_blend_tree_resource.GetGraphOutputNode()) {
|
2022-02-15 21:06:12 +01:00
|
|
|
ImGui::TextUnformatted("Graph Outputs");
|
2024-04-05 00:44:37 +02:00
|
|
|
} else if (
|
|
|
|
node_resource
|
|
|
|
== sGraphGresource.m_blend_tree_resource.GetGraphInputNode()) {
|
2022-02-15 21:06:12 +01:00
|
|
|
ImGui::TextUnformatted("Graph Inputs");
|
|
|
|
} else {
|
2024-04-05 00:44:37 +02:00
|
|
|
ImGui::TextUnformatted(node_resource->m_node_type_name.c_str());
|
2022-02-15 21:06:12 +01:00
|
|
|
}
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::EndNodeTitleBar();
|
|
|
|
|
|
|
|
// Inputs
|
2023-04-01 22:53:53 +02:00
|
|
|
std::vector<Socket>& node_inputs =
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_socket_accessor->m_inputs;
|
2022-02-11 16:51:18 +01:00
|
|
|
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
2023-04-01 22:53:53 +02:00
|
|
|
Socket& socket = node_inputs[j];
|
2022-02-18 23:33:30 +01:00
|
|
|
|
|
|
|
ImColor socket_color = ImColor(255, 255, 255, 255);
|
|
|
|
if (socket.m_flags & SocketFlagAffectsTime) {
|
|
|
|
socket_color = ImColor(255, 128, 128, 255);
|
|
|
|
}
|
|
|
|
|
2022-02-14 22:37:19 +01:00
|
|
|
ImNodes::BeginInputAttribute(
|
|
|
|
GenerateInputAttributeId(i, j),
|
|
|
|
sGetSocketShapeFromSocketType(socket.m_type),
|
2022-02-18 23:33:30 +01:00
|
|
|
socket_color);
|
2022-02-19 12:16:57 +01:00
|
|
|
ImGui::TextUnformatted(socket.m_name.c_str());
|
2022-02-15 20:57:59 +01:00
|
|
|
|
2023-03-26 23:39:11 +02:00
|
|
|
bool socket_connected =
|
2024-04-05 00:44:37 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.IsSocketConnected(
|
|
|
|
node_resource,
|
|
|
|
socket.m_name);
|
2023-04-01 14:16:20 +02:00
|
|
|
if (!socket_connected && (socket.m_type == SocketType::SocketTypeFloat)) {
|
2022-04-03 21:05:11 +02:00
|
|
|
ImGui::SameLine();
|
2023-04-01 22:53:53 +02:00
|
|
|
float socket_value = socket.m_value.float_value;
|
2023-04-01 14:16:20 +02:00
|
|
|
ImGui::PushItemWidth(
|
|
|
|
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
2023-04-01 22:53:53 +02:00
|
|
|
if (ImGui::DragFloat("##hidelabel", &socket_value, 0.01f)) {
|
|
|
|
socket.SetValue(socket_value);
|
|
|
|
}
|
2022-04-03 21:05:11 +02:00
|
|
|
ImGui::PopItemWidth();
|
|
|
|
}
|
|
|
|
|
2023-04-02 21:40:49 +02:00
|
|
|
if (!socket_connected && (socket.m_type == SocketType::SocketTypeInt)) {
|
|
|
|
ImGui::SameLine();
|
|
|
|
int socket_value = socket.m_value.int_value;
|
|
|
|
ImGui::PushItemWidth(
|
|
|
|
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
|
|
|
if (ImGui::InputInt("##hidelabel", &socket_value, 1)) {
|
|
|
|
socket.SetValue(socket_value);
|
|
|
|
}
|
|
|
|
ImGui::PopItemWidth();
|
|
|
|
}
|
|
|
|
|
2022-02-18 22:24:19 +01:00
|
|
|
ImNodes::PushAttributeFlag(
|
|
|
|
ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::EndInputAttribute();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outputs
|
2022-02-12 12:06:25 +01:00
|
|
|
const std::vector<Socket>& node_outputs =
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_socket_accessor->m_outputs;
|
2022-02-11 16:51:18 +01:00
|
|
|
for (size_t j = 0, ni = node_outputs.size(); j < ni; j++) {
|
|
|
|
const Socket& socket = node_outputs[j];
|
2022-02-14 22:37:19 +01:00
|
|
|
ImNodes::BeginOutputAttribute(
|
|
|
|
GenerateOutputAttributeId(i, j),
|
|
|
|
sGetSocketShapeFromSocketType(socket.m_type),
|
|
|
|
ImColor(255, 255, 255, 255));
|
2022-02-19 12:16:57 +01:00
|
|
|
ImGui::TextUnformatted(socket.m_name.c_str());
|
2022-02-18 22:24:19 +01:00
|
|
|
ImNodes::PushAttributeFlag(
|
|
|
|
ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::EndInputAttribute();
|
|
|
|
}
|
|
|
|
|
2022-02-15 21:06:12 +01:00
|
|
|
// Graph output node
|
|
|
|
if (i == 0) {
|
|
|
|
if (ImGui::Button("+Output")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimNodeResource* graph_output_node =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetGraphOutputNode();
|
2022-02-15 21:06:12 +01:00
|
|
|
|
|
|
|
static float bla = 0.f;
|
|
|
|
std::string socket_name = "Output";
|
2022-02-18 22:24:19 +01:00
|
|
|
socket_name += std::to_string(
|
2024-04-05 00:44:37 +02:00
|
|
|
graph_output_node->m_socket_accessor->m_inputs.size());
|
|
|
|
graph_output_node->m_socket_accessor->RegisterInput<float>(
|
2023-04-01 14:16:20 +02:00
|
|
|
socket_name.c_str(),
|
2022-02-15 21:06:12 +01:00
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
} else if (i == 1) {
|
|
|
|
if (ImGui::Button("+Input")) {
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimNodeResource* graph_input_node =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetGraphInputNode();
|
2022-02-15 21:06:12 +01:00
|
|
|
|
|
|
|
static float bla = 0.f;
|
|
|
|
std::string socket_name = "Input";
|
2022-02-18 22:24:19 +01:00
|
|
|
socket_name += std::to_string(
|
2024-04-05 00:44:37 +02:00
|
|
|
graph_input_node->m_socket_accessor->m_outputs.size());
|
|
|
|
graph_input_node->m_socket_accessor->RegisterOutput<float>(
|
2023-04-01 14:16:20 +02:00
|
|
|
socket_name.c_str(),
|
2022-02-15 21:06:12 +01:00
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-11 16:51:18 +01:00
|
|
|
// Save state in node resource
|
|
|
|
ImVec2 node_pos = ImNodes::GetNodeGridSpacePos(i);
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_position[0] = node_pos[0];
|
|
|
|
node_resource->m_position[1] = node_pos[1];
|
2022-04-03 21:05:11 +02:00
|
|
|
ImGui::PopItemWidth();
|
|
|
|
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::EndNode();
|
2022-02-18 23:33:30 +01:00
|
|
|
|
|
|
|
// Ensure flags such as SocketFlagAffectsTime are properly set.
|
2024-04-05 00:44:37 +02:00
|
|
|
node_resource->m_socket_accessor->UpdateFlags();
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
for (size_t i = 0,
|
2024-04-24 21:58:47 +02:00
|
|
|
n = sGraphGresource.m_blend_tree_resource.GetNumConnections();
|
2024-04-05 00:44:37 +02:00
|
|
|
i < n;
|
|
|
|
i++) {
|
2024-04-24 21:58:47 +02:00
|
|
|
const BlendTreeConnectionResource* connection =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetConnection(i);
|
2022-02-11 16:51:18 +01:00
|
|
|
int start_attr, end_attr;
|
2022-03-25 11:46:44 +01:00
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
const AnimNodeResource* source_node =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection->source_node_index);
|
2024-04-05 00:44:37 +02:00
|
|
|
int source_socket_index = source_node->m_socket_accessor->GetOutputIndex(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection->source_socket_name.c_str());
|
2022-04-01 13:19:54 +02:00
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
const AnimNodeResource* target_node =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection->target_node_index);
|
2024-04-05 00:44:37 +02:00
|
|
|
int target_socket_index = target_node->m_socket_accessor->GetInputIndex(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection->target_socket_name.c_str());
|
2022-04-01 13:19:54 +02:00
|
|
|
|
|
|
|
start_attr = GenerateOutputAttributeId(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection->source_node_index,
|
2022-04-01 13:19:54 +02:00
|
|
|
source_socket_index);
|
|
|
|
end_attr = GenerateInputAttributeId(
|
2024-04-24 21:58:47 +02:00
|
|
|
connection->target_node_index,
|
2022-04-01 13:19:54 +02:00
|
|
|
target_socket_index);
|
2022-03-25 11:46:44 +01:00
|
|
|
|
2022-02-11 16:51:18 +01:00
|
|
|
ImNodes::Link(i, start_attr, end_attr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImNodes::EndNodeEditor();
|
|
|
|
|
2022-02-15 20:57:59 +01:00
|
|
|
// Handle newly created links.
|
2022-02-11 16:51:18 +01:00
|
|
|
int start_attr, end_attr;
|
|
|
|
if (ImNodes::IsLinkCreated(&start_attr, &end_attr)) {
|
|
|
|
int node_start_id;
|
|
|
|
int node_start_output_index;
|
2022-02-12 12:06:25 +01:00
|
|
|
SplitOutputAttributeId(
|
|
|
|
start_attr,
|
|
|
|
&node_start_id,
|
|
|
|
&node_start_output_index);
|
2022-02-11 16:51:18 +01:00
|
|
|
|
|
|
|
int node_end_id;
|
|
|
|
int node_end_input_index;
|
|
|
|
SplitInputAttributeId(end_attr, &node_end_id, &node_end_input_index);
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
BlendTreeConnectionResource connection;
|
2022-04-01 13:19:54 +02:00
|
|
|
connection.source_node_index = node_start_id;
|
2024-04-05 00:44:37 +02:00
|
|
|
const AnimNodeResource* source_node =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(node_start_id);
|
2022-04-01 13:19:54 +02:00
|
|
|
connection.source_socket_name =
|
2024-04-05 00:44:37 +02:00
|
|
|
source_node->m_socket_accessor->m_outputs[node_start_output_index]
|
2022-04-01 13:19:54 +02:00
|
|
|
.m_name;
|
|
|
|
|
|
|
|
connection.target_node_index = node_end_id;
|
2024-04-05 00:44:37 +02:00
|
|
|
const AnimNodeResource* target_node =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(node_end_id);
|
2022-04-01 13:19:54 +02:00
|
|
|
connection.target_socket_name =
|
2024-04-05 00:44:37 +02:00
|
|
|
target_node->m_socket_accessor->m_inputs[node_end_input_index].m_name;
|
2022-02-11 16:51:18 +01:00
|
|
|
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.ConnectSockets(
|
|
|
|
source_node,
|
|
|
|
connection.source_socket_name,
|
|
|
|
target_node,
|
|
|
|
connection.target_socket_name);
|
2023-03-26 23:39:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_Delete, false)) {
|
|
|
|
std::cerr << "Delete key!" << std::endl;
|
2022-02-15 20:57:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle link detachements.
|
|
|
|
int link_id = 0;
|
|
|
|
if (ImNodes::IsLinkDestroyed(&link_id)) {
|
2024-04-24 21:58:47 +02:00
|
|
|
BlendTreeConnectionResource* connection =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetConnection(link_id);
|
|
|
|
AnimNodeResource* source_node =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection->source_node_index);
|
|
|
|
AnimNodeResource* target_node =
|
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(
|
|
|
|
connection->target_node_index);
|
|
|
|
sGraphGresource.m_blend_tree_resource.DisconnectSockets(
|
|
|
|
source_node,
|
|
|
|
connection->source_socket_name,
|
|
|
|
target_node,
|
|
|
|
connection->target_socket_name);
|
2022-02-18 22:24:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int selected_nodes[ImNodes::NumSelectedNodes()];
|
|
|
|
ImNodes::GetSelectedNodes(selected_nodes);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sidebar
|
|
|
|
//
|
|
|
|
ImGui::NextColumn();
|
|
|
|
|
|
|
|
if (ImNodes::NumSelectedNodes() == 1) {
|
2024-04-05 00:44:37 +02:00
|
|
|
if (selected_nodes[0]
|
2024-04-24 21:58:47 +02:00
|
|
|
< sGraphGresource.m_blend_tree_resource.GetNumNodes()) {
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimNodeResource* selected_node =
|
2024-04-24 21:58:47 +02:00
|
|
|
sGraphGresource.m_blend_tree_resource.GetNode(selected_nodes[0]);
|
2024-04-05 00:44:37 +02:00
|
|
|
AnimGraphEditorRenderSidebar(
|
|
|
|
sGraphGresource.m_blend_tree_resource,
|
|
|
|
selected_node);
|
2022-02-18 22:24:19 +01:00
|
|
|
}
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|
2022-02-18 22:24:19 +01:00
|
|
|
|
|
|
|
ImGui::Columns(1);
|
2023-03-26 23:39:11 +02:00
|
|
|
}
|
|
|
|
|
2024-04-05 00:44:37 +02:00
|
|
|
void AnimGraphEditorGetRuntimeGraph(AnimGraphBlendTree& blend_tree) {
|
|
|
|
sGraphGresource.CreateBlendTreeInstance(blend_tree);
|
2022-02-11 16:51:18 +01:00
|
|
|
}
|