diff --git a/CMakeLists.txt b/CMakeLists.txt index 333ee3b..77d5bf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,11 +8,11 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(WIN32) - set(IMGUI_BACKEND "imgui_impl_dx11.cpp") # DirectX 11 for Windows + set(IMGUI_BACKEND "imgui_impl_dx11.cpp") # DirectX 11 for Windows elseif(APPLE) - set(IMGUI_BACKEND "imgui_impl_metal.mm") # Metal for macOS + set(IMGUI_BACKEND "imgui_impl_metal.mm") # Metal for macOS elseif(UNIX) - set(IMGUI_BACKEND "imgui_impl_opengl3.cpp") # OpenGL for Linux + set(IMGUI_BACKEND "imgui_impl_opengl3.cpp") # OpenGL for Linux endif() # includes @@ -21,25 +21,25 @@ include_directories(./includes) # raylib include(FetchContent) FetchContent_Declare( - raylib - GIT_REPOSITORY https://github.com/raysan5/raylib.git - GIT_TAG 5.5 - GIT_SHALLOW 1 + raylib + GIT_REPOSITORY https://github.com/raysan5/raylib.git + GIT_TAG 5.5 + GIT_SHALLOW 1 ) FetchContent_GetProperties(raylib) if (NOT raylib_POPULATED) - set(FETCHCONTENT_QUIET NO) - FetchContent_Populate(raylib) - set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) - set(BUILD_GAMES OFF CACHE BOOL "" FORCE) - add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) + set(FETCHCONTENT_QUIET NO) + FetchContent_Populate(raylib) + set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + set(BUILD_GAMES OFF CACHE BOOL "" FORCE) + add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) endif() # imgui FetchContent_Declare( - imgui - GIT_REPOSITORY https://github.com/ocornut/imgui.git - GIT_TAG docking + imgui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG docking ) FetchContent_MakeAvailable(imgui) @@ -48,9 +48,9 @@ set(imgui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/imgui-src) # rlimgui FetchContent_Declare( - rlImGui - GIT_REPOSITORY https://github.com/raylib-extras/rlImGui.git - GIT_TAG main + rlImGui + GIT_REPOSITORY https://github.com/raylib-extras/rlImGui.git + GIT_TAG main ) FetchContent_MakeAvailable(rlImGui) set(rlImGui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/rlimgui-src) @@ -58,25 +58,26 @@ set(rlImGui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/rlimgui-src) # nlohmann::json FetchContent_Declare( - json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.3 + json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 ) FetchContent_MakeAvailable(json) include_directories(${imgui_SOURCE_DIR} ${rlImGui_SOURCE_DIR}) -set(SRC_CXX_FILES "./src/main.cpp" - "./src/rules.cpp" - "./src/world.cpp" - "./src/render.cpp" +set(SRC_CXX_FILES "./src/main.cpp" + "./src/rules.cpp" + "./src/world.cpp" + "./src/render.cpp" "./src/control_menu.cpp" - "${rlImGui_SOURCE_DIR}/rlImGui.cpp" - "${imgui_SOURCE_DIR}/imgui.cpp" - "${imgui_SOURCE_DIR}/imgui_draw.cpp" - "${imgui_SOURCE_DIR}/imgui_widgets.cpp" - "${imgui_SOURCE_DIR}/imgui_tables.cpp" - "${imgui_SOURCE_DIR}/backends/${IMGUI_BACKEND}" + "./src/settings_menu.cpp" + "${rlImGui_SOURCE_DIR}/rlImGui.cpp" + "${imgui_SOURCE_DIR}/imgui.cpp" + "${imgui_SOURCE_DIR}/imgui_draw.cpp" + "${imgui_SOURCE_DIR}/imgui_widgets.cpp" + "${imgui_SOURCE_DIR}/imgui_tables.cpp" + "${imgui_SOURCE_DIR}/backends/${IMGUI_BACKEND}" ) # Setup the example diff --git a/includes/context.hpp b/includes/context.hpp index c03587c..21fa3db 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -2,7 +2,7 @@ * File name: context.hpp * Author: lejulien * Date created: 01-01-1970 00:59:59 -// Date modified: 12-01-2026 20:31:50 +// Date modified: 12-01-2026 21:30:10 * ------ */ @@ -14,12 +14,16 @@ class World; class Rules; +class Render; namespace gol { +class SettingsMenu; typedef struct ctx { std::shared_ptr world = nullptr; std::shared_ptr rules = nullptr; + std::shared_ptr render = nullptr; + std::shared_ptr settings_menu = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp index 2aa0c2e..2cbf0f0 100644 --- a/includes/control_menu.hpp +++ b/includes/control_menu.hpp @@ -2,7 +2,7 @@ * File name: control_menu.hpp * Author: lejulien * Date created: 10-01-2026 22:00:33 -// Date modified: 10-01-2026 22:45:10 +// Date modified: 12-01-2026 20:50:02 * ------ */ @@ -23,20 +23,13 @@ private: ctx context_; public: // Keep those public for easy access MenuState menu_state_ = MenuState::NONE; - int fps_ctrl_ = false; - int cell_size_ctrl_ = false; bool play_ctrl_ = true; bool step_ctrl_ = false; bool step_back_ctrl_ = false; bool rand_ctrl_ = false; bool edit_ctrl_ = false; bool clear_ctrl_ = false; - bool settings_window_ = false; bool paterns_ctrl_ = false; - int width_ctrl_ = false; - int height_ctrl_ = false; - bool dark_theme_ctrl_ = false; - bool apply_ctrl_ = false; }; } // namespace gol diff --git a/includes/settings_menu.hpp b/includes/settings_menu.hpp new file mode 100644 index 0000000..b61807f --- /dev/null +++ b/includes/settings_menu.hpp @@ -0,0 +1,44 @@ +/* +* File name: settings_menu.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:28:03 +* ------ +*/ + +#pragma once + +#include + +namespace gol { + +class SettingsMenu { +public: + SettingsMenu(ctx &context); + ~SettingsMenu() = default; + void update(); + void display(); + bool isOpen(); + void Toogle(); + // Getter/Setters + int getFPS(); + void setFPS(int); + int getCellSize(); + void setCellSize(int); + int getWidth(); + void setWidth(int); + int getHeight(); + void setHeight(int); +private: + ctx context_; + int fps_ctrl_ = false; + int cell_size_ctrl_ = false; + bool settings_window_ = false; + int width_ctrl_ = false; + int height_ctrl_ = false; + bool dark_theme_ctrl_ = false; + bool apply_ctrl_ = false; +}; + + +} // namespace gol diff --git a/src/control_menu.cpp b/src/control_menu.cpp index f9aa76b..e5c8045 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -2,7 +2,7 @@ * File name: control_menu.cpp * Author: lejulien * Date created: 10-01-2026 22:12:44 -// Date modified: 12-01-2026 20:36:39 +// Date modified: 12-01-2026 21:26:33 * ------ */ @@ -11,26 +11,20 @@ #include #include +#include #include #include namespace gol { ControlMenu::ControlMenu(ctx context):context_(context) { - fps_ctrl_ = context.config_json["fps"].get(); - cell_size_ctrl_ = context.config_json["cell_size"].get(); play_ctrl_ = true; step_ctrl_ = false; step_back_ctrl_ = false; rand_ctrl_ = false; edit_ctrl_ = false; clear_ctrl_ = false; - settings_window_ = false; paterns_ctrl_ = false; - width_ctrl_ = context.config_json["screen_width"].get(); - height_ctrl_ = context.config_json["screen_height"].get(); - dark_theme_ctrl_ = context.config_json["dark_theme"].get(); - apply_ctrl_ = false; } void ControlMenu::update() { @@ -91,8 +85,8 @@ void ControlMenu::display() { if (ImGui::Button((paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { paterns_ctrl_ = !paterns_ctrl_; } - if (ImGui::Button((settings_window_) ? "Hide settings" : "Show settings")) { - settings_window_ = !settings_window_; + if (ImGui::Button((context_.settings_menu->isOpen()) ? "Hide settings" : "Show settings")) { + context_.settings_menu->Toogle(); } ImGui::Text("Generation: %zu", context_.world->getCycle()); ImGui::End();} diff --git a/src/main.cpp b/src/main.cpp index cb95fde..a1fffd9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 -// Date modified: 12-01-2026 20:34:37 +// Date modified: 12-01-2026 21:33:13 * ------ */ @@ -22,6 +22,7 @@ #include #include #include +#include Vector2 snapToGrid(Vector2 screen, int cell_size) { return {static_cast(round(screen.x / cell_size) * cell_size), @@ -102,7 +103,8 @@ int main(int ac, char **av) { // Initialize objects context.world = std::make_shared(context); context.rules = std::make_shared(); - Render render(context.config_json["cell_size"]); + context.settings_menu = std::make_shared(context); + context.render = std::make_shared(context.settings_menu->getCellSize()); // Imgui control menu gol::ControlMenu control_menu(context); @@ -127,7 +129,7 @@ int main(int ac, char **av) { while (!WindowShouldClose()) { // Frames shinenigans float deltaTime = GetFrameTime(); - sim_speed = control_menu.fps_ctrl_ / 10.0f; + sim_speed = context.settings_menu->getFPS() / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; control_menu.update(); @@ -142,15 +144,15 @@ int main(int ac, char **av) { } // Selection behaviour - if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !control_menu.settings_window_) { + 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, control_menu.cell_size_ctrl_); + sel_pos = snapToGrid(mousePos, context.settings_menu->getCellSize()); selecting = true; } - if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < control_menu.width_ctrl_ && mousePos.y >=0 && mousePos.y < control_menu.height_ctrl_ ) { + 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, control_menu.cell_size_ctrl_); - Vector2i p2 = screenToGrid(mousePos, control_menu.cell_size_ctrl_); + 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, @@ -171,35 +173,7 @@ int main(int ac, char **av) { if (!sel_ctrl) { patern_name[0] = '\0'; } - - if (control_menu.apply_ctrl_) { - bool resize_needed = false; - context.config_json["fps"] = control_menu.fps_ctrl_; - if (context.config_json["screen_width"].get() != control_menu.width_ctrl_ || - context.config_json["screen_height"].get() != control_menu.height_ctrl_) { - context.config_json["screen_width"] = control_menu.width_ctrl_; - context.config_json["screen_height"] = control_menu.height_ctrl_; - rlImGuiShutdown(); - SetWindowSize(control_menu.width_ctrl_, control_menu.height_ctrl_); - rlImGuiSetup(control_menu.dark_theme_ctrl_); - resize_needed = true; - } - if (control_menu.cell_size_ctrl_ != context.config_json["cell_size"].get() || - resize_needed) { - context.world->resize(context.config_json["screen_width"].get() / control_menu.cell_size_ctrl_, - context.config_json["screen_height"].get() / control_menu.cell_size_ctrl_); - render.updateCellSize(control_menu.cell_size_ctrl_); - context.rules->newWorld(&(*context.world)); - context.config_json["cell_size"] = control_menu.cell_size_ctrl_; - } - if (control_menu.dark_theme_ctrl_ != context.config_json["dark_theme"]) { - rlImGuiShutdown(); - rlImGuiSetup(control_menu.dark_theme_ctrl_); - context.config_json["dark_theme"] = control_menu.dark_theme_ctrl_; - } - control_menu.apply_ctrl_ = false; - control_menu.settings_window_ = false; - } + context.settings_menu->update(); // Accumulate time and update simulation at the adjusted speed deltaTimeAccumulator += deltaTime; @@ -214,9 +188,9 @@ int main(int ac, char **av) { } BeginDrawing(); ClearBackground(BLACK); - render.display(&(*context.world)); + context.render->display(&(*context.world)); if (selecting) { - auto grid_mouse = snapToGrid(mousePos, control_menu.cell_size_ctrl_); + 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), @@ -235,20 +209,7 @@ int main(int ac, char **av) { ImGui::Button("refresh"); ImGui::End(); } - if (control_menu.settings_window_) { - ImGuiWindowFlags settings_flags = - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; - ImGui::Begin("Settings", &control_menu.settings_window_, settings_flags); - ImGui::SliderInt("Window Width", &control_menu.width_ctrl_, 800, 1920); - ImGui::SliderInt("Window Height", &control_menu.height_ctrl_, 600, 1200); - ImGui::SliderInt("FPS", &control_menu.fps_ctrl_, 0, 30); - ImGui::SliderInt("Cell Size", &control_menu.cell_size_ctrl_, 4, 100); - ImGui::Checkbox("Dark Theme", &control_menu.dark_theme_ctrl_); - if (ImGui::Button("Save & Apply")) { - control_menu.apply_ctrl_ = true; - } - ImGui::End(); - } + context.settings_menu->display(); if (sel_ctrl) { BeginTextureMode(selectionTexture); ClearBackground(BLACK); diff --git a/src/settings_menu.cpp b/src/settings_menu.cpp new file mode 100644 index 0000000..93bfd09 --- /dev/null +++ b/src/settings_menu.cpp @@ -0,0 +1,121 @@ +/* +* File name: settings_menu.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:31:20 +* ------ +*/ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace gol { + +SettingsMenu::SettingsMenu(ctx &context): context_(context) { + fps_ctrl_ = context.config_json["fps"].get(); + cell_size_ctrl_ = context.config_json["cell_size"].get(); + settings_window_ = false; + width_ctrl_ = context.config_json["screen_width"].get(); + height_ctrl_ = context.config_json["screen_height"].get(); + dark_theme_ctrl_ = context.config_json["dark_theme"].get(); + apply_ctrl_ = false; +} + +void SettingsMenu::update() { + if (apply_ctrl_) { + bool resize_needed = false; + context_.config_json["fps"] = fps_ctrl_; + if (context_.config_json["screen_width"].get() != width_ctrl_ || + context_.config_json["screen_height"].get() != height_ctrl_) { + context_.config_json["screen_width"] = width_ctrl_; + context_.config_json["screen_height"] = height_ctrl_; + rlImGuiShutdown(); + SetWindowSize(width_ctrl_, height_ctrl_); + rlImGuiSetup(dark_theme_ctrl_); + resize_needed = true; + } + if (cell_size_ctrl_ != context_.config_json["cell_size"].get() || + resize_needed) { + context_.world->resize(context_.config_json["screen_width"].get() / cell_size_ctrl_, + context_.config_json["screen_height"].get() / cell_size_ctrl_); + context_.render->updateCellSize(cell_size_ctrl_); + context_.rules->newWorld(&(*context_.world)); + context_.config_json["cell_size"] = cell_size_ctrl_; + } + if (dark_theme_ctrl_ != context_.config_json["dark_theme"]) { + rlImGuiShutdown(); + rlImGuiSetup(dark_theme_ctrl_); + context_.config_json["dark_theme"] = dark_theme_ctrl_; + } + apply_ctrl_ = false; + settings_window_ = false; + } +} + +void SettingsMenu::display() { + if (settings_window_) { + ImGuiWindowFlags settings_flags = + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; + ImGui::Begin("Settings", &settings_window_, settings_flags); + ImGui::SliderInt("Window Width", &width_ctrl_, 800, 1920); + ImGui::SliderInt("Window Height", &height_ctrl_, 600, 1200); + ImGui::SliderInt("FPS", &fps_ctrl_, 0, 30); + ImGui::SliderInt("Cell Size", &cell_size_ctrl_, 4, 100); + ImGui::Checkbox("Dark Theme", &dark_theme_ctrl_); + if (ImGui::Button("Save & Apply")) { + apply_ctrl_ = true; + } + ImGui::End(); + } +} + +bool SettingsMenu::isOpen() { + return settings_window_; +} + +void SettingsMenu::Toogle() { + settings_window_ = !settings_window_; +} + +// Getters/Setters +int SettingsMenu::getFPS() { + return fps_ctrl_; +} + +void SettingsMenu::setFPS(int new_fps) { + fps_ctrl_ = new_fps; +} + +int SettingsMenu::getCellSize() { + return cell_size_ctrl_; +} + +void SettingsMenu::setCellSize(int new_cell_size) { + cell_size_ctrl_ = new_cell_size; +} + +int SettingsMenu::getWidth() { + return width_ctrl_; +} + +void SettingsMenu::setWidth(int new_width) { + width_ctrl_ = new_width; +} + +int SettingsMenu::getHeight() { + return height_ctrl_; +} + +void SettingsMenu::setHeight(int new_height) { + height_ctrl_ = new_height; +} + +} // namespace gol