Files
GameOfLifeEditor/src/main.cpp

174 lines
5.6 KiB
C++

/*
* File name: main.cpp
* Author: lejulien
* Date created: 10-01-2026 21:59:32
// Date modified: 12-01-2026 22:17:54
* ------
*/
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <nlohmann/json.hpp>
#include <imgui.h>
#include <raylib.h>
#include <rlImGui.h>
#include <render.hpp>
#include <rules.hpp>
#include <world.hpp>
#include <types.hpp>
#include <context.hpp>
#include <control_menu.hpp>
#include <settings_menu.hpp>
#include <selection_menu.hpp>
#include <selection.hpp>
#include <paterns_menu.hpp>
int main(int ac, char **av) {
std::shared_ptr<gol::ctx> context = std::make_shared<gol::ctx>();
// Load or default config
const std::string config_file_name = "config.json";
std::fstream config_file(config_file_name, std::ios::in | std::ios::out);
if (!config_file.is_open()) {
config_file.open(config_file_name, std::ios::out);
if (!config_file) {
std::cerr << "Failed to create config file, the settings will not be "
"kepts after restart."
<< std::endl;
return 1;
}
config_file.close();
config_file.open(config_file_name, std::ios::in | std::ios::out);
config_file << "{}";
config_file.flush();
}
// Try reading the configuration
try {
config_file.seekg(0);
config_file >> context->config_json;
} catch (const nlohmann::json::parse_error &e) {
std::cerr << "An error occured while loading config : " << e.what()
<< std::endl;
std::cerr << "Please fix the configuration or remove the config.json file."
<< std::endl;
return 1;
}
config_file.close();
// Check config values or populate them
if (!context->config_json.contains("cell_size") ||
(context->config_json["cell_size"] < 4 || context->config_json["cell_size"] > 100)) {
context->config_json["cell_size"] = 10;
}
if (!context->config_json.contains("screen_width") ||
(context->config_json["screen_width"] < 800 ||
context->config_json["screen_width"] > 1920)) {
context->config_json["screen_width"] = 800;
}
if (!context->config_json.contains("screen_height") ||
(context->config_json["screen_height"] < 600 ||
context->config_json["screen_height"] > 1200)) {
context->config_json["screen_height"] = 600;
}
if (!context->config_json.contains("dark_theme")) {
context->config_json["dark_theme"] = true;
}
if (!context->config_json.contains("fps") ||
(context->config_json["fps"] < 0 || context->config_json["fps"] > 30)) {
context->config_json["fps"] = 800;
}
// Get program directory
char path_buf[1024];
ssize_t len = readlink("/proc/self/exe", path_buf, sizeof(path_buf)-1);
if (len == -1) {
std::cerr << "Failed to determine program directory" << std::endl;
return 1;
}
context->program_dir = std::filesystem::path(path_buf).parent_path();
InitWindow(context->config_json["screen_width"], context->config_json["screen_height"],
&av[0][2]);
SetTargetFPS(60);
rlImGuiSetup(context->config_json["dark_theme"]);
// Initialize objects
context->control_menu = std::make_shared<gol::ControlMenu>(context);
context->world = std::make_shared<World>(context);
context->rules = std::make_shared<Rules>();
context->settings_menu = std::make_shared<gol::SettingsMenu>(context);
context->render = std::make_shared<Render>(context->settings_menu->getCellSize());
context->selection_menu = std::make_shared<gol::SelectionMenu>(context);
context->selection = std::make_shared<gol::Selection>(context);
context->paterns_menu = std::make_shared<gol::PaternsMenu>(context);
// Speed handling values
float sim_speed = 1.0f;
float deltaTimeAccumulator = 0.0f;
float timePerUpdate = 1.0f / 10.0f;
// Setups
context->rules->setup(context->world);
context->paterns_menu->refresh();
// Diplay generations
while (!WindowShouldClose()) {
// Frames shinenigans
float deltaTime = GetFrameTime();
sim_speed = context->settings_menu->getFPS() / 10.0f;
timePerUpdate = (1.0f / 10.0f) / sim_speed;
context->control_menu->update();
auto gesture = GetGestureDetected();
auto mousePos = GetMousePosition();
if (context->control_menu->edit_ctrl_ && IsMouseButtonPressed(0) &&
!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) {
context->control_menu->menu_state_ = MenuState::EDIT;
context->world->setCell(mousePos.x / context->config_json["cell_size"].get<int>(),
mousePos.y / context->config_json["cell_size"].get<int>());
}
// Selection behaviour
context->selection->update();
context->selection_menu->update();
context->settings_menu->update();
// Accumulate time and update simulation at the adjusted speed
deltaTimeAccumulator += deltaTime;
if (deltaTimeAccumulator >= timePerUpdate) {
// Reset accumulator
deltaTimeAccumulator -= timePerUpdate;
if (context->control_menu->menu_state_ == MenuState::PLAY) {
context->world->saveCompressed();
context->rules->update();
}
}
BeginDrawing();
ClearBackground(BLACK);
context->render->display(context->world);
context->selection->display();
// Start ImGui frame
rlImGuiBegin();
context->control_menu->display();
context->paterns_menu->display();
context->settings_menu->display();
context->selection_menu->display();
// End ImGui frame
rlImGuiEnd();
EndDrawing();
}
config_file.open(config_file_name, std::ios::out | std::ios::trunc);
config_file << context->config_json.dump(2);
config_file.close();
rlImGuiShutdown();
CloseWindow();
return 0;
}