Files
aee-arcade/source/game/options.hpp
T
JailDesignerandClaude Opus 4.7 a3b03b87be refactor(game): COUP-03 + CONV-02 encapsulate Options state behind setters
L'estat mutable d'Options (window, video, audio, locale, presets, paths)
es mou a un anonymous namespace dins options.cpp. L'API pública del
namespace passa a ser:

- Getters const-ref: window(), video(), audio(), locale(),
  configVersion(), postfxPresets(), crtpiPresets().
- Setters específics que muten i persisteixen via saveToFile():
  setWindowZoom, setWindowFullscreen, setVideoVSync,
  setVideoScalingMode, setVideoRenderInfoPosition,
  setVideoRenderInfoShowTime, setShaderEnabled, setActiveShaderName,
  setPostFXPreset, setCrtPiPreset.

Els setters NO notifiquen els subsistemes: el caller (global_inputs.cpp)
crida explícitament Screen::setWindowZoom, reapplyShader, etc. La part
"observers" del audit es deixa WONTFIX justificat — notificar des
d'Options invertiria la direcció Director→Screen/Audio i Options
aprenria del layout dels subsistemes.

CONV-02 tanca al pas: la part Options dels "globals sense observers"
queda resolta amb la nova encapsulació. Map::* (l'altra meitat de
CONV-02) ja s'havia tancat amb PATCH-07.

Smoke tests 13/13 OK; log Game start → Bye! sota xvfb-run +
SDL_VIDEODRIVER=dummy + SIGINT idèntic al baseline de main.
clang-tidy i cppcheck nets sobre els fitxers modificats.

Refs: docs/audit-game.md (COUP-03, CONV-02, INCONS-01).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 08:37:59 +02:00

156 lines
6.0 KiB
C++

#pragma once
#include <string>
#include <vector>
#include "core/audio/audio.hpp"
#include "core/rendering/render_info.hpp"
#include "core/rendering/screen.hpp"
#include "core/rendering/shader_backend.hpp"
#include "utils/defaults.hpp"
// Gestor de configuració del joc. És l'ÚNIC lloc que coneix YAML i la ruta
// del config.yaml. Els subsistemes (Screen, Audio, ...) reben structs tipats
// a través dels build*Config(), de manera que no queden acoblats a aquest
// namespace ni al format concret del fitxer.
//
// L'estat mutable viu en un anonymous namespace dins d'`options.cpp`: els
// callers el llegeixen via getters const-ref (`window()`, `video()`, ...) i
// el muten via setters específics que persisteixen a config.yaml. Els
// setters NO notifiquen els subsistemes (Screen/Audio): el caller (típic.
// `core/input/global_inputs.cpp`) crida després el setter del subsistema.
// Aquesta asimetria preserva la direcció `Director → Screen/Audio` i evita
// que Options aprenga del layout dels subsistemes (decisió WONTFIX d'aquest
// refactor: veure docs/audit-game.md → COUP-03).
namespace Options {
struct Window {
int zoom{Defaults::Window::ZOOM};
bool fullscreen{Defaults::Window::FULLSCREEN};
};
struct Gpu {
bool acceleration{Defaults::Video::GPU_ACCELERATION};
std::string preferred_driver{Defaults::Video::GPU_PREFERRED_DRIVER};
};
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 {
bool vsync{Defaults::Video::VSYNC};
Defaults::ScalingMode scaling_mode{Defaults::Video::SCALING_MODE};
Defaults::TextureFilter texture_filter{Defaults::Video::TEXTURE_FILTER};
Defaults::RenderInfoPosition render_info_position{Defaults::Video::RENDER_INFO_POSITION};
bool render_info_show_time{Defaults::Video::RENDER_INFO_SHOW_TIME};
Gpu gpu{};
Shader shader{};
};
// Preset d'efectes PostFX (un per entrada a postfx.yaml).
struct PostFXPreset {
std::string name;
float vignette{0.0F};
float scanlines{0.0F};
float chroma{0.0F};
float mask{0.0F};
float gamma{0.0F};
float curvature{0.0F};
float bleeding{0.0F};
float flicker{0.0F};
// 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};
};
// 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};
};
struct Sound {
bool enabled{Defaults::Audio::SOUND_ENABLED};
float volume{Defaults::Audio::SOUND_VOLUME};
};
struct Audio {
bool enabled{Defaults::Audio::ENABLED};
float volume{Defaults::Audio::VOLUME};
Music music{};
Sound sound{};
};
// --- Getters de l'estat (read-only) ---
[[nodiscard]] auto window() -> const Window&;
[[nodiscard]] auto video() -> const Video&;
[[nodiscard]] auto audio() -> const Audio&;
[[nodiscard]] auto locale() -> const std::string&;
[[nodiscard]] auto configVersion() -> const std::string&;
[[nodiscard]] auto postfxPresets() -> const std::vector<PostFXPreset>&;
[[nodiscard]] auto crtpiPresets() -> const std::vector<CrtPiPreset>&;
// --- Setters: muten + persisteixen a config.yaml ---
// No notifiquen els subsistemes; el caller ha de propagar el canvi al
// subsistema corresponent (p.ex. Screen::setWindowZoom) per separat.
void setWindowZoom(int value);
void setWindowFullscreen(bool value);
void setVideoVSync(bool value);
void setVideoScalingMode(Defaults::ScalingMode value);
void setVideoRenderInfoPosition(Defaults::RenderInfoPosition value);
void setVideoRenderInfoShowTime(bool value);
void setShaderEnabled(bool value);
void setActiveShaderName(const std::string& value); // "postfx" | "crtpi"
void setPostFXPreset(const std::string& value);
void setCrtPiPreset(const std::string& value);
// --- API pública: càrrega/desament de fitxers ---
void setConfigFile(const std::string& path);
auto loadFromFile() -> bool;
auto saveToFile() -> bool;
void setPostFXFile(const std::string& path);
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;
// Els colors de text/ombra els decideix la UI del joc (no Options), per
// això es passen com a paràmetres.
[[nodiscard]] auto buildRenderInfoFrame(Uint8 text_color, Uint8 shadow_color) -> RenderInfo::Frame;
// `::Audio` és la classe global d'àudio (no `Options::Audio`, que és la
// struct serialitzable). Retornem la seua Config per passar-la a init().
[[nodiscard]] auto buildAudioConfig() -> ::Audio::Config;
} // namespace Options