/* * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 // Date modified: 12-01-2026 22:17:54 * ------ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main(int ac, char **av) { std::shared_ptr context = std::make_shared(); // 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(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); context->selection = std::make_shared(context); context->paterns_menu = std::make_shared(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(), mousePos.y / context->config_json["cell_size"].get()); } // 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; }