options: loadCrtPiFromFile en helpers (defaults, writer, parser)

This commit is contained in:
2026-05-17 16:03:33 +02:00
parent 19c7b58cba
commit e89a664eed
+83 -156
View File
@@ -2,9 +2,11 @@
#include <SDL3/SDL.h>
#include <algorithm> // Para ranges::transform
#include <filesystem> // Para create_directories
#include <fstream> // Para ifstream, ofstream
#include <iostream> // Para cout, cerr
#include <iterator> // Para back_inserter
#include <string> // Para string
#include <unordered_map> // 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<CrtPiPreset> {
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<CrtPiPreset>& 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<std::string>();
}
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<int>();
} catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */
}
}
if (p.contains("enable_scanlines")) {
try {
preset.enable_scanlines = p["enable_scanlines"].get_value<bool>();
} catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */
}
}
if (p.contains("enable_multisample")) {
try {
preset.enable_multisample = p["enable_multisample"].get_value<bool>();
} catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */
}
}
if (p.contains("enable_gamma")) {
try {
preset.enable_gamma = p["enable_gamma"].get_value<bool>();
} catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */
}
}
if (p.contains("enable_curvature")) {
try {
preset.enable_curvature = p["enable_curvature"].get_value<bool>();
} catch (...) { /* @INTENTIONAL: camp YAML malformat → conservem default */
}
}
if (p.contains("enable_sharper")) {
try {
preset.enable_sharper = p["enable_sharper"].get_value<bool>();
} 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;
}