PostFXParams/Preset amb chroma_min/max + scan_*; presets P2026 migrats
This commit is contained in:
@@ -590,42 +590,24 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
|
|||||||
return Resource::Helper::loadFile(filepath);
|
return Resource::Helper::loadFile(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::setLinearUpscale(bool linear) {
|
|
||||||
Options::video.supersampling.linear_upscale = linear;
|
|
||||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
|
||||||
shader_backend_->setLinearUpscale(linear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::setDownscaleAlgo(int algo) {
|
|
||||||
Options::video.supersampling.downscale_algo = algo;
|
|
||||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
|
||||||
shader_backend_->setDownscaleAlgo(algo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Screen::getSsTextureSize() const -> std::pair<int, int> {
|
|
||||||
if (!shader_backend_) { return {0, 0}; }
|
|
||||||
return shader_backend_->getSsTextureSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activa/desactiva el supersampling global (Ctrl+F4)
|
|
||||||
void Screen::toggleSupersampling() {
|
|
||||||
Options::video.supersampling.enabled = !Options::video.supersampling.enabled;
|
|
||||||
if (Options::video.shader.enabled && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
|
||||||
applyCurrentPostFXPreset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aplica los parámetros del preset actual al backend de shaders
|
// Aplica los parámetros del preset actual al backend de shaders
|
||||||
void Screen::applyCurrentPostFXPreset() {
|
void Screen::applyCurrentPostFXPreset() {
|
||||||
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
||||||
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)];
|
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)];
|
||||||
// Supersampling es un toggle global (Options::video.supersampling.enabled), no por preset.
|
Rendering::PostFXParams params{
|
||||||
// setOversample primero: puede recrear texturas antes de que setPostFXParams
|
.vignette = p.vignette,
|
||||||
// decida si hornear scanlines en CPU o aplicarlas en GPU.
|
.scanlines = p.scanlines,
|
||||||
shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1);
|
.chroma_min = p.chroma_min,
|
||||||
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding, .flicker = p.flicker};
|
.chroma_max = p.chroma_max,
|
||||||
|
.mask = p.mask,
|
||||||
|
.gamma = p.gamma,
|
||||||
|
.curvature = p.curvature,
|
||||||
|
.bleeding = p.bleeding,
|
||||||
|
.flicker = p.flicker,
|
||||||
|
.scan_dark_ratio = p.scan_dark_ratio,
|
||||||
|
.scan_dark_floor = p.scan_dark_floor,
|
||||||
|
.scan_edge_soft = p.scan_edge_soft,
|
||||||
|
};
|
||||||
shader_backend_->setPostFXParams(params);
|
shader_backend_->setPostFXParams(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -698,11 +680,9 @@ void Screen::initShaders() {
|
|||||||
shader_backend_->init(window_, tex, "", "");
|
shader_backend_->init(window_, tex, "", "");
|
||||||
gpu_driver_ = shader_backend_->getDriverName();
|
gpu_driver_ = shader_backend_->getDriverName();
|
||||||
|
|
||||||
// Propagar flags de vsync, integer scale, upscale y downscale al backend GPU
|
// Propagar flags de vsync e integer scale al backend GPU
|
||||||
shader_backend_->setVSync(Options::video.vertical_sync);
|
shader_backend_->setVSync(Options::video.vertical_sync);
|
||||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||||
shader_backend_->setLinearUpscale(Options::video.supersampling.linear_upscale);
|
|
||||||
shader_backend_->setDownscaleAlgo(Options::video.supersampling.downscale_algo);
|
|
||||||
|
|
||||||
if (Options::video.shader.enabled) {
|
if (Options::video.shader.enabled) {
|
||||||
applyCurrentPostFXPreset();
|
applyCurrentPostFXPreset();
|
||||||
|
|||||||
@@ -7,20 +7,28 @@
|
|||||||
|
|
||||||
// PostFX uniforms pushed to fragment stage each frame.
|
// PostFX uniforms pushed to fragment stage each frame.
|
||||||
// Must match the MSL struct and GLSL uniform block layout.
|
// Must match the MSL struct and GLSL uniform block layout.
|
||||||
// 12 floats = 48 bytes — meets Metal/Vulkan 16-byte alignment requirement.
|
// 16 floats = 64 bytes (4 × vec4) — meets Metal/Vulkan 16-byte alignment.
|
||||||
struct PostFXUniforms {
|
struct PostFXUniforms {
|
||||||
|
// vec4 #0
|
||||||
float vignette_strength; // 0 = none, ~0.8 = subtle
|
float vignette_strength; // 0 = none, ~0.8 = subtle
|
||||||
float chroma_strength; // 0 = off, ~0.2 = subtle chromatic aberration
|
float chroma_min; // aberració cromàtica mínima (sempre present)
|
||||||
float scanline_strength; // 0 = off, 1 = full
|
float scanline_strength; // 0 = off, 1 = full
|
||||||
float screen_height; // logical height in pixels (used by bleeding effect)
|
float screen_height; // logical height in pixels (used by bleeding effect)
|
||||||
|
// vec4 #1
|
||||||
float mask_strength; // 0 = off, 1 = full phosphor dot mask
|
float mask_strength; // 0 = off, 1 = full phosphor dot mask
|
||||||
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
|
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
|
||||||
float curvature; // 0 = flat, 1 = max barrel distortion
|
float curvature; // 0 = flat, 1 = max barrel distortion
|
||||||
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
|
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
|
||||||
|
// vec4 #2
|
||||||
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
|
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
|
||||||
float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f)
|
float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f)
|
||||||
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
|
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz
|
||||||
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — keep struct at 48 bytes (3 × 16)
|
float chroma_max; // si == chroma_min queda estàtic; si != pulsa sinusoidalment
|
||||||
|
// vec4 #3 — paràmetres de forma de les scanlines (exposats per preset)
|
||||||
|
float scan_dark_ratio; // fracció de subfila fosca (1/3 = 0.333 per defecte)
|
||||||
|
float scan_dark_floor; // brillantor de la subfila fosca (0.42 per defecte)
|
||||||
|
float scan_edge_soft; // suavitzat de la transició (0 = step dur, 1 = 1px físic)
|
||||||
|
float pad3;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CrtPi uniforms pushed to fragment stage each frame.
|
// CrtPi uniforms pushed to fragment stage each frame.
|
||||||
@@ -49,15 +57,6 @@ struct CrtPiUniforms {
|
|||||||
float texture_height; // Alto del canvas en píxeles (inyectado en render)
|
float texture_height; // Alto del canvas en píxeles (inyectado en render)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Downscale uniforms pushed to the Lanczos downscale fragment stage.
|
|
||||||
// 1 int + 3 floats = 16 bytes — meets Metal/Vulkan alignment.
|
|
||||||
struct DownscaleUniforms {
|
|
||||||
int algorithm; // 0 = Lanczos2 (ventana 2), 1 = Lanczos3 (ventana 3)
|
|
||||||
float pad0;
|
|
||||||
float pad1;
|
|
||||||
float pad2;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,18 +98,6 @@ namespace Rendering {
|
|||||||
// Activa/desactiva escalado entero (integer scale)
|
// Activa/desactiva escalado entero (integer scale)
|
||||||
void setScaleMode(bool integer_scale) override;
|
void setScaleMode(bool integer_scale) override;
|
||||||
|
|
||||||
// Establece factor de supersampling (1 = off, 3 = 3×SS)
|
|
||||||
void setOversample(int factor) override;
|
|
||||||
|
|
||||||
// Activa/desactiva interpolación LINEAR en el upscale (false = NEAREST)
|
|
||||||
void setLinearUpscale(bool linear) override;
|
|
||||||
|
|
||||||
// Selecciona algoritmo de downscale: 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3
|
|
||||||
void setDownscaleAlgo(int algo) override;
|
|
||||||
|
|
||||||
// Devuelve las dimensiones de la textura de supersampling (0,0 si SS desactivado)
|
|
||||||
[[nodiscard]] auto getSsTextureSize() const -> std::pair<int, int> override;
|
|
||||||
|
|
||||||
// Selecciona el shader de post-procesado activo (POSTFX o CRTPI)
|
// Selecciona el shader de post-procesado activo (POSTFX o CRTPI)
|
||||||
void setActiveShader(ShaderType type) override;
|
void setActiveShader(ShaderType type) override;
|
||||||
|
|
||||||
@@ -139,40 +126,28 @@ namespace Rendering {
|
|||||||
auto createPipeline() -> bool;
|
auto createPipeline() -> bool;
|
||||||
auto createCrtPiPipeline() -> bool; // Pipeline dedicado para el shader CrtPi
|
auto createCrtPiPipeline() -> bool; // Pipeline dedicado para el shader CrtPi
|
||||||
auto reinitTexturesAndBuffer() -> bool; // Recrea scene_texture_ y upload_buffer_
|
auto reinitTexturesAndBuffer() -> bool; // Recrea scene_texture_ y upload_buffer_
|
||||||
auto recreateScaledTexture(int factor) -> bool; // Recrea scaled_texture_ para factor dado
|
|
||||||
static auto calcSsFactor(float zoom) -> int; // Primer múltiplo de 3 >= zoom (mín 3)
|
|
||||||
// Devuelve el mejor present mode disponible: IMMEDIATE > MAILBOX > VSYNC
|
// Devuelve el mejor present mode disponible: IMMEDIATE > MAILBOX > VSYNC
|
||||||
[[nodiscard]] auto bestPresentMode(bool vsync) const -> SDL_GPUPresentMode;
|
[[nodiscard]] auto bestPresentMode(bool vsync) const -> SDL_GPUPresentMode;
|
||||||
|
|
||||||
SDL_Window* window_ = nullptr;
|
SDL_Window* window_ = nullptr;
|
||||||
SDL_GPUDevice* device_ = nullptr;
|
SDL_GPUDevice* device_ = nullptr;
|
||||||
SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass (→ swapchain o → postfx_texture_)
|
SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass → swapchain
|
||||||
SDL_GPUGraphicsPipeline* crtpi_pipeline_ = nullptr; // CrtPi pass (→ swapchain directo, sin SS)
|
SDL_GPUGraphicsPipeline* crtpi_pipeline_ = nullptr; // CrtPi pass → swapchain
|
||||||
SDL_GPUGraphicsPipeline* postfx_offscreen_pipeline_ = nullptr; // PostFX → postfx_texture_ (B8G8R8A8, solo con Lanczos)
|
|
||||||
SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale pass (solo con SS)
|
|
||||||
SDL_GPUGraphicsPipeline* downscale_pipeline_ = nullptr; // Lanczos downscale (solo con SS + algo > 0)
|
|
||||||
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
|
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
|
||||||
SDL_GPUTexture* scaled_texture_ = nullptr; // Upscale target (game×factor), solo con SS
|
|
||||||
SDL_GPUTexture* postfx_texture_ = nullptr; // PostFX output a resolución escalada, solo con Lanczos
|
|
||||||
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
|
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
|
||||||
SDL_GPUSampler* sampler_ = nullptr; // NEAREST
|
SDL_GPUSampler* sampler_ = nullptr; // NEAREST
|
||||||
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR
|
|
||||||
|
|
||||||
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F};
|
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_min = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .chroma_max = 0.15F, .scan_dark_ratio = 0.333F, .scan_dark_floor = 0.42F, .scan_edge_soft = 1.0F};
|
||||||
CrtPiUniforms crtpi_uniforms_{.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 = 1, .enable_multisample = 1, .enable_gamma = 1};
|
CrtPiUniforms crtpi_uniforms_{.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 = 1, .enable_multisample = 1, .enable_gamma = 1};
|
||||||
ShaderType active_shader_ = ShaderType::POSTFX; // Shader de post-procesado activo
|
ShaderType active_shader_ = ShaderType::POSTFX; // Shader de post-procesado activo
|
||||||
|
|
||||||
int game_width_ = 0; // Dimensiones originales del canvas
|
int game_width_ = 0; // Dimensiones originales del canvas
|
||||||
int game_height_ = 0;
|
int game_height_ = 0;
|
||||||
int ss_factor_ = 0; // Factor SS activo (3, 6, 9...) o 0 si SS desactivado
|
|
||||||
int oversample_ = 1; // SS on/off (1 = off, >1 = on)
|
|
||||||
int downscale_algo_ = 1; // 0 = bilinear legacy, 1 = Lanczos2, 2 = Lanczos3
|
|
||||||
std::string driver_name_;
|
std::string driver_name_;
|
||||||
std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige)
|
std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige)
|
||||||
bool is_initialized_ = false;
|
bool is_initialized_ = false;
|
||||||
bool vsync_ = true;
|
bool vsync_ = true;
|
||||||
bool integer_scale_ = false;
|
bool integer_scale_ = false;
|
||||||
bool linear_upscale_ = false; // Upscale NEAREST (false) o LINEAR (true)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -19,12 +19,19 @@ namespace Rendering {
|
|||||||
struct PostFXParams {
|
struct PostFXParams {
|
||||||
float vignette = 0.0F; // Intensidad de la viñeta
|
float vignette = 0.0F; // Intensidad de la viñeta
|
||||||
float scanlines = 0.0F; // Intensidad de las scanlines
|
float scanlines = 0.0F; // Intensidad de las scanlines
|
||||||
float chroma = 0.0F; // Aberración cromática
|
// Aberració cromàtica — varia entre min i max via sinusoidal; si coincideixen
|
||||||
|
// queda estàtica. min > 0 garanteix que la imatge mai sigui lliure de chroma.
|
||||||
|
float chroma_min = 0.0F;
|
||||||
|
float chroma_max = 0.0F;
|
||||||
float mask = 0.0F; // Máscara de fósforo RGB
|
float mask = 0.0F; // Máscara de fósforo RGB
|
||||||
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
||||||
float curvature = 0.0F; // Curvatura barrel CRT
|
float curvature = 0.0F; // Curvatura barrel CRT
|
||||||
float bleeding = 0.0F; // Sangrado de color NTSC
|
float bleeding = 0.0F; // Sangrado de color NTSC
|
||||||
float flicker = 0.0F; // Parpadeo de fósforo CRT ~50 Hz
|
float flicker = 0.0F; // Parpadeo de fósforo CRT ~50 Hz
|
||||||
|
// Forma de les scanlines — 3 subpíxels per fila lògica per defecte.
|
||||||
|
float scan_dark_ratio = 0.333F; // fracció obscura (1/3)
|
||||||
|
float scan_dark_floor = 0.42F; // brillantor subfila fosca
|
||||||
|
float scan_edge_soft = 1.0F; // 0 = step dur; 1 = suavitzat 1 px físic
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,34 +117,6 @@ namespace Rendering {
|
|||||||
*/
|
*/
|
||||||
virtual void setScaleMode(bool /*integer_scale*/) {}
|
virtual void setScaleMode(bool /*integer_scale*/) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Establece el factor de supersampling (1 = off, 3 = 3× SS)
|
|
||||||
* Con factor > 1, la textura GPU se crea a game×factor resolución y
|
|
||||||
* las scanlines se hornean en CPU (uploadPixels). El sampler usa LINEAR.
|
|
||||||
*/
|
|
||||||
virtual void setOversample(int /*factor*/) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Activa/desactiva interpolación LINEAR en el paso de upscale (SS).
|
|
||||||
* Por defecto NEAREST (false). Solo tiene efecto con supersampling activo.
|
|
||||||
*/
|
|
||||||
virtual void setLinearUpscale(bool /*linear*/) {}
|
|
||||||
[[nodiscard]] virtual auto isLinearUpscale() const -> bool { return false; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Selecciona el algoritmo de downscale tras el PostFX (SS activo).
|
|
||||||
* 0 = bilinear legacy (comportamiento actual, sin textura intermedia),
|
|
||||||
* 1 = Lanczos2 (ventana 2, ~25 muestras), 2 = Lanczos3 (ventana 3, ~49 muestras).
|
|
||||||
*/
|
|
||||||
virtual void setDownscaleAlgo(int /*algo*/) {}
|
|
||||||
[[nodiscard]] virtual auto getDownscaleAlgo() const -> int { return 0; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Devuelve las dimensiones de la textura de supersampling.
|
|
||||||
* @return Par (ancho, alto) en píxeles; (0, 0) si SS está desactivado.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] virtual auto getSsTextureSize() const -> std::pair<int, int> { return {0, 0}; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Verifica si el backend está usando aceleración por hardware
|
* @brief Verifica si el backend está usando aceleración por hardware
|
||||||
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
||||||
|
|||||||
+27
-48
@@ -323,31 +323,6 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: carga la sección supersampling desde YAML
|
|
||||||
void loadSupersamplingConfigFromYaml(const fkyaml::node& ss_node) {
|
|
||||||
if (ss_node.contains("enabled")) {
|
|
||||||
try {
|
|
||||||
video.supersampling.enabled = ss_node["enabled"].get_value<bool>();
|
|
||||||
} catch (...) {
|
|
||||||
video.supersampling.enabled = Defaults::Video::SUPERSAMPLING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ss_node.contains("linear_upscale")) {
|
|
||||||
try {
|
|
||||||
video.supersampling.linear_upscale = ss_node["linear_upscale"].get_value<bool>();
|
|
||||||
} catch (...) {
|
|
||||||
video.supersampling.linear_upscale = Defaults::Video::LINEAR_UPSCALE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ss_node.contains("downscale_algo")) {
|
|
||||||
try {
|
|
||||||
video.supersampling.downscale_algo = ss_node["downscale_algo"].get_value<int>();
|
|
||||||
} catch (...) {
|
|
||||||
video.supersampling.downscale_algo = Defaults::Video::DOWNSCALE_ALGO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper: carga la sección shader desde YAML
|
// Helper: carga la sección shader desde YAML
|
||||||
void loadShaderConfigFromYaml(const fkyaml::node& sh_node) {
|
void loadShaderConfigFromYaml(const fkyaml::node& sh_node) {
|
||||||
if (sh_node.contains("enabled")) {
|
if (sh_node.contains("enabled")) {
|
||||||
@@ -437,9 +412,6 @@ namespace Options {
|
|||||||
if (vid.contains("gpu")) {
|
if (vid.contains("gpu")) {
|
||||||
loadGPUConfigFromYaml(vid["gpu"]);
|
loadGPUConfigFromYaml(vid["gpu"]);
|
||||||
}
|
}
|
||||||
if (vid.contains("supersampling")) {
|
|
||||||
loadSupersamplingConfigFromYaml(vid["supersampling"]);
|
|
||||||
}
|
|
||||||
if (vid.contains("shader")) {
|
if (vid.contains("shader")) {
|
||||||
loadShaderConfigFromYaml(vid["shader"]);
|
loadShaderConfigFromYaml(vid["shader"]);
|
||||||
}
|
}
|
||||||
@@ -811,10 +783,6 @@ namespace Options {
|
|||||||
file << " gpu:\n";
|
file << " gpu:\n";
|
||||||
file << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n";
|
file << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n";
|
||||||
file << " preferred_driver: \"" << video.gpu.preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n";
|
file << " preferred_driver: \"" << video.gpu.preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n";
|
||||||
file << " supersampling:\n";
|
|
||||||
file << " enabled: " << (video.supersampling.enabled ? "true" : "false") << "\n";
|
|
||||||
file << " linear_upscale: " << (video.supersampling.linear_upscale ? "true" : "false") << "\n";
|
|
||||||
file << " downscale_algo: " << video.supersampling.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n";
|
|
||||||
file << " shader:\n";
|
file << " shader:\n";
|
||||||
file << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n";
|
file << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n";
|
||||||
file << " current_shader: " << (video.shader.current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n";
|
file << " current_shader: " << (video.shader.current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n";
|
||||||
@@ -939,12 +907,16 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
parseFloatField(p, "vignette", preset.vignette);
|
parseFloatField(p, "vignette", preset.vignette);
|
||||||
parseFloatField(p, "scanlines", preset.scanlines);
|
parseFloatField(p, "scanlines", preset.scanlines);
|
||||||
parseFloatField(p, "chroma", preset.chroma);
|
parseFloatField(p, "chroma_min", preset.chroma_min);
|
||||||
|
parseFloatField(p, "chroma_max", preset.chroma_max);
|
||||||
parseFloatField(p, "mask", preset.mask);
|
parseFloatField(p, "mask", preset.mask);
|
||||||
parseFloatField(p, "gamma", preset.gamma);
|
parseFloatField(p, "gamma", preset.gamma);
|
||||||
parseFloatField(p, "curvature", preset.curvature);
|
parseFloatField(p, "curvature", preset.curvature);
|
||||||
parseFloatField(p, "bleeding", preset.bleeding);
|
parseFloatField(p, "bleeding", preset.bleeding);
|
||||||
parseFloatField(p, "flicker", preset.flicker);
|
parseFloatField(p, "flicker", preset.flicker);
|
||||||
|
parseFloatField(p, "scan_dark_ratio", preset.scan_dark_ratio);
|
||||||
|
parseFloatField(p, "scan_dark_floor", preset.scan_dark_floor);
|
||||||
|
parseFloatField(p, "scan_edge_soft", preset.scan_edge_soft);
|
||||||
// Nota: 'supersampling' era un campo por-preset (eliminado). Si existe
|
// Nota: 'supersampling' era un campo por-preset (eliminado). Si existe
|
||||||
// en el fichero del usuario se ignora silenciosamente (compatible).
|
// en el fichero del usuario se ignora silenciosamente (compatible).
|
||||||
postfx_presets.push_back(preset);
|
postfx_presets.push_back(preset);
|
||||||
@@ -984,19 +956,21 @@ namespace Options {
|
|||||||
file << "# Each preset defines the intensity of post-processing effects (0.0 to 1.0).\n";
|
file << "# Each preset defines the intensity of post-processing effects (0.0 to 1.0).\n";
|
||||||
file << "# vignette: screen darkening at the edges\n";
|
file << "# vignette: screen darkening at the edges\n";
|
||||||
file << "# scanlines: horizontal scanline effect\n";
|
file << "# scanlines: horizontal scanline effect\n";
|
||||||
file << "# chroma: chromatic aberration (RGB color fringing)\n";
|
file << "# chroma_min/max: chromatic aberration (RGB color fringing)\n";
|
||||||
|
file << "# min == max → estàtic; min != max → pulsa sinusoïdalment entre els dos\n";
|
||||||
file << "# mask: phosphor dot mask (RGB subpixel pattern)\n";
|
file << "# mask: phosphor dot mask (RGB subpixel pattern)\n";
|
||||||
file << "# gamma: gamma correction input 2.4 / output 2.2\n";
|
file << "# gamma: gamma correction input 2.4 / output 2.2\n";
|
||||||
file << "# curvature: CRT barrel distortion\n";
|
file << "# curvature: CRT barrel distortion\n";
|
||||||
file << "# bleeding: NTSC horizontal colour bleeding\n";
|
file << "# bleeding: NTSC horizontal colour bleeding\n";
|
||||||
file << "# flicker: phosphor CRT flicker ~50 Hz (0.0 = off, 1.0 = max)\n";
|
file << "# flicker: phosphor CRT flicker ~50 Hz (0.0 = off, 1.0 = max)\n";
|
||||||
file << "# Note: supersampling is a global toggle in config.yaml, not per-preset.\n";
|
file << "# scan_dark_ratio/floor/edge_soft: forma analítica de les scanlines\n";
|
||||||
file << "\n";
|
file << "\n";
|
||||||
file << "presets:\n";
|
file << "presets:\n";
|
||||||
file << " - name: \"CRT\"\n";
|
file << " - name: \"CRT\"\n";
|
||||||
file << " vignette: 0.6\n";
|
file << " vignette: 0.6\n";
|
||||||
file << " scanlines: 0.7\n";
|
file << " scanlines: 0.7\n";
|
||||||
file << " chroma: 0.15\n";
|
file << " chroma_min: 0.15\n";
|
||||||
|
file << " chroma_max: 0.15\n";
|
||||||
file << " mask: 0.6\n";
|
file << " mask: 0.6\n";
|
||||||
file << " gamma: 0.8\n";
|
file << " gamma: 0.8\n";
|
||||||
file << " curvature: 0.0\n";
|
file << " curvature: 0.0\n";
|
||||||
@@ -1005,7 +979,8 @@ namespace Options {
|
|||||||
file << " - name: \"NTSC\"\n";
|
file << " - name: \"NTSC\"\n";
|
||||||
file << " vignette: 0.4\n";
|
file << " vignette: 0.4\n";
|
||||||
file << " scanlines: 0.5\n";
|
file << " scanlines: 0.5\n";
|
||||||
file << " chroma: 0.2\n";
|
file << " chroma_min: 0.2\n";
|
||||||
|
file << " chroma_max: 0.2\n";
|
||||||
file << " mask: 0.4\n";
|
file << " mask: 0.4\n";
|
||||||
file << " gamma: 0.5\n";
|
file << " gamma: 0.5\n";
|
||||||
file << " curvature: 0.0\n";
|
file << " curvature: 0.0\n";
|
||||||
@@ -1014,7 +989,8 @@ namespace Options {
|
|||||||
file << " - name: \"CURVED\"\n";
|
file << " - name: \"CURVED\"\n";
|
||||||
file << " vignette: 0.5\n";
|
file << " vignette: 0.5\n";
|
||||||
file << " scanlines: 0.6\n";
|
file << " scanlines: 0.6\n";
|
||||||
file << " chroma: 0.1\n";
|
file << " chroma_min: 0.1\n";
|
||||||
|
file << " chroma_max: 0.1\n";
|
||||||
file << " mask: 0.5\n";
|
file << " mask: 0.5\n";
|
||||||
file << " gamma: 0.7\n";
|
file << " gamma: 0.7\n";
|
||||||
file << " curvature: 0.8\n";
|
file << " curvature: 0.8\n";
|
||||||
@@ -1023,7 +999,8 @@ namespace Options {
|
|||||||
file << " - name: \"SCANLINES\"\n";
|
file << " - name: \"SCANLINES\"\n";
|
||||||
file << " vignette: 0.0\n";
|
file << " vignette: 0.0\n";
|
||||||
file << " scanlines: 0.8\n";
|
file << " scanlines: 0.8\n";
|
||||||
file << " chroma: 0.0\n";
|
file << " chroma_min: 0.0\n";
|
||||||
|
file << " chroma_max: 0.0\n";
|
||||||
file << " mask: 0.0\n";
|
file << " mask: 0.0\n";
|
||||||
file << " gamma: 0.0\n";
|
file << " gamma: 0.0\n";
|
||||||
file << " curvature: 0.0\n";
|
file << " curvature: 0.0\n";
|
||||||
@@ -1032,7 +1009,8 @@ namespace Options {
|
|||||||
file << " - name: \"SUBTLE\"\n";
|
file << " - name: \"SUBTLE\"\n";
|
||||||
file << " vignette: 0.3\n";
|
file << " vignette: 0.3\n";
|
||||||
file << " scanlines: 0.4\n";
|
file << " scanlines: 0.4\n";
|
||||||
file << " chroma: 0.05\n";
|
file << " chroma_min: 0.05\n";
|
||||||
|
file << " chroma_max: 0.05\n";
|
||||||
file << " mask: 0.0\n";
|
file << " mask: 0.0\n";
|
||||||
file << " gamma: 0.3\n";
|
file << " gamma: 0.3\n";
|
||||||
file << " curvature: 0.0\n";
|
file << " curvature: 0.0\n";
|
||||||
@@ -1041,7 +1019,8 @@ namespace Options {
|
|||||||
file << " - name: \"CRT LIVE\"\n";
|
file << " - name: \"CRT LIVE\"\n";
|
||||||
file << " vignette: 0.5\n";
|
file << " vignette: 0.5\n";
|
||||||
file << " scanlines: 0.6\n";
|
file << " scanlines: 0.6\n";
|
||||||
file << " chroma: 0.3\n";
|
file << " chroma_min: 0.3\n";
|
||||||
|
file << " chroma_max: 0.3\n";
|
||||||
file << " mask: 0.3\n";
|
file << " mask: 0.3\n";
|
||||||
file << " gamma: 0.4\n";
|
file << " gamma: 0.4\n";
|
||||||
file << " curvature: 0.3\n";
|
file << " curvature: 0.3\n";
|
||||||
@@ -1052,14 +1031,14 @@ namespace Options {
|
|||||||
|
|
||||||
std::cout << "PostFX file created with defaults: " << postfx_file_path << '\n';
|
std::cout << "PostFX file created with defaults: " << postfx_file_path << '\n';
|
||||||
|
|
||||||
// Cargar los presets recién creados
|
// Cargar los presets recién creados (chroma estàtic: min==max).
|
||||||
postfx_presets.clear();
|
postfx_presets.clear();
|
||||||
postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.3F, 0.6F, 0.8F, 0.0F, 0.0F, 0.0F});
|
postfx_presets.push_back({.name = "CRT", .vignette = 0.6F, .scanlines = 0.7F, .chroma_min = 0.15F, .chroma_max = 0.15F, .mask = 0.6F, .gamma = 0.8F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F});
|
||||||
postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F, 0.0F});
|
postfx_presets.push_back({.name = "NTSC", .vignette = 0.4F, .scanlines = 0.5F, .chroma_min = 0.2F, .chroma_max = 0.2F, .mask = 0.4F, .gamma = 0.5F, .curvature = 0.0F, .bleeding = 0.6F, .flicker = 0.0F});
|
||||||
postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F, 0.0F});
|
postfx_presets.push_back({.name = "CURVED", .vignette = 0.5F, .scanlines = 0.6F, .chroma_min = 0.1F, .chroma_max = 0.1F, .mask = 0.5F, .gamma = 0.7F, .curvature = 0.8F, .bleeding = 0.0F, .flicker = 0.0F});
|
||||||
postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
|
postfx_presets.push_back({.name = "SCANLINES", .vignette = 0.0F, .scanlines = 0.8F, .chroma_min = 0.0F, .chroma_max = 0.0F, .mask = 0.0F, .gamma = 0.0F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F});
|
||||||
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F});
|
postfx_presets.push_back({.name = "SUBTLE", .vignette = 0.3F, .scanlines = 0.4F, .chroma_min = 0.05F, .chroma_max = 0.05F, .mask = 0.0F, .gamma = 0.3F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F});
|
||||||
postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
|
postfx_presets.push_back({.name = "CRT LIVE", .vignette = 0.5F, .scanlines = 0.6F, .chroma_min = 0.3F, .chroma_max = 0.3F, .mask = 0.3F, .gamma = 0.4F, .curvature = 0.3F, .bleeding = 0.4F, .flicker = 0.8F});
|
||||||
video.shader.current_postfx_preset = 0;
|
video.shader.current_postfx_preset = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -79,13 +79,6 @@ namespace Options {
|
|||||||
std::string preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque.
|
std::string preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de supersampling
|
|
||||||
struct Supersampling {
|
|
||||||
bool enabled{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo
|
|
||||||
bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false)
|
|
||||||
int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3
|
|
||||||
};
|
|
||||||
|
|
||||||
// Estructura para las opciones de shader (dentro de Video)
|
// Estructura para las opciones de shader (dentro de Video)
|
||||||
struct ShaderConfig {
|
struct ShaderConfig {
|
||||||
bool enabled{Defaults::Video::SHADER_ENABLED}; // Indica si se usan shaders de post-procesado
|
bool enabled{Defaults::Video::SHADER_ENABLED}; // Indica si se usan shaders de post-procesado
|
||||||
@@ -108,7 +101,6 @@ namespace Options {
|
|||||||
std::string info; // Información sobre el modo de vídeo
|
std::string info; // Información sobre el modo de vídeo
|
||||||
Border border{}; // Borde de la pantalla
|
Border border{}; // Borde de la pantalla
|
||||||
GPU gpu{}; // Opciones de aceleración GPU
|
GPU gpu{}; // Opciones de aceleración GPU
|
||||||
Supersampling supersampling{}; // Opciones de supersampling
|
|
||||||
ShaderConfig shader{}; // Opciones de shader post-procesado
|
ShaderConfig shader{}; // Opciones de shader post-procesado
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,12 +149,18 @@ namespace Options {
|
|||||||
std::string name; // Nombre del preset
|
std::string name; // Nombre del preset
|
||||||
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
||||||
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
||||||
float chroma{0.15F}; // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima)
|
// Aberració cromàtica: min == max → estàtic; min != max → pulsa sinusoïdalment.
|
||||||
|
float chroma_min{0.15F};
|
||||||
|
float chroma_max{0.15F};
|
||||||
float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
|
float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
|
||||||
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
||||||
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
||||||
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
||||||
float flicker{0.0F}; // Parpadeo de fósforo CRT ~50 Hz (0.0 = off, 1.0 = máximo)
|
float flicker{0.0F}; // Parpadeo de fósforo CRT ~50 Hz (0.0 = off, 1.0 = máximo)
|
||||||
|
// Forma de les scanlines — 3 subpíxels per fila lògica per defecte.
|
||||||
|
float scan_dark_ratio{0.333F};
|
||||||
|
float scan_dark_floor{0.42F};
|
||||||
|
float scan_edge_soft{1.0F};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para un preset del shader CRT-Pi
|
// Estructura para un preset del shader CRT-Pi
|
||||||
|
|||||||
Reference in New Issue
Block a user