feat(notifier): infrastructura del sistema de notificacions toast

- Notifier singleton (System::init/get/destroy) que dibuixa un cuadre
  centrat al centre-superior amb fons semitransparent (derivat oscur del
  color del text) i bordes en línies.
- Màquina d'estats HIDDEN → ENTERING → HOLDING → EXITING amb easing
  outCubic (entrada) i inCubic (sortida), slide de 300 ms.
- pushRect() afegit a GpuFrameRenderer (2 triangles, edge_dist=0) per
  poder pintar el fons opac/semitransparent reutilitzant el pipeline de
  línies — sense afegir cap pipeline nou.
- VectorText::render/renderCentered admeten color RGBA explícit
  (default {0,0,0,0} preserva el comportament previ amb oscil·lador
  global de color).
- Easing header-only a core/utils/easing.hpp (outCubic, inCubic).
- Director crea Notifier just després del DebugOverlay i el draweja com
  a última capa per damunt de l'escena i el debug.

Encara cap consumer el crida; els F1-F5 i la doble pulsació d'ESC
arriben en commits posteriors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 22:07:56 +02:00
parent 799a97930c
commit 81330f8432
8 changed files with 595 additions and 258 deletions
+14 -1
View File
@@ -17,6 +17,7 @@
#include "core/rendering/sdl_manager.hpp"
#include "core/resources/resource_helper.hpp"
#include "core/resources/resource_loader.hpp"
#include "core/system/notifier.hpp"
#include "core/utils/path_utils.hpp"
#include "debug_overlay.hpp"
#include "game/scenes/game_scene.hpp"
@@ -264,6 +265,11 @@ auto Director::run() -> int {
// a todas las escenas. Toggle con F11 (visible por defecto en _DEBUG).
System::DebugOverlay debug_overlay(sdl.getRenderer(), cfg_->rendering);
// Sistema de notificacions toast: singleton accessible des d'on calgui
// (F1-F5 a sdl_manager, ESC a global_events). El renderer ha de viure
// tant com el Notifier; el destruim explícitament abans de tornar.
System::Notifier::init(sdl.getRenderer());
// Bucle principal: construir escena → frame loop → destruir → siguiente.
while (context.nextScene() != SceneType::EXIT) {
SceneManager::actual = context.nextScene();
@@ -275,6 +281,7 @@ auto Director::run() -> int {
}
SceneManager::actual = SceneType::EXIT;
System::Notifier::destroy();
return 0;
}
@@ -325,6 +332,9 @@ void Director::runFrameLoop(Scene& scene, SDLManager& sdl, SceneContext& context
scene.update(delta_time);
debug_overlay.update(delta_time);
if (auto* notifier = System::Notifier::get(); notifier != nullptr) {
notifier->update(delta_time);
}
Audio::update();
// Si la swapchain no está disponible (ventana minimizada, etc.),
@@ -335,7 +345,10 @@ void Director::runFrameLoop(Scene& scene, SDLManager& sdl, SceneContext& context
}
sdl.updateRenderingContext();
scene.draw();
debug_overlay.draw(); // siempre on top de la escena
debug_overlay.draw(); // sempre per damunt de l'escena
if (const auto* notifier = System::Notifier::get(); notifier != nullptr) {
notifier->draw(); // toast: per damunt de tot
}
sdl.present();
}
}