diff --git a/source/game/options.cpp b/source/game/options.cpp index d9e0ca2..6d4fe52 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -2,9 +2,11 @@ #include +#include // Para ranges::transform #include // Para create_directories #include // Para ifstream, ofstream #include // Para cout, cerr +#include // Para back_inserter #include // Para string #include // Para unordered_map @@ -1050,110 +1052,91 @@ namespace Options { crtpi_file_path = path; } + // Defaults dels 4 presets CrtPi (DEFAULT, CURVED, SHARP, MINIMAL) + static auto defaultCrtPiPresets() -> std::vector { + return { + {.name = "DEFAULT", .scanline_weight = 6.0F, .scanline_gap_brightness = 0.12F, .bloom_factor = 3.5F, .input_gamma = 2.4F, .output_gamma = 2.2F, .mask_brightness = 0.80F, .curvature_x = 0.05F, .curvature_y = 0.10F, .mask_type = 2, .enable_scanlines = true, .enable_multisample = true, .enable_gamma = true, .enable_curvature = false, .enable_sharper = false}, + {.name = "CURVED", .scanline_weight = 6.0F, .scanline_gap_brightness = 0.12F, .bloom_factor = 3.5F, .input_gamma = 2.4F, .output_gamma = 2.2F, .mask_brightness = 0.80F, .curvature_x = 0.05F, .curvature_y = 0.10F, .mask_type = 2, .enable_scanlines = true, .enable_multisample = true, .enable_gamma = true, .enable_curvature = true, .enable_sharper = false}, + {.name = "SHARP", .scanline_weight = 6.0F, .scanline_gap_brightness = 0.12F, .bloom_factor = 3.5F, .input_gamma = 2.4F, .output_gamma = 2.2F, .mask_brightness = 0.80F, .curvature_x = 0.05F, .curvature_y = 0.10F, .mask_type = 2, .enable_scanlines = true, .enable_multisample = false, .enable_gamma = true, .enable_curvature = false, .enable_sharper = true}, + {.name = "MINIMAL", .scanline_weight = 8.0F, .scanline_gap_brightness = 0.05F, .bloom_factor = 2.0F, .input_gamma = 2.4F, .output_gamma = 2.2F, .mask_brightness = 1.00F, .curvature_x = 0.0F, .curvature_y = 0.0F, .mask_type = 0, .enable_scanlines = true, .enable_multisample = false, .enable_gamma = false, .enable_curvature = false, .enable_sharper = false}}; + } + + // Escriu el fitxer CrtPi amb capçalera + els 4 presets default. Retorna false si no pot obrir. + static auto writeCrtPiDefaultFile(const std::string& path, const std::vector& presets) -> bool { + const std::filesystem::path P(path); + if (P.has_parent_path()) { + std::error_code ec; + std::filesystem::create_directories(P.parent_path(), ec); + } + std::ofstream out(path); + if (!out.is_open()) { return false; } + + out << "# JailDoctor's Dilemma - CrtPi Shader Presets\n"; + out << "# scanline_weight: ajuste gaussiano (mayor = scanlines mas estrechas, default 6.0)\n"; + out << "# scanline_gap_brightness: brillo minimo entre scanlines (0.0-1.0, default 0.12)\n"; + out << "# bloom_factor: factor de brillo para zonas iluminadas (default 3.5)\n"; + out << "# input_gamma: gamma de entrada - linealizacion (default 2.4)\n"; + out << "# output_gamma: gamma de salida - codificacion (default 2.2)\n"; + out << "# mask_brightness: brillo sub-pixeles de la mascara de fosforo (default 0.80)\n"; + out << "# curvature_x/y: distorsion barrel CRT (0.0 = plana)\n"; + out << "# mask_type: 0=ninguna, 1=verde/magenta, 2=RGB fosforo\n"; + out << "# enable_scanlines/multisample/gamma/curvature/sharper: true/false\n"; + out << "\npresets:\n"; + for (const auto& p : presets) { + out << " - name: \"" << p.name << "\"\n"; + out << " scanline_weight: " << p.scanline_weight << "\n"; + out << " scanline_gap_brightness: " << p.scanline_gap_brightness << "\n"; + out << " bloom_factor: " << p.bloom_factor << "\n"; + out << " input_gamma: " << p.input_gamma << "\n"; + out << " output_gamma: " << p.output_gamma << "\n"; + out << " mask_brightness: " << p.mask_brightness << "\n"; + out << " curvature_x: " << p.curvature_x << "\n"; + out << " curvature_y: " << p.curvature_y << "\n"; + out << " mask_type: " << p.mask_type << "\n"; + out << " enable_scanlines: " << (p.enable_scanlines ? "true" : "false") << "\n"; + out << " enable_multisample: " << (p.enable_multisample ? "true" : "false") << "\n"; + out << " enable_gamma: " << (p.enable_gamma ? "true" : "false") << "\n"; + out << " enable_curvature: " << (p.enable_curvature ? "true" : "false") << "\n"; + out << " enable_sharper: " << (p.enable_sharper ? "true" : "false") << "\n"; + } + return true; + } + + // Parseja un node YAML a un CrtPiPreset usant els helpers genèrics + static auto parseCrtPiPreset(const fkyaml::node& p) -> CrtPiPreset { + CrtPiPreset preset; + readYamlField(p, "name", preset.name); + parseFloatField(p, "scanline_weight", preset.scanline_weight); + parseFloatField(p, "scanline_gap_brightness", preset.scanline_gap_brightness); + parseFloatField(p, "bloom_factor", preset.bloom_factor); + parseFloatField(p, "input_gamma", preset.input_gamma); + parseFloatField(p, "output_gamma", preset.output_gamma); + parseFloatField(p, "mask_brightness", preset.mask_brightness); + parseFloatField(p, "curvature_x", preset.curvature_x); + parseFloatField(p, "curvature_y", preset.curvature_y); + readYamlField(p, "mask_type", preset.mask_type); + readYamlField(p, "enable_scanlines", preset.enable_scanlines); + readYamlField(p, "enable_multisample", preset.enable_multisample); + readYamlField(p, "enable_gamma", preset.enable_gamma); + readYamlField(p, "enable_curvature", preset.enable_curvature); + readYamlField(p, "enable_sharper", preset.enable_sharper); + return preset; + } + // Carga los presets del shader CrtPi desde el fichero. Crea defaults si no existe. - auto loadCrtPiFromFile() -> bool { // NOLINT(readability-function-cognitive-complexity) + auto loadCrtPiFromFile() -> bool { crtpi_presets.clear(); std::ifstream file(crtpi_file_path); if (!file.good()) { std::cout << "CrtPi file not found, creating default: " << crtpi_file_path << '\n'; - // Crear directorio padre si no existe - const std::filesystem::path P(crtpi_file_path); - if (P.has_parent_path()) { - std::error_code ec; - std::filesystem::create_directories(P.parent_path(), ec); - } - // Escribir defaults - std::ofstream out(crtpi_file_path); - if (!out.is_open()) { - std::cerr << "Error: Cannot create CrtPi file: " << crtpi_file_path << '\n'; - // Cargar defaults en memoria aunque no se pueda escribir - crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false}); - crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false}); - crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true}); - crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false}); - video.shader.current_crtpi_preset = 0; - return true; - } - out << "# JailDoctor's Dilemma - CrtPi Shader Presets\n"; - out << "# scanline_weight: ajuste gaussiano (mayor = scanlines mas estrechas, default 6.0)\n"; - out << "# scanline_gap_brightness: brillo minimo entre scanlines (0.0-1.0, default 0.12)\n"; - out << "# bloom_factor: factor de brillo para zonas iluminadas (default 3.5)\n"; - out << "# input_gamma: gamma de entrada - linealizacion (default 2.4)\n"; - out << "# output_gamma: gamma de salida - codificacion (default 2.2)\n"; - out << "# mask_brightness: brillo sub-pixeles de la mascara de fosforo (default 0.80)\n"; - out << "# curvature_x/y: distorsion barrel CRT (0.0 = plana)\n"; - out << "# mask_type: 0=ninguna, 1=verde/magenta, 2=RGB fosforo\n"; - out << "# enable_scanlines/multisample/gamma/curvature/sharper: true/false\n"; - out << "\n"; - out << "presets:\n"; - out << " - name: \"DEFAULT\"\n"; - out << " scanline_weight: 6.0\n"; - out << " scanline_gap_brightness: 0.12\n"; - out << " bloom_factor: 3.5\n"; - out << " input_gamma: 2.4\n"; - out << " output_gamma: 2.2\n"; - out << " mask_brightness: 0.80\n"; - out << " curvature_x: 0.05\n"; - out << " curvature_y: 0.10\n"; - out << " mask_type: 2\n"; - out << " enable_scanlines: true\n"; - out << " enable_multisample: true\n"; - out << " enable_gamma: true\n"; - out << " enable_curvature: false\n"; - out << " enable_sharper: false\n"; - out << " - name: \"CURVED\"\n"; - out << " scanline_weight: 6.0\n"; - out << " scanline_gap_brightness: 0.12\n"; - out << " bloom_factor: 3.5\n"; - out << " input_gamma: 2.4\n"; - out << " output_gamma: 2.2\n"; - out << " mask_brightness: 0.80\n"; - out << " curvature_x: 0.05\n"; - out << " curvature_y: 0.10\n"; - out << " mask_type: 2\n"; - out << " enable_scanlines: true\n"; - out << " enable_multisample: true\n"; - out << " enable_gamma: true\n"; - out << " enable_curvature: true\n"; - out << " enable_sharper: false\n"; - out << " - name: \"SHARP\"\n"; - out << " scanline_weight: 6.0\n"; - out << " scanline_gap_brightness: 0.12\n"; - out << " bloom_factor: 3.5\n"; - out << " input_gamma: 2.4\n"; - out << " output_gamma: 2.2\n"; - out << " mask_brightness: 0.80\n"; - out << " curvature_x: 0.05\n"; - out << " curvature_y: 0.10\n"; - out << " mask_type: 2\n"; - out << " enable_scanlines: true\n"; - out << " enable_multisample: false\n"; - out << " enable_gamma: true\n"; - out << " enable_curvature: false\n"; - out << " enable_sharper: true\n"; - out << " - name: \"MINIMAL\"\n"; - out << " scanline_weight: 8.0\n"; - out << " scanline_gap_brightness: 0.05\n"; - out << " bloom_factor: 2.0\n"; - out << " input_gamma: 2.4\n"; - out << " output_gamma: 2.2\n"; - out << " mask_brightness: 1.00\n"; - out << " curvature_x: 0.0\n"; - out << " curvature_y: 0.0\n"; - out << " mask_type: 0\n"; - out << " enable_scanlines: true\n"; - out << " enable_multisample: false\n"; - out << " enable_gamma: false\n"; - out << " enable_curvature: false\n"; - out << " enable_sharper: false\n"; - out.close(); - std::cout << "CrtPi file created with defaults: " << crtpi_file_path << '\n'; - crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false}); - crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false}); - crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true}); - crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false}); + crtpi_presets = defaultCrtPiPresets(); video.shader.current_crtpi_preset = 0; + if (!writeCrtPiDefaultFile(crtpi_file_path, crtpi_presets)) { + std::cerr << "Error: Cannot create CrtPi file: " << crtpi_file_path << '\n'; + return true; // defaults en memòria igualment + } + std::cout << "CrtPi file created with defaults: " << crtpi_file_path << '\n'; return true; } @@ -1162,77 +1145,21 @@ namespace Options { try { auto yaml = fkyaml::node::deserialize(content); - if (yaml.contains("presets")) { - const auto& presets = yaml["presets"]; - for (const auto& p : presets) { - CrtPiPreset preset; - if (p.contains("name")) { - preset.name = p["name"].get_value(); - } - parseFloatField(p, "scanline_weight", preset.scanline_weight); - parseFloatField(p, "scanline_gap_brightness", preset.scanline_gap_brightness); - parseFloatField(p, "bloom_factor", preset.bloom_factor); - parseFloatField(p, "input_gamma", preset.input_gamma); - parseFloatField(p, "output_gamma", preset.output_gamma); - parseFloatField(p, "mask_brightness", preset.mask_brightness); - parseFloatField(p, "curvature_x", preset.curvature_x); - parseFloatField(p, "curvature_y", preset.curvature_y); - if (p.contains("mask_type")) { - try { - preset.mask_type = p["mask_type"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - if (p.contains("enable_scanlines")) { - try { - preset.enable_scanlines = p["enable_scanlines"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - if (p.contains("enable_multisample")) { - try { - preset.enable_multisample = p["enable_multisample"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - if (p.contains("enable_gamma")) { - try { - preset.enable_gamma = p["enable_gamma"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - if (p.contains("enable_curvature")) { - try { - preset.enable_curvature = p["enable_curvature"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - if (p.contains("enable_sharper")) { - try { - preset.enable_sharper = p["enable_sharper"].get_value(); - } catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */ - } - } - crtpi_presets.push_back(preset); - } + const auto& presets_node = yaml["presets"]; + std::ranges::transform(presets_node, std::back_inserter(crtpi_presets), parseCrtPiPreset); } - - // Resolver el nombre del preset a índice if (!crtpi_presets.empty()) { resolveCrtPiPresetName(); } else { video.shader.current_crtpi_preset = 0; } - std::cout << "CrtPi file loaded: " << crtpi_presets.size() << " preset(s)\n"; return true; - } catch (const fkyaml::exception& e) { std::cerr << "Error parsing CrtPi YAML: " << e.what() << '\n'; - // Cargar defaults en memoria en caso de error crtpi_presets.clear(); - crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false}); + crtpi_presets.push_back(defaultCrtPiPresets().front()); // només DEFAULT en cas d'error video.shader.current_crtpi_preset = 0; return false; }