removing nodes causes problems!
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(graphs VERSION 0.1.6)
|
project(graphs VERSION 0.1.7)
|
||||||
|
|
||||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||||
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace conf
|
||||||
inline constexpr float DEFAULT_INITIAL_TEMPERATURE = 100;
|
inline constexpr float DEFAULT_INITIAL_TEMPERATURE = 100;
|
||||||
|
|
||||||
inline constexpr float POINT_SIZE = 35;
|
inline constexpr float POINT_SIZE = 35;
|
||||||
inline constexpr auto DEFAULT_IMAGE = "parker_point";
|
inline constexpr auto DEFAULT_IMAGE = "unknown";
|
||||||
inline constexpr auto POINT_OUTLINE_COLOR = blt::make_color(0, 0.6, 0.6);
|
inline constexpr auto POINT_OUTLINE_COLOR = blt::make_color(0, 0.6, 0.6);
|
||||||
inline constexpr auto POINT_HIGHLIGHT_COLOR = blt::make_color(0, 1.0, 1.0);
|
inline constexpr auto POINT_HIGHLIGHT_COLOR = blt::make_color(0, 1.0, 1.0);
|
||||||
inline constexpr auto POINT_SELECT_COLOR = blt::make_color(0, 0.9, 0.7);
|
inline constexpr auto POINT_SELECT_COLOR = blt::make_color(0, 0.9, 0.7);
|
||||||
|
|
|
@ -188,7 +188,7 @@ class engine_t
|
||||||
friend struct loader_t;
|
friend struct loader_t;
|
||||||
private:
|
private:
|
||||||
graph_t graph;
|
graph_t graph;
|
||||||
selector_t selector;
|
selector_t selector {graph};
|
||||||
|
|
||||||
void draw_gui(const blt::gfx::window_data& data);
|
void draw_gui(const blt::gfx::window_data& data);
|
||||||
|
|
||||||
|
@ -205,10 +205,12 @@ class engine_t
|
||||||
auto& io = ImGui::GetIO();
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
if (!io.WantCaptureMouse)
|
if (!io.WantCaptureMouse)
|
||||||
selector.process_mouse(graph, data.width, data.height);
|
selector.process_mouse(data.width, data.height);
|
||||||
|
if (!io.WantCaptureKeyboard)
|
||||||
|
selector.process_keyboard(data.width, data.height);
|
||||||
|
|
||||||
graph.render();
|
graph.render();
|
||||||
selector.render(graph, data.width, data.height);
|
selector.render(data.width, data.height);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,23 +24,36 @@
|
||||||
class selector_t
|
class selector_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit selector_t(graph_t& graph): graph(graph)
|
||||||
|
{}
|
||||||
|
|
||||||
// called inside the info panel block, used for adding more information
|
// called inside the info panel block, used for adding more information
|
||||||
void draw_gui(graph_t& graph, blt::i32 width, blt::i32 height);
|
void draw_gui(blt::i32 width, blt::i32 height);
|
||||||
|
|
||||||
// called once per frame, for rendering animations
|
// called once per frame, for rendering animations
|
||||||
void render(graph_t& graph, blt::i32 width, blt::i32 height);
|
void render(blt::i32 width, blt::i32 height);
|
||||||
|
|
||||||
// called once per frame assuming imgui doesn't want the mouse
|
// called once per frame assuming imgui doesn't want the mouse
|
||||||
void process_mouse(graph_t& graph, blt::i32 width, blt::i32 height);
|
void process_mouse(blt::i32 width, blt::i32 height);
|
||||||
|
|
||||||
|
void process_keyboard(blt::i32 width, blt::i32 height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_primary_selection(blt::i64 n);
|
void set_primary_selection(blt::i64 n);
|
||||||
|
|
||||||
void set_drag_selection(blt::i64 n);
|
void set_drag_selection(blt::i64 n);
|
||||||
|
|
||||||
void set_secondary_selection(blt::i64 n);
|
void set_secondary_selection(blt::i64 n);
|
||||||
|
|
||||||
|
void create_placement_node(const blt::vec2& pos);
|
||||||
|
void destroy_node(blt::i64 node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
blt::i64 drag_selection = -1;
|
blt::i64 drag_selection = -1;
|
||||||
blt::i64 primary_selection = -1;
|
blt::i64 primary_selection = -1;
|
||||||
blt::i64 secondary_selection = -1;
|
blt::i64 secondary_selection = -1;
|
||||||
bool edge = false;
|
bool placement = false;
|
||||||
|
graph_t& graph;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //GRAPHS_SELECTION_H
|
#endif //GRAPHS_SELECTION_H
|
||||||
|
|
After Width: | Height: | Size: 361 KiB |
After Width: | Height: | Size: 3.9 MiB |
After Width: | Height: | Size: 498 KiB |
After Width: | Height: | Size: 2.8 MiB |
After Width: | Height: | Size: 809 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 1.2 MiB |
|
@ -269,7 +269,7 @@ void engine_t::draw_gui(const blt::gfx::window_data& data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selector.draw_gui(graph, data.width, data.height);
|
selector.draw_gui(data.width, data.height);
|
||||||
im::End();
|
im::End();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/main.cpp
|
@ -54,6 +54,13 @@ void init(const blt::gfx::window_data& data)
|
||||||
resources.enqueue("res/parker.png", "parker");
|
resources.enqueue("res/parker.png", "parker");
|
||||||
resources.enqueue("res/parkerpoint.png", "parker_point");
|
resources.enqueue("res/parkerpoint.png", "parker_point");
|
||||||
resources.enqueue("res/parker cat ears.jpg", "parkercat");
|
resources.enqueue("res/parker cat ears.jpg", "parkercat");
|
||||||
|
resources.enqueue("res/ivy.jpg", "ivy");
|
||||||
|
resources.enqueue("res/sayori.jpg", "sayori");
|
||||||
|
resources.enqueue("res/jacob.jpg", "jacob");
|
||||||
|
resources.enqueue("res/braxton.jpg", "braxton");
|
||||||
|
resources.enqueue("res/ben.jpg", "ben");
|
||||||
|
resources.enqueue("res/no_image.jpg", "unknown");
|
||||||
|
resources.enqueue("res/me.png", "me");
|
||||||
|
|
||||||
if (auto loader = loader_t::load_for(engine, data, "default.json", "save.json"))
|
if (auto loader = loader_t::load_for(engine, data, "default.json", "save.json"))
|
||||||
{
|
{
|
||||||
|
@ -76,7 +83,8 @@ void update(const blt::gfx::window_data& data)
|
||||||
|
|
||||||
engine.render(data);
|
engine.render(data);
|
||||||
|
|
||||||
camera.update();
|
if (!im::GetIO().WantCaptureKeyboard)
|
||||||
|
camera.update();
|
||||||
camera.update_view(global_matrices);
|
camera.update_view(global_matrices);
|
||||||
global_matrices.update();
|
global_matrices.update();
|
||||||
|
|
||||||
|
|
160
src/selector.cpp
|
@ -18,71 +18,191 @@
|
||||||
#include <selection.h>
|
#include <selection.h>
|
||||||
#include <graph.h>
|
#include <graph.h>
|
||||||
#include <blt/gfx/raycast.h>
|
#include <blt/gfx/raycast.h>
|
||||||
|
#include <blt/std/memory.h>
|
||||||
|
|
||||||
extern blt::gfx::batch_renderer_2d renderer_2d;
|
extern blt::gfx::batch_renderer_2d renderer_2d;
|
||||||
extern blt::gfx::matrix_state_manager global_matrices;
|
extern blt::gfx::matrix_state_manager global_matrices;
|
||||||
|
|
||||||
void selector_t::render(graph_t& graph, blt::i32 width, blt::i32 height)
|
blt::expanding_buffer<char> name_input;
|
||||||
|
blt::expanding_buffer<char> texture_input;
|
||||||
|
blt::expanding_buffer<char> description_input;
|
||||||
|
|
||||||
|
struct callback_data_t
|
||||||
|
{
|
||||||
|
std::string& str;
|
||||||
|
blt::expanding_buffer<char>& buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
void from_string(std::string& str, blt::expanding_buffer<char>& buf)
|
||||||
|
{
|
||||||
|
if (buf.size() <= str.size())
|
||||||
|
buf.resize(str.size() + 1);
|
||||||
|
std::memcpy(buf.data(), str.data(), str.size());
|
||||||
|
buf.data()[str.size()] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int text_input_callback(ImGuiInputTextCallbackData* data)
|
||||||
|
{
|
||||||
|
auto [str, buffer] = *static_cast<callback_data_t*>(data->UserData);
|
||||||
|
|
||||||
|
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
|
||||||
|
{
|
||||||
|
buffer.resize(data->BufSize);
|
||||||
|
data->Buf = buffer.data();
|
||||||
|
} else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit || data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
|
||||||
|
str = std::string_view{data->Buf, static_cast<blt::size_t>(data->BufTextLen)};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void selector_t::render(blt::i32 width, blt::i32 height)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_t::process_mouse(graph_t& graph, blt::i32 width, blt::i32 height)
|
void selector_t::process_mouse(blt::i32 width, blt::i32 height)
|
||||||
{
|
{
|
||||||
const auto mouse_pos = blt::make_vec2(blt::gfx::calculateRay2D(width, height, global_matrices.getScale2D(), global_matrices.getView2D(),
|
const auto mouse_pos = blt::make_vec2(blt::gfx::calculateRay2D(width, height, global_matrices.getScale2D(), global_matrices.getView2D(),
|
||||||
global_matrices.getOrtho()));
|
global_matrices.getOrtho()));
|
||||||
|
|
||||||
bool mouse_pressed = blt::gfx::isMousePressed(0) && blt::gfx::mousePressedLastFrame();
|
bool mouse_pressed = blt::gfx::isMousePressed(0) && blt::gfx::mousePressedLastFrame();
|
||||||
|
|
||||||
for (const auto& [index, node] : blt::enumerate(graph.nodes))
|
if (placement)
|
||||||
{
|
{
|
||||||
const auto pos = node.getPosition();
|
if (mouse_pressed)
|
||||||
const auto dist = pos - mouse_pos;
|
|
||||||
const auto mag = dist.magnitude();
|
|
||||||
|
|
||||||
if (mag < node.getRenderObj().scale && mouse_pressed)
|
|
||||||
{
|
{
|
||||||
set_drag_selection(static_cast<blt::i64>(index));
|
placement = false;
|
||||||
if (primary_selection == drag_selection || secondary_selection == drag_selection)
|
set_drag_selection(-1);
|
||||||
|
} else if (blt::gfx::isKeyPressed(GLFW_KEY_ESCAPE))
|
||||||
|
{
|
||||||
|
destroy_node(primary_selection);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
for (const auto& [index, node] : blt::enumerate(graph.nodes))
|
||||||
|
{
|
||||||
|
const auto pos = node.getPosition();
|
||||||
|
const auto dist = pos - mouse_pos;
|
||||||
|
const auto mag = dist.magnitude();
|
||||||
|
|
||||||
|
if (mag < node.getRenderObj().scale && mouse_pressed)
|
||||||
{
|
{
|
||||||
edge = false;
|
set_drag_selection(static_cast<blt::i64>(index));
|
||||||
|
if (blt::gfx::isKeyPressed(GLFW_KEY_LEFT_SHIFT))
|
||||||
|
set_secondary_selection(drag_selection);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_primary_selection(drag_selection);
|
||||||
|
set_secondary_selection(-1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (blt::gfx::isKeyPressed(GLFW_KEY_LEFT_SHIFT))
|
|
||||||
set_secondary_selection(drag_selection);
|
|
||||||
else
|
|
||||||
set_primary_selection(drag_selection);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (blt::gfx::mouseReleaseLastFrame())
|
||||||
|
set_drag_selection(-1);
|
||||||
}
|
}
|
||||||
if (blt::gfx::mouseReleaseLastFrame())
|
if (drag_selection >= 0 && drag_selection < static_cast<blt::i64>(graph.nodes.size()) && (blt::gfx::isMousePressed(0) || placement))
|
||||||
set_drag_selection(-1);
|
|
||||||
if (drag_selection >= 0 && drag_selection < static_cast<blt::i64>(graph.nodes.size()) && blt::gfx::isMousePressed(0))
|
|
||||||
{
|
{
|
||||||
graph.nodes[drag_selection].getPositionRef() = mouse_pos;
|
graph.nodes[drag_selection].getPositionRef() = mouse_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_t::draw_gui(graph_t& graph, blt::i32 width, blt::i32 height)
|
void selector_t::process_keyboard(blt::i32 width, blt::i32 height)
|
||||||
|
{
|
||||||
|
const auto mouse_pos = blt::make_vec2(blt::gfx::calculateRay2D(width, height, global_matrices.getScale2D(), global_matrices.getView2D(),
|
||||||
|
global_matrices.getOrtho()));
|
||||||
|
if (blt::gfx::keyPressedLastFrame())
|
||||||
|
{
|
||||||
|
if (blt::gfx::isKeyPressed(GLFW_KEY_C))
|
||||||
|
{
|
||||||
|
if (placement)
|
||||||
|
destroy_node(primary_selection);
|
||||||
|
else
|
||||||
|
create_placement_node(mouse_pos);
|
||||||
|
} else if (blt::gfx::isKeyPressed(GLFW_KEY_X))
|
||||||
|
{
|
||||||
|
if (primary_selection != -1)
|
||||||
|
destroy_node(primary_selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selector_t::draw_gui(blt::i32 width, blt::i32 height)
|
||||||
{
|
{
|
||||||
im::SetNextItemOpen(true, ImGuiCond_Once);
|
im::SetNextItemOpen(true, ImGuiCond_Once);
|
||||||
if (im::CollapsingHeader("Selection Information"))
|
if (im::CollapsingHeader("Selection Information"))
|
||||||
{
|
{
|
||||||
im::Text("Silly (%ld) | (%ld || %ld)", drag_selection, primary_selection, secondary_selection);
|
im::Text("Silly (%ld) | (%ld || %ld)", drag_selection, primary_selection, secondary_selection);
|
||||||
|
if (primary_selection >= 0)
|
||||||
|
{
|
||||||
|
if (secondary_selection >= 0)
|
||||||
|
{
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
im::InputFloat("Size", &graph.nodes[primary_selection].point.scale);
|
||||||
|
callback_data_t name_data{graph.nodes[primary_selection].name, name_input};
|
||||||
|
callback_data_t texture_data{graph.nodes[primary_selection].texture, texture_input};
|
||||||
|
callback_data_t description_data{graph.nodes[primary_selection].description, description_input};
|
||||||
|
im::InputText("Name", name_input.data(), name_input.size(),
|
||||||
|
ImGuiInputTextFlags_CallbackResize | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion,
|
||||||
|
text_input_callback, &name_data);
|
||||||
|
im::InputText("Texture", texture_input.data(), texture_input.size(),
|
||||||
|
ImGuiInputTextFlags_CallbackResize | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion,
|
||||||
|
text_input_callback, &texture_data);
|
||||||
|
im::InputTextMultiline("Description", description_input.data(), description_input.size(), {},
|
||||||
|
ImGuiInputTextFlags_CallbackResize | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion,
|
||||||
|
text_input_callback, &description_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_t::set_secondary_selection(blt::i64 n)
|
void selector_t::set_secondary_selection(blt::i64 n)
|
||||||
{
|
{
|
||||||
secondary_selection = n;
|
secondary_selection = n;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_t::set_primary_selection(blt::i64 n)
|
void selector_t::set_primary_selection(blt::i64 n)
|
||||||
{
|
{
|
||||||
primary_selection = n;
|
primary_selection = n;
|
||||||
|
if (primary_selection >= 0)
|
||||||
|
{
|
||||||
|
from_string(graph.nodes[primary_selection].name, name_input);
|
||||||
|
from_string(graph.nodes[primary_selection].texture, texture_input);
|
||||||
|
from_string(graph.nodes[primary_selection].description, description_input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_t::set_drag_selection(blt::i64 n)
|
void selector_t::set_drag_selection(blt::i64 n)
|
||||||
{
|
{
|
||||||
drag_selection = n;
|
drag_selection = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selector_t::create_placement_node(const blt::vec2& pos)
|
||||||
|
{
|
||||||
|
auto node = static_cast<blt::i64>(graph.nodes.size());
|
||||||
|
graph.nodes.push_back(node_t{{pos, conf::POINT_SIZE}});
|
||||||
|
set_drag_selection(node);
|
||||||
|
set_primary_selection(node);
|
||||||
|
placement = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void selector_t::destroy_node(blt::i64 node)
|
||||||
|
{
|
||||||
|
auto& node_v = graph.nodes[node];
|
||||||
|
graph.names_to_node.erase(node_v.name);
|
||||||
|
erase_if(graph.edges, [node](const edge_t& v) {
|
||||||
|
return static_cast<blt::i64>(v.getFirst()) == node || static_cast<blt::i64>(v.getSecond()) == node;
|
||||||
|
});
|
||||||
|
graph.connected_nodes.erase(node);
|
||||||
|
for (auto& v : graph.connected_nodes)
|
||||||
|
{
|
||||||
|
v.second.erase(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.nodes.erase(graph.nodes.begin() + node);
|
||||||
|
set_drag_selection(-1);
|
||||||
|
set_primary_selection(-1);
|
||||||
|
placement = false;
|
||||||
|
}
|
||||||
|
|