diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cb9cc0..811c3d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC_CXX_FILES "./src/main.cpp" "./src/control_menu.cpp" "./src/settings_menu.cpp" "./src/selection_menu.cpp" + "./src/selection.cpp" "${rlImGui_SOURCE_DIR}/rlImGui.cpp" "${imgui_SOURCE_DIR}/imgui.cpp" "${imgui_SOURCE_DIR}/imgui_draw.cpp" diff --git a/includes/context.hpp b/includes/context.hpp index f025d49..9ad954e 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -19,6 +19,8 @@ class Render; namespace gol { class SettingsMenu; class SelectionMenu; +class ControlMenu; +class Selection; typedef struct ctx { std::shared_ptr world = nullptr; @@ -26,6 +28,8 @@ typedef struct ctx { std::shared_ptr render = nullptr; std::shared_ptr settings_menu = nullptr; std::shared_ptr selection_menu = nullptr; + std::shared_ptr control_menu = nullptr; + std::shared_ptr selection = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/selection.hpp b/includes/selection.hpp new file mode 100644 index 0000000..eb1de78 --- /dev/null +++ b/includes/selection.hpp @@ -0,0 +1,32 @@ +/* +* File name: selection.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#pragma once + +#include + +#include +#include +#include + +namespace gol { + +class Selection { +public: + Selection(std::shared_ptr); + ~Selection() = default; + void update(); + void display(); +private: + std::shared_ptr context_ = nullptr; + Vector2 sel_pos_ = {0., 0.}; + Vector2 mouse_pos_ = {0., 0.}; + bool selecting_ = false; +}; + +} // namespace gol diff --git a/includes/snapping.hpp b/includes/snapping.hpp new file mode 100644 index 0000000..dfcc0fb --- /dev/null +++ b/includes/snapping.hpp @@ -0,0 +1,24 @@ +/* +* File name: selection.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#pragma once + +#include + +#include +#include + +Vector2 snapToGrid(Vector2 screen, int cell_size) { + return {static_cast(round(screen.x / cell_size) * cell_size), + static_cast(round(screen.y / cell_size) * cell_size)}; +} + +Vector2i screenToGrid(Vector2 screen, int cell_size) { + return {static_cast(round(screen.x / cell_size)), + static_cast(round(screen.y / cell_size))}; +} diff --git a/src/main.cpp b/src/main.cpp index 4c68eed..25482dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,16 +23,7 @@ #include #include #include - -Vector2 snapToGrid(Vector2 screen, int cell_size) { - return {static_cast(round(screen.x / cell_size) * cell_size), - static_cast(round(screen.y / cell_size) * cell_size)}; -} - -Vector2i screenToGrid(Vector2 screen, int cell_size) { - return {static_cast(round(screen.x / cell_size)), - static_cast(round(screen.y / cell_size))}; -} +#include int main(int ac, char **av) { std::shared_ptr context = std::make_shared(); @@ -98,71 +89,41 @@ int main(int ac, char **av) { rlImGuiSetup(context->config_json["dark_theme"]); // Initialize objects + context->control_menu = std::make_shared(context); context->world = std::make_shared(context); context->rules = std::make_shared(); context->settings_menu = std::make_shared(context); context->render = std::make_shared(context->settings_menu->getCellSize()); context->selection_menu = std::make_shared(context); - - // Imgui control menu - gol::ControlMenu control_menu(context); + context->selection = std::make_shared(context); // Speed handling values float sim_speed = 1.0f; float deltaTimeAccumulator = 0.0f; float timePerUpdate = 1.0f / 10.0f; - // Selection window - Vector2 sel_pos = {0., 0.}; - bool selecting = false; - // Setups context->rules->setup(context->world); // Diplay generations while (!WindowShouldClose()) { // Frames shinenigans float deltaTime = GetFrameTime(); - sim_speed = context->settings_menu->getFPS() / 10.0f; + sim_speed = context->settings_menu->getFPS() / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; - control_menu.update(); + context->control_menu->update(); auto gesture = GetGestureDetected(); auto mousePos = GetMousePosition(); - if (control_menu.edit_ctrl_ && IsMouseButtonPressed(0) && + if (context->control_menu->edit_ctrl_ && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - control_menu.menu_state_ = MenuState::EDIT; + context->control_menu->menu_state_ = MenuState::EDIT; context->world->setCell(mousePos.x / context->config_json["cell_size"].get(), mousePos.y / context->config_json["cell_size"].get()); } // Selection behaviour - if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !context->settings_menu->isOpen()) { - if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - sel_pos = snapToGrid(mousePos, context->settings_menu->getCellSize()); - selecting = true; - } - if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < context->settings_menu->getWidth() && mousePos.y >=0 && mousePos.y < context->settings_menu->getHeight() ) { - selecting = false; - Vector2i p1 = screenToGrid(sel_pos, context->settings_menu->getCellSize()); - Vector2i p2 = screenToGrid(mousePos, context->settings_menu->getCellSize()); - // Get origin - Vector2i orig = { - (p1.x < p2.x)?p1.x:p2.x, - (p1.y < p2.y)?p1.y:p2.y, - }; - // Get selection size - Vector2i sel_size = { - (p1.x > p2.x)?p1.x-p2.x:p2.x-p1.x, - (p1.y > p2.y)?p1.y-p2.y:p2.y-p1.y, - }; - // Ensure there is at least one cell selected - if (!(sel_size.x == 0 || sel_size.y == 0)) { - context->selection_menu->setSelection(context->world->getSelection(orig, sel_size)); - context->selection_menu->open(); - } - } - } + context->selection->update(); context->selection_menu->update(); context->settings_menu->update(); @@ -172,7 +133,7 @@ int main(int ac, char **av) { if (deltaTimeAccumulator >= timePerUpdate) { // Reset accumulator deltaTimeAccumulator -= timePerUpdate; - if (control_menu.menu_state_ == MenuState::PLAY) { + if (context->control_menu->menu_state_ == MenuState::PLAY) { context->world->saveCompressed(); context->rules->update(); } @@ -180,23 +141,15 @@ int main(int ac, char **av) { BeginDrawing(); ClearBackground(BLACK); context->render->display(context->world); - if (selecting) { - auto grid_mouse = snapToGrid(mousePos, context->settings_menu->getCellSize()); - bool sel_x_less = (sel_pos.x < grid_mouse.x); - bool sel_y_less = (sel_pos.y < grid_mouse.y); - DrawRectangleLines(((sel_x_less)? sel_pos.x: grid_mouse.x), ((sel_y_less)? sel_pos.y: grid_mouse.y), - ((sel_x_less)? grid_mouse.x - sel_pos.x : sel_pos.x - grid_mouse.x), - ((sel_y_less)? grid_mouse.y - sel_pos.y : sel_pos.y - grid_mouse.y), - RED); - } + context->selection->display(); // Start ImGui frame rlImGuiBegin(); - control_menu.display(); - if (control_menu.paterns_ctrl_) { + context->control_menu->display(); + if (context->control_menu->paterns_ctrl_) { ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); - ImGui::Begin("paterns", &control_menu.paterns_ctrl_, paterns_flags); + ImGui::Begin("paterns", &context->control_menu->paterns_ctrl_, paterns_flags); ImGui::Button("refresh"); ImGui::End(); } diff --git a/src/selection.cpp b/src/selection.cpp new file mode 100644 index 0000000..c36cfd7 --- /dev/null +++ b/src/selection.cpp @@ -0,0 +1,67 @@ +/* +* File name: selection.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#include + +#include +#include +#include +#include +#include +#include + +namespace gol { + +Selection::Selection(std::shared_ptr context): context_(context) { + +} + +void Selection::update() { + auto gesture = GetGestureDetected(); + mouse_pos_ = GetMousePosition(); + if (!context_->control_menu->edit_ctrl_ && !context_->control_menu->play_ctrl_ && !context_->control_menu->paterns_ctrl_ && !context_->settings_menu->isOpen()) { + if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { + sel_pos_ = snapToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + selecting_ = true; + } + if (ImGui::IsMouseReleased(0) && selecting_ == true && mouse_pos_.x >=0 && mouse_pos_.x < context_->settings_menu->getWidth() && mouse_pos_.y >=0 && mouse_pos_.y < context_->settings_menu->getHeight() ) { + selecting_ = false; + Vector2i p1 = screenToGrid(sel_pos_, context_->settings_menu->getCellSize()); + Vector2i p2 = screenToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + // Get origin + Vector2i orig = { + (p1.x < p2.x)?p1.x:p2.x, + (p1.y < p2.y)?p1.y:p2.y, + }; + // Get selection size + Vector2i sel_size = { + (p1.x > p2.x)?p1.x-p2.x:p2.x-p1.x, + (p1.y > p2.y)?p1.y-p2.y:p2.y-p1.y, + }; + // Ensure there is at least one cell selected + if (!(sel_size.x == 0 || sel_size.y == 0)) { + context_->selection_menu->setSelection(context_->world->getSelection(orig, sel_size)); + context_->selection_menu->open(); + } + } + } +} + +void Selection::display() { + if (selecting_) { + auto grid_mouse = snapToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + bool sel_x_less = (sel_pos_.x < grid_mouse.x); + bool sel_y_less = (sel_pos_.y < grid_mouse.y); + DrawRectangleLines(((sel_x_less)? sel_pos_.x: grid_mouse.x), ((sel_y_less)? sel_pos_.y: grid_mouse.y), + ((sel_x_less)? grid_mouse.x - sel_pos_.x : sel_pos_.x - grid_mouse.x), + ((sel_y_less)? grid_mouse.y - sel_pos_.y : sel_pos_.y - grid_mouse.y), + RED); + } +} + +} // namespace gol