diff --git a/source/core/rendering/screen.cpp b/source/core/rendering/screen.cpp index 2409516..83cef7c 100644 --- a/source/core/rendering/screen.cpp +++ b/source/core/rendering/screen.cpp @@ -590,42 +590,24 @@ auto loadData(const std::string& filepath) -> std::vector { 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 { - 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 void Screen::applyCurrentPostFXPreset() { if (shader_backend_ && !Options::postfx_presets.empty()) { const auto& p = Options::postfx_presets[static_cast(Options::video.shader.current_postfx_preset)]; - // Supersampling es un toggle global (Options::video.supersampling.enabled), no por preset. - // setOversample primero: puede recrear texturas antes de que setPostFXParams - // decida si hornear scanlines en CPU o aplicarlas en GPU. - shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1); - 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}; + Rendering::PostFXParams params{ + .vignette = p.vignette, + .scanlines = p.scanlines, + .chroma_min = p.chroma_min, + .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); } } @@ -698,11 +680,9 @@ void Screen::initShaders() { shader_backend_->init(window_, tex, "", ""); 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_->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) { applyCurrentPostFXPreset(); diff --git a/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp b/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp index 6298898..d1fe704 100644 --- a/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp +++ b/source/core/rendering/sdl3gpu/sdl3gpu_shader.hpp @@ -7,20 +7,28 @@ // PostFX uniforms pushed to fragment stage each frame. // 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 { + // vec4 #0 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 screen_height; // logical height in pixels (used by bleeding effect) - float mask_strength; // 0 = off, 1 = full phosphor dot mask - float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction - float curvature; // 0 = flat, 1 = max barrel distortion - float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding - float pixel_scale; // physical pixels per logical pixel (vh / tex_height_) - 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 — keep struct at 48 bytes (3 × 16) + // vec4 #1 + float mask_strength; // 0 = off, 1 = full phosphor dot mask + float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction + float curvature; // 0 = flat, 1 = max barrel distortion + float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding + // vec4 #2 + float pixel_scale; // physical pixels per logical pixel (vh / tex_height_) + float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f) + float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz + 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. @@ -49,15 +57,6 @@ struct CrtPiUniforms { 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 { /** @@ -99,18 +98,6 @@ namespace Rendering { // Activa/desactiva escalado entero (integer scale) 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 override; - // Selecciona el shader de post-procesado activo (POSTFX o CRTPI) void setActiveShader(ShaderType type) override; @@ -137,42 +124,30 @@ namespace Rendering { Uint32 num_uniform_buffers) -> SDL_GPUShader*; auto createPipeline() -> bool; - auto createCrtPiPipeline() -> bool; // Pipeline dedicado para el shader CrtPi - 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) + auto createCrtPiPipeline() -> bool; // Pipeline dedicado para el shader CrtPi + auto reinitTexturesAndBuffer() -> bool; // Recrea scene_texture_ y upload_buffer_ // Devuelve el mejor present mode disponible: IMMEDIATE > MAILBOX > VSYNC [[nodiscard]] auto bestPresentMode(bool vsync) const -> SDL_GPUPresentMode; SDL_Window* window_ = nullptr; SDL_GPUDevice* device_ = nullptr; - SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass (→ swapchain o → postfx_texture_) - SDL_GPUGraphicsPipeline* crtpi_pipeline_ = nullptr; // CrtPi pass (→ swapchain directo, sin SS) - 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* 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_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass → swapchain + SDL_GPUGraphicsPipeline* crtpi_pipeline_ = nullptr; // CrtPi pass → swapchain + SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_) SDL_GPUTransferBuffer* upload_buffer_ = nullptr; - SDL_GPUSampler* sampler_ = nullptr; // NEAREST - SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR + SDL_GPUSampler* sampler_ = nullptr; // NEAREST - 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}; ShaderType active_shader_ = ShaderType::POSTFX; // Shader de post-procesado activo int game_width_ = 0; // Dimensiones originales del canvas 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 preferred_driver_; // Driver preferido; vacío = auto (SDL elige) bool is_initialized_ = false; bool vsync_ = true; bool integer_scale_ = false; - bool linear_upscale_ = false; // Upscale NEAREST (false) o LINEAR (true) }; } // namespace Rendering diff --git a/source/core/rendering/shader_backend.hpp b/source/core/rendering/shader_backend.hpp index def2c60..03f6979 100644 --- a/source/core/rendering/shader_backend.hpp +++ b/source/core/rendering/shader_backend.hpp @@ -19,12 +19,19 @@ namespace Rendering { struct PostFXParams { float vignette = 0.0F; // Intensidad de la viñeta 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 gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full) float curvature = 0.0F; // Curvatura barrel CRT float bleeding = 0.0F; // Sangrado de color NTSC 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*/) {} - /** - * @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 { return {0, 0}; } - /** * @brief Verifica si el backend está usando aceleración por hardware * @return true si usa aceleración (OpenGL/Metal/Vulkan) diff --git a/source/game/options.cpp b/source/game/options.cpp index 566eead..3ce82ce 100644 --- a/source/game/options.cpp +++ b/source/game/options.cpp @@ -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(); - } catch (...) { - video.supersampling.enabled = Defaults::Video::SUPERSAMPLING; - } - } - if (ss_node.contains("linear_upscale")) { - try { - video.supersampling.linear_upscale = ss_node["linear_upscale"].get_value(); - } 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(); - } catch (...) { - video.supersampling.downscale_algo = Defaults::Video::DOWNSCALE_ALGO; - } - } - } - // Helper: carga la sección shader desde YAML void loadShaderConfigFromYaml(const fkyaml::node& sh_node) { if (sh_node.contains("enabled")) { @@ -437,9 +412,6 @@ namespace Options { if (vid.contains("gpu")) { loadGPUConfigFromYaml(vid["gpu"]); } - if (vid.contains("supersampling")) { - loadSupersamplingConfigFromYaml(vid["supersampling"]); - } if (vid.contains("shader")) { loadShaderConfigFromYaml(vid["shader"]); } @@ -811,10 +783,6 @@ namespace Options { file << " gpu:\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 << " 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 << " enabled: " << (video.shader.enabled ? "true" : "false") << "\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, "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, "gamma", preset.gamma); parseFloatField(p, "curvature", preset.curvature); parseFloatField(p, "bleeding", preset.bleeding); 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 // en el fichero del usuario se ignora silenciosamente (compatible). 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 << "# vignette: screen darkening at the edges\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 << "# gamma: gamma correction input 2.4 / output 2.2\n"; file << "# curvature: CRT barrel distortion\n"; file << "# bleeding: NTSC horizontal colour bleeding\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 << "presets:\n"; file << " - name: \"CRT\"\n"; file << " vignette: 0.6\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 << " gamma: 0.8\n"; file << " curvature: 0.0\n"; @@ -1005,7 +979,8 @@ namespace Options { file << " - name: \"NTSC\"\n"; file << " vignette: 0.4\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 << " gamma: 0.5\n"; file << " curvature: 0.0\n"; @@ -1014,7 +989,8 @@ namespace Options { file << " - name: \"CURVED\"\n"; file << " vignette: 0.5\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 << " gamma: 0.7\n"; file << " curvature: 0.8\n"; @@ -1023,7 +999,8 @@ namespace Options { file << " - name: \"SCANLINES\"\n"; file << " vignette: 0.0\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 << " gamma: 0.0\n"; file << " curvature: 0.0\n"; @@ -1032,7 +1009,8 @@ namespace Options { file << " - name: \"SUBTLE\"\n"; file << " vignette: 0.3\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 << " gamma: 0.3\n"; file << " curvature: 0.0\n"; @@ -1041,7 +1019,8 @@ namespace Options { file << " - name: \"CRT LIVE\"\n"; file << " vignette: 0.5\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 << " gamma: 0.4\n"; file << " curvature: 0.3\n"; @@ -1052,14 +1031,14 @@ namespace Options { 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.push_back({"CRT", 0.6F, 0.7F, 0.3F, 0.6F, 0.8F, 0.0F, 0.0F, 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({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F, 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({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 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", .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({.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({.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({.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({.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({.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; return true; diff --git a/source/game/options.hpp b/source/game/options.hpp index 4e4b118..3592f47 100644 --- a/source/game/options.hpp +++ b/source/game/options.hpp @@ -79,13 +79,6 @@ namespace Options { 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) struct ShaderConfig { 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 Border border{}; // Borde de la pantalla GPU gpu{}; // Opciones de aceleración GPU - Supersampling supersampling{}; // Opciones de supersampling ShaderConfig shader{}; // Opciones de shader post-procesado }; @@ -157,12 +149,18 @@ namespace Options { std::string name; // Nombre del preset 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 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 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 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) + // 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