Shader CRT-Pi alternatiu en pipeline separat; selecció via config + presets (v0.6.0)
This commit is contained in:
1 parent
26b4d9e610
commit
ce5bec1b34
16 files changed
+11205
-8
No files matched your search
+153
-1
@@ -76,9 +76,15 @@ namespace {
|
||||
if (!video_node.contains("shader")) { return; }
|
||||
const auto& node = video_node["shader"];
|
||||
if (node.contains("enabled")) { Options::video.shader.enabled = node["enabled"].get_value<bool>(); }
|
||||
if (node.contains("current_shader")) {
|
||||
Options::video.shader.current_shader = node["current_shader"].get_value<std::string>();
|
||||
}
|
||||
if (node.contains("current_postfx_preset")) {
|
||||
Options::video.shader.current_postfx_preset = node["current_postfx_preset"].get_value<std::string>();
|
||||
}
|
||||
if (node.contains("current_crtpi_preset")) {
|
||||
Options::video.shader.current_crtpi_preset = node["current_crtpi_preset"].get_value<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void parseVideo(const fkyaml::node& yaml) {
|
||||
@@ -167,6 +173,61 @@ namespace {
|
||||
out << " flicker: " << preset.flicker << "\n";
|
||||
}
|
||||
|
||||
// Presets per defecte de CrtPi (tuning bàsic del shader original CRT-Pi).
|
||||
auto defaultCrtPiPresets() -> std::vector<Options::CrtPiPreset> {
|
||||
return {
|
||||
{.name = "default"},
|
||||
{.name = "sharper",
|
||||
.scanline_weight = 8.0F,
|
||||
.scanline_gap_brightness = 0.10F,
|
||||
.bloom_factor = 3.0F,
|
||||
.enable_sharper = true},
|
||||
{.name = "curved",
|
||||
.scanline_weight = 6.0F,
|
||||
.scanline_gap_brightness = 0.12F,
|
||||
.bloom_factor = 3.5F,
|
||||
.curvature_x = 0.05F,
|
||||
.curvature_y = 0.10F,
|
||||
.enable_curvature = true},
|
||||
};
|
||||
}
|
||||
|
||||
void parseCrtPiPreset(const fkyaml::node& node, Options::CrtPiPreset& preset) {
|
||||
if (node.contains("name")) { preset.name = node["name"].get_value<std::string>(); }
|
||||
if (node.contains("scanline_weight")) { preset.scanline_weight = node["scanline_weight"].get_value<float>(); }
|
||||
if (node.contains("scanline_gap_brightness")) { preset.scanline_gap_brightness = node["scanline_gap_brightness"].get_value<float>(); }
|
||||
if (node.contains("bloom_factor")) { preset.bloom_factor = node["bloom_factor"].get_value<float>(); }
|
||||
if (node.contains("input_gamma")) { preset.input_gamma = node["input_gamma"].get_value<float>(); }
|
||||
if (node.contains("output_gamma")) { preset.output_gamma = node["output_gamma"].get_value<float>(); }
|
||||
if (node.contains("mask_brightness")) { preset.mask_brightness = node["mask_brightness"].get_value<float>(); }
|
||||
if (node.contains("curvature_x")) { preset.curvature_x = node["curvature_x"].get_value<float>(); }
|
||||
if (node.contains("curvature_y")) { preset.curvature_y = node["curvature_y"].get_value<float>(); }
|
||||
if (node.contains("mask_type")) { preset.mask_type = node["mask_type"].get_value<int>(); }
|
||||
if (node.contains("enable_scanlines")) { preset.enable_scanlines = node["enable_scanlines"].get_value<bool>(); }
|
||||
if (node.contains("enable_multisample")) { preset.enable_multisample = node["enable_multisample"].get_value<bool>(); }
|
||||
if (node.contains("enable_gamma")) { preset.enable_gamma = node["enable_gamma"].get_value<bool>(); }
|
||||
if (node.contains("enable_curvature")) { preset.enable_curvature = node["enable_curvature"].get_value<bool>(); }
|
||||
if (node.contains("enable_sharper")) { preset.enable_sharper = node["enable_sharper"].get_value<bool>(); }
|
||||
}
|
||||
|
||||
void writeCrtPiPreset(std::ostringstream& out, const Options::CrtPiPreset& preset) {
|
||||
out << " - name: \"" << preset.name << "\"\n";
|
||||
out << " scanline_weight: " << preset.scanline_weight << "\n";
|
||||
out << " scanline_gap_brightness: " << preset.scanline_gap_brightness << "\n";
|
||||
out << " bloom_factor: " << preset.bloom_factor << "\n";
|
||||
out << " input_gamma: " << preset.input_gamma << "\n";
|
||||
out << " output_gamma: " << preset.output_gamma << "\n";
|
||||
out << " mask_brightness: " << preset.mask_brightness << "\n";
|
||||
out << " curvature_x: " << preset.curvature_x << "\n";
|
||||
out << " curvature_y: " << preset.curvature_y << "\n";
|
||||
out << " mask_type: " << preset.mask_type << "\n";
|
||||
out << " enable_scanlines: " << (preset.enable_scanlines ? "true" : "false") << "\n";
|
||||
out << " enable_multisample: " << (preset.enable_multisample ? "true" : "false") << "\n";
|
||||
out << " enable_gamma: " << (preset.enable_gamma ? "true" : "false") << "\n";
|
||||
out << " enable_curvature: " << (preset.enable_curvature ? "true" : "false") << "\n";
|
||||
out << " enable_sharper: " << (preset.enable_sharper ? "true" : "false") << "\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Options {
|
||||
@@ -229,7 +290,9 @@ namespace Options {
|
||||
out << " preferred_driver: \"" << video.gpu.preferred_driver << "\"\n";
|
||||
out << " shader:\n";
|
||||
out << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n";
|
||||
out << " current_postfx_preset: \"" << video.shader.current_postfx_preset << "\"\n\n";
|
||||
out << " current_shader: \"" << video.shader.current_shader << "\"\n";
|
||||
out << " current_postfx_preset: \"" << video.shader.current_postfx_preset << "\"\n";
|
||||
out << " current_crtpi_preset: \"" << video.shader.current_crtpi_preset << "\"\n\n";
|
||||
|
||||
out << "audio:\n";
|
||||
out << " enabled: " << (audio.enabled ? "true" : "false") << "\n";
|
||||
@@ -309,6 +372,95 @@ namespace Options {
|
||||
return writeFile(postfx_file_path, out.str());
|
||||
}
|
||||
|
||||
void setCrtPiFile(const std::string& path) {
|
||||
crtpi_file_path = path;
|
||||
}
|
||||
|
||||
auto loadCrtPiFromFile() -> bool {
|
||||
if (crtpi_file_path.empty()) { return false; }
|
||||
|
||||
const std::string CONTENT = readFileOrEmpty(crtpi_file_path);
|
||||
if (CONTENT.empty()) {
|
||||
crtpi_presets = defaultCrtPiPresets();
|
||||
return saveCrtPiToFile();
|
||||
}
|
||||
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(CONTENT);
|
||||
if (!yaml.contains("presets") || !yaml["presets"].is_sequence()) {
|
||||
crtpi_presets = defaultCrtPiPresets();
|
||||
return saveCrtPiToFile();
|
||||
}
|
||||
|
||||
crtpi_presets.clear();
|
||||
for (const auto& preset_node : yaml["presets"]) {
|
||||
CrtPiPreset preset;
|
||||
parseCrtPiPreset(preset_node, preset);
|
||||
crtpi_presets.push_back(preset);
|
||||
}
|
||||
|
||||
if (crtpi_presets.empty()) {
|
||||
crtpi_presets = defaultCrtPiPresets();
|
||||
return saveCrtPiToFile();
|
||||
}
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Options: error parsejant crtpi.yaml: " << e.what() << '\n';
|
||||
std::cerr << "Options: reescrivint el fitxer amb presets per defecte.\n";
|
||||
crtpi_presets = defaultCrtPiPresets();
|
||||
return saveCrtPiToFile();
|
||||
}
|
||||
}
|
||||
|
||||
auto saveCrtPiToFile() -> bool {
|
||||
if (crtpi_file_path.empty()) { return false; }
|
||||
|
||||
std::ostringstream out;
|
||||
out << "# Presets CRT-Pi per a AEE 2026. Editable a mà.\n";
|
||||
out << "# Els noms han de coincidir amb config.yaml > video.shader.current_crtpi_preset.\n";
|
||||
out << "presets:\n";
|
||||
for (const auto& preset : crtpi_presets) {
|
||||
writeCrtPiPreset(out, preset);
|
||||
}
|
||||
return writeFile(crtpi_file_path, out.str());
|
||||
}
|
||||
|
||||
auto buildActiveShader() -> Rendering::ShaderType {
|
||||
if (video.shader.current_shader == "crtpi") {
|
||||
return Rendering::ShaderType::CRTPI;
|
||||
}
|
||||
return Rendering::ShaderType::POSTFX;
|
||||
}
|
||||
|
||||
auto buildCrtPiParams() -> Rendering::CrtPiParams {
|
||||
// Si el shader està deshabilitat, retornem defaults (el dispatch anirà per
|
||||
// PostFX passthrough, però sent nets per si algú consulta aquests params).
|
||||
if (!video.shader.enabled) { return {}; }
|
||||
|
||||
const auto IT = std::ranges::find_if(crtpi_presets,
|
||||
[](const CrtPiPreset& preset) { return preset.name == video.shader.current_crtpi_preset; });
|
||||
if (IT == crtpi_presets.end()) {
|
||||
std::cerr << "Options: preset CrtPi \"" << video.shader.current_crtpi_preset << "\" no trobat; aplicant defaults.\n";
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
.scanline_weight = IT->scanline_weight,
|
||||
.scanline_gap_brightness = IT->scanline_gap_brightness,
|
||||
.bloom_factor = IT->bloom_factor,
|
||||
.input_gamma = IT->input_gamma,
|
||||
.output_gamma = IT->output_gamma,
|
||||
.mask_brightness = IT->mask_brightness,
|
||||
.curvature_x = IT->curvature_x,
|
||||
.curvature_y = IT->curvature_y,
|
||||
.mask_type = IT->mask_type,
|
||||
.enable_scanlines = IT->enable_scanlines,
|
||||
.enable_multisample = IT->enable_multisample,
|
||||
.enable_gamma = IT->enable_gamma,
|
||||
.enable_curvature = IT->enable_curvature,
|
||||
.enable_sharper = IT->enable_sharper,
|
||||
};
|
||||
}
|
||||
|
||||
auto buildPostFXParams() -> Rendering::PostFXParams {
|
||||
// Si el shader està deshabilitat, retornem params a zero → passthrough.
|
||||
if (!video.shader.enabled) { return {}; }
|
||||
|
||||
@@ -25,7 +25,9 @@ namespace Options {
|
||||
|
||||
struct Shader {
|
||||
bool enabled{Defaults::Video::SHADER_ENABLED};
|
||||
std::string current_shader{Defaults::Video::CURRENT_SHADER}; // "postfx" o "crtpi"
|
||||
std::string current_postfx_preset{Defaults::Video::POSTFX_DEFAULT_PRESET};
|
||||
std::string current_crtpi_preset{Defaults::Video::CRTPI_DEFAULT_PRESET};
|
||||
};
|
||||
|
||||
struct Video {
|
||||
@@ -49,6 +51,25 @@ namespace Options {
|
||||
float flicker{0.0F};
|
||||
};
|
||||
|
||||
// Preset del shader CRT-Pi (un per entrada a crtpi.yaml).
|
||||
struct CrtPiPreset {
|
||||
std::string name;
|
||||
float scanline_weight{6.0F};
|
||||
float scanline_gap_brightness{0.12F};
|
||||
float bloom_factor{3.5F};
|
||||
float input_gamma{2.4F};
|
||||
float output_gamma{2.2F};
|
||||
float mask_brightness{0.80F};
|
||||
float curvature_x{0.05F};
|
||||
float curvature_y{0.10F};
|
||||
int mask_type{2};
|
||||
bool enable_scanlines{true};
|
||||
bool enable_multisample{true};
|
||||
bool enable_gamma{true};
|
||||
bool enable_curvature{false};
|
||||
bool enable_sharper{false};
|
||||
};
|
||||
|
||||
struct Music {
|
||||
bool enabled{Defaults::Audio::MUSIC_ENABLED};
|
||||
float volume{Defaults::Audio::MUSIC_VOLUME};
|
||||
@@ -71,10 +92,12 @@ namespace Options {
|
||||
inline std::string config_version{};
|
||||
inline std::string config_file_path{};
|
||||
inline std::string postfx_file_path{};
|
||||
inline std::string crtpi_file_path{};
|
||||
inline Window window{};
|
||||
inline Video video{};
|
||||
inline Audio audio{};
|
||||
inline std::vector<PostFXPreset> postfx_presets{};
|
||||
inline std::vector<CrtPiPreset> crtpi_presets{};
|
||||
|
||||
// --- API pública ---
|
||||
void setConfigFile(const std::string& path);
|
||||
@@ -85,8 +108,14 @@ namespace Options {
|
||||
auto loadPostFXFromFile() -> bool;
|
||||
auto savePostFXToFile() -> bool;
|
||||
|
||||
void setCrtPiFile(const std::string& path);
|
||||
auto loadCrtPiFromFile() -> bool;
|
||||
auto saveCrtPiToFile() -> bool;
|
||||
|
||||
// --- Builders per als subsistemes ---
|
||||
[[nodiscard]] auto buildScreenConfig() -> Screen::Config;
|
||||
[[nodiscard]] auto buildPostFXParams() -> Rendering::PostFXParams;
|
||||
[[nodiscard]] auto buildCrtPiParams() -> Rendering::CrtPiParams;
|
||||
[[nodiscard]] auto buildActiveShader() -> Rendering::ShaderType;
|
||||
|
||||
} // namespace Options
|
||||
Reference in new issue
Block a user