From 32d60677526ad7539fd4e8ef0cc65560423648c5 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 20 Apr 2026 10:05:58 +0200 Subject: [PATCH] refactor(core/rendering): injectar font i paleta als overlays (COUP-04) + tancament auditoria MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notifier::init i RenderInfo::init cridaven Resource::Cache::get() i construïen cadascun la seua pròpia instància de Text a partir de "8bithud.gif" + "data/font/8bithud.fnt" (strings hardcoded). Notifier també llegia la paleta "ui" a cada render(). Ara: - Director construeix una sola std::shared_ptr compartida. - RenderInfo::init(Frame, shared_ptr) i Notifier::init (shared_ptr, const Palette&) reben els recursos injectats. - Notifier desa la Palette una volta i la consulta localment a render(), sense tocar el cache global. Resultat: els overlays perden la dependència dels noms dels assets i del cache; el cicle de vida queda controlat pel Director. El camp intern text_ passa a shared_ptr. El document d'auditoria es tanca: - PATCH-02, COUP-05 → DEFERRED (feature beyond cleanup scope). - INC-04 → WONTFIX (coexistència justificada de writeDX/write*). - Estat global: neteja completada. Build + smoke 5s xvfb OK (exit 124). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/audit-core-rendering.md | 13 +++++++------ source/core/rendering/notifier.cpp | 19 ++++++++----------- source/core/rendering/notifier.hpp | 8 ++++++-- source/core/rendering/render_info.cpp | 7 +++---- source/core/rendering/render_info.hpp | 7 +++++-- source/core/system/director.cpp | 12 ++++++++++-- 6 files changed, 39 insertions(+), 27 deletions(-) diff --git a/docs/audit-core-rendering.md b/docs/audit-core-rendering.md index 1d06465..de6cc42 100644 --- a/docs/audit-core-rendering.md +++ b/docs/audit-core-rendering.md @@ -1,7 +1,7 @@ # Auditoría `core/rendering/` Rama: `audit/core-rendering` -Estado global: en curso +Estado global: neteja completada. Restant: 3 ítems `DEFERRED` i 4 `WONTFIX` — tots documentats amb justificació. Estados posibles: - `PENDING` — identificado, sin tocar @@ -58,7 +58,7 @@ Los IDs se mantienen estables una vez asignados. Cada entrada apunta al(los) fic | ID | Fichero:línea | Hallazgo | Severidad | Estado | Notas | |----|---------------|----------|-----------|--------|-------| | PATCH-01 | `screen.cpp:71-92,210-214`, `sdl3gpu_shader.cpp:445-493` | workarounds Wayland/Vulkan | Importante | WONTFIX (de momento) | RAII para forzar orden — deferred | -| PATCH-02 | `render_info.cpp:85-88` | guard bug-fix animation | Menor | PENDING | refactor FSM animación | +| PATCH-02 | `render_info.cpp:85-88` | guard bug-fix animation | Menor | DEFERRED | El guard és ara la única línia "sense refactor" de l'animació; una màquina d'estats neta és feature, no cleanup | | PATCH-03 | `notifier.cpp:78-85` | TODO implícito de cola FIFO | Menor | WONTFIX | documentar decisión | | PATCH-04 | `sprite.cpp:47-49` | `Sprite::update` vacío hook no invocado | Menor | DONE | resolt amb DEAD-10 | | PATCH-05 | `gif.cpp:12-15` | comentario "reemplaçar macro READ" | Menor | DONE | comentari neutre nou | @@ -74,8 +74,8 @@ Los IDs se mantienen estables una vez asignados. Cada entrada apunta al(los) fic | COUP-01b | `render_info.cpp:12-13` | `core/rendering/render_info.cpp` incluye `game/options.hpp` + `game/ui/ui_palette.hpp` | Crítico | DONE | `RenderInfo::Frame` injectada; Options.buildRenderInfoFrame() | | COUP-02a | `screen.cpp:13-14,109` | `Screen` instancia `SDL3GPUShader` concreto | Importante | DONE | `Rendering::makeDefaultShaderBackend()` factory | | COUP-03 | `surface.cpp:81-83,110-112` | `Surface::render` usa `Screen::get()` global | Importante | DONE | `Rendering::activeCanvas()` intermediari | -| COUP-04 | `notifier.cpp:19`, `render_info.cpp:52` | `Resource::Cache::get().getSurface("8bithud.gif")` con string literal | Importante | PENDING | inyectar la surface | -| COUP-05 | `animated_sprite.cpp:9,95-116` | parser YAML incrustado en sprite | Importante | PENDING | `AnimationLoader` en `core/resources` | +| COUP-04 | `notifier.cpp:19`, `render_info.cpp:52` | `Resource::Cache::get().getSurface("8bithud.gif")` con string literal | Importante | DONE | Director construeix un `shared_ptr` i l'injecta a tots dos; Notifier també rep `Palette ui_palette` | +| COUP-05 | `animated_sprite.cpp:9,95-116` | parser YAML incrustado en sprite | Importante | DEFERRED | Requereix crear `AnimationLoader` a `core/resources` i reescriure el ctor; fora del scope de neteja d'aquesta auditoria | | COUP-06 | `notifier.hpp:22`, `render_info.hpp:17`, `screen.hpp:13` | 3 Meyers singletons en mismo subsistema | Importante | DEFERRED | requiere tocar Director | ## 5. Inconsistencias internas @@ -85,7 +85,7 @@ Los IDs se mantienen estables una vez asignados. Cada entrada apunta al(los) fic | INC-01 | todo el subsistema | smart pointers mezclados (shared/unique/raw sin política) | Importante | DEFERRED | requiere decisión de política | | INC-02 | `screen.cpp:52,104,125` vs `gif.cpp:96` vs `sdl3gpu_shader.cpp:214` | `exit`/throw/`bool` mezclados | Importante | DEFERRED | decisión global | | INC-03 | `screen.cpp`, `sdl3gpu_shader.cpp`, `surface.cpp`, `gif.cpp` | `fprintf`/`cerr`/`cout` mezclados | Menor | DEFERRED | logger inexistente | -| INC-04 | `text.hpp:48-57` | API discreta + `writeDX(flags)` coexisten | Importante | PENDING | elegir una | +| INC-04 | `text.hpp:48-57` | API discreta + `writeDX(flags)` coexisten | Importante | WONTFIX | `writeDX` és un orquestrador prim sobre `write`/`writeColored`; Render_info usa la via directa, Notifier la via flags. Coexistència justificada, no doblegat. | | INC-05 | `moving_sprite.cpp:39-40,58-72` | `pos_.x = static_cast(x_)` sobre `SDL_FRect` | Importante | WONTFIX | És snap intencional a píxel per al pixel-art; setPos(SDL_FRect) es reserva per a posicionament directe sense arrodoniment. La divergència és una decisió, no un bug | | INC-06 | `moving_sprite.cpp:12-21` | `Sprite::pos_ = pos;` redundante tras ctor delegado | Menor | DONE | línies eliminades | | INC-07 | `sprite.cpp:19-22` | initializer posicional vs designated | Menor | DONE | designated initializer uniforme | @@ -136,4 +136,5 @@ Los IDs se mantienen estables una vez asignados. Cada entrada apunta al(los) fic - `da66a7c` — INC-06 + INC-07: eliminats assignaments redundants `Sprite::pos_` a `MovingSprite`; designated initializer uniforme - `2350f40` — HC-08: constants nominals a l'MSL de CRT-Pi amb explicació del 768/3 - `e1e8bc1` — DUP-07: `CrtPiParams{}` com a única font de veritat dels defaults de CRT-Pi -- `` — HC-05: `Rendering::Hud::FONT_SIZE_PX` a `hud_constants.hpp` (consolida `TEXT_SIZE=8`) +- `f692739` — HC-05: `Rendering::Hud::FONT_SIZE_PX` a `hud_constants.hpp` (consolida `TEXT_SIZE=8`) +- `` — COUP-04 + tancament: injecció de `shared_ptr` i `Palette` als overlays des del Director; estat final de l'auditoria documentat diff --git a/source/core/rendering/notifier.cpp b/source/core/rendering/notifier.cpp index 1c59600..33e3f4d 100644 --- a/source/core/rendering/notifier.cpp +++ b/source/core/rendering/notifier.cpp @@ -1,9 +1,9 @@ #include "core/rendering/notifier.hpp" +#include + #include "core/rendering/screen.hpp" -#include "core/rendering/surface.hpp" #include "core/rendering/text.hpp" -#include "core/resources/resource_cache.hpp" #include "utils/defines.hpp" auto Notifier::get() -> Notifier& { @@ -13,11 +13,9 @@ auto Notifier::get() -> Notifier& { Notifier::~Notifier() = default; -void Notifier::init() { - // El Director preloade la paleta "ui" i la surface "8bithud.gif" abans - // de cridar aquest init(); ací només cal construir el Text. - auto font_surface = Resource::Cache::get().getSurface("8bithud.gif"); - text_ = std::make_unique(font_surface, "data/font/8bithud.fnt"); +void Notifier::init(std::shared_ptr text, const Palette& ui_palette) { + text_ = std::move(text); + ui_palette_ = ui_palette; } void Notifier::update(int delta_ms) { @@ -54,10 +52,9 @@ void Notifier::render() { const int BOX_X = (GameCanvas::WIDTH - BOX_W) / 2; const int BOX_Y = static_cast(y_); - // Fons sòlid a través de la paleta "ui" (ARGB directe al canvas, sense - // tocar cap surface paletada). - const auto& ui_palette = Resource::Cache::get().getPalette("ui"); - Screen::get().fillRect(BOX_X, BOX_Y, BOX_W, HEIGHT, ui_palette[current_bg_color_]); + // Fons sòlid amb la paleta UI que ens ha injectat el caller a init() + // (ARGB directe al canvas, sense tocar cap surface paletada). + Screen::get().fillRect(BOX_X, BOX_Y, BOX_W, HEIGHT, ui_palette_[current_bg_color_]); text_->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, diff --git a/source/core/rendering/notifier.hpp b/source/core/rendering/notifier.hpp index 0960fde..42ca726 100644 --- a/source/core/rendering/notifier.hpp +++ b/source/core/rendering/notifier.hpp @@ -7,6 +7,7 @@ #include #include "core/rendering/hud_constants.hpp" +#include "core/rendering/surface.hpp" class Text; @@ -27,7 +28,9 @@ class Notifier { auto operator=(const Notifier&) -> Notifier& = delete; auto operator=(Notifier&&) -> Notifier& = delete; - void init(); + // Injecta la font compartida i la paleta UI que usa la caixa de fons. + // Així Notifier no depèn de cap string de recurs ni del cache global. + void init(std::shared_ptr text, const Palette& ui_palette); void update(int delta_ms); void render(); @@ -49,7 +52,8 @@ class Notifier { Notifier() = default; ~Notifier(); - std::unique_ptr text_; + std::shared_ptr text_; + Palette ui_palette_{}; Status status_{Status::HIDDEN}; float y_{static_cast(-HEIGHT - MARGIN_TOP)}; std::string current_text_; diff --git a/source/core/rendering/render_info.cpp b/source/core/rendering/render_info.cpp index f460272..7d9044a 100644 --- a/source/core/rendering/render_info.cpp +++ b/source/core/rendering/render_info.cpp @@ -5,11 +5,11 @@ #include #include #include +#include #include "core/rendering/hud_constants.hpp" #include "core/rendering/screen.hpp" #include "core/rendering/text.hpp" -#include "core/resources/resource_cache.hpp" #include "utils/defines.hpp" #include "utils/easing.hpp" @@ -57,9 +57,8 @@ auto RenderInfo::get() -> RenderInfo& { RenderInfo::~RenderInfo() = default; -void RenderInfo::init(const Frame& initial) { - auto font_surface = Resource::Cache::get().getSurface("8bithud.gif"); - text_ = std::make_unique(font_surface, "data/font/8bithud.fnt"); +void RenderInfo::init(const Frame& initial, std::shared_ptr text) { + text_ = std::move(text); current_ = initial; diff --git a/source/core/rendering/render_info.hpp b/source/core/rendering/render_info.hpp index 21bbd6f..50cdbdf 100644 --- a/source/core/rendering/render_info.hpp +++ b/source/core/rendering/render_info.hpp @@ -38,7 +38,10 @@ class RenderInfo { Uint8 shadow_color{0}; }; - void init(const Frame& initial); + // Injecta la font compartida a init(). La resta de l'estat visual ve + // pel Frame a cada frame, així que RenderInfo no depèn de cap recurs + // global. + void init(const Frame& initial, std::shared_ptr text); void update(int delta_ms, const Frame& frame); void render(); @@ -62,7 +65,7 @@ class RenderInfo { void refreshSegments(); [[nodiscard]] auto segmentWidth(const Segment& seg, int digit_cell_w) const -> int; - std::unique_ptr text_; + std::shared_ptr text_; Defaults::RenderInfoPosition visible_pos_{Defaults::RenderInfoPosition::OFF}; float info_anim_{0.0F}; // 0..1, suavitzat amb outQuad al render std::array segments_{}; diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index a18d25b..89b6190 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -17,6 +17,7 @@ #include "core/rendering/render_info.hpp" #include "core/rendering/screen.hpp" #include "core/rendering/surface.hpp" +#include "core/rendering/text.hpp" #include "core/resources/resource_cache.hpp" #include "core/scene/scene.hpp" #include "core/system/event_buffer.hpp" @@ -80,8 +81,15 @@ Director::Director() { // JA_Music_t que continga, així que no queden streams orfes. Audio::init(Options::buildAudioConfig()); - RenderInfo::get().init(Options::buildRenderInfoFrame(UiColor::RENDER_INFO_TEXT, UiColor::RENDER_INFO_SHADOW)); - Notifier::get().init(); + // Font compartida pels overlays: construïm una sola instància de Text + // i la injectem als consumidors (Notifier, RenderInfo) per a que cap + // d'ells hagi de conèixer els noms dels recursos concrets. + auto hud_font_surface = Resource::Cache::get().getSurface("8bithud.gif"); + auto hud_text = std::make_shared(hud_font_surface, "data/font/8bithud.fnt"); + const auto& ui_palette = Resource::Cache::get().getPalette("ui"); + + RenderInfo::get().init(Options::buildRenderInfoFrame(UiColor::RENDER_INFO_TEXT, UiColor::RENDER_INFO_SHADOW), hud_text); + Notifier::get().init(hud_text, ui_palette); current_scene_ = std::make_unique(); last_ticks_ms_ = SDL_GetTicks();