174 lines
5.6 KiB
C++
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;
|
|
}
|