feat(logo): scanline reveal CRT amb glitch, bursts VHS i pulse de banda

This commit is contained in:
JailDesigner committed 2026-05-07 13:52:57 +02:00
1 parent 243ced7498
commit e32cff9dac
9 files changed
+440 -20

No files matched your search

+36 -9
View File
@@ -38,9 +38,23 @@ LogoScene::LogoScene(std::shared_ptr<Surface> logo, bool reset)
audio->stopAllSounds();
}
}
// Arranca el fade-in: el primer frame ja pinta negre opac que
// s'esvaeix cap a la imatge durant FADE_IN_MS.
fade_.begin(FADE_IN_MS, Transitions::FadeToBlack::Direction::FADE_IN);
// Arranca el revelat CRT: el primer frame ja pinta zero files (banda
// damunt del logo) i avança fins a tenir-lo visible al final.
const auto& s = UiConfig::get().logoScan();
scan_.begin({
.duration_ms = s.duration_ms,
.band_height_px = s.band_height_px,
.band_alpha = s.band_alpha,
.band_pulse_hz = s.band_pulse_hz,
.band_pulse_depth = s.band_pulse_depth,
.glitch_amplitude_px = s.glitch_amplitude_px,
.glitch_band_radius_px = s.glitch_band_radius_px,
.vhs_burst_per_sec = s.vhs_burst_per_sec,
.vhs_burst_duration_ms = s.vhs_burst_duration_ms,
.vhs_burst_height_px = s.vhs_burst_height_px,
.vhs_burst_amplitude_px = s.vhs_burst_amplitude_px,
.flash_ms = s.flash_ms,
});
}
LogoScene::~LogoScene() = default;
@@ -83,12 +97,16 @@ void LogoScene::update(int delta_ms) {
if (phase_ != Phase::DONE) {
phase_elapsed_ms_ += delta_ms;
// Tick dels efectes actius. `scan_` només fa feina visible
// durant Phase::SCAN; `fade_` només durant Phase::FADE_OUT. Tots
// dos són no-op si el seu duration_ms intern està a 0.
scan_.tick(delta_ms);
fade_.tick(delta_ms);
}
switch (phase_) {
case Phase::FADE_IN:
if (phase_elapsed_ms_ >= FADE_IN_MS) { enterMiddle(); }
case Phase::SCAN:
if (scan_.isFinished()) { enterMiddle(); }
break;
case Phase::MIDDLE:
// Música del títol al cor de la fase central. La crida és
@@ -121,13 +139,22 @@ void LogoScene::render() {
if (logo_) {
const int X = (GameCanvas::WIDTH - logo_->getWidth()) / 2;
const int Y = (GameCanvas::HEIGHT - logo_->getHeight()) / 2;
logo_->render(X, Y);
if (phase_ == Phase::SCAN) {
// Revelat CRT: la pròpia ScanReveal s'encarrega del blit
// fila a fila, de la banda lluminosa, dels glitches i del
// flash final.
scan_.render(*logo_, X, Y);
} else {
// MIDDLE i FADE_OUT: render normal, el logo ja està a
// pantalla complet i estable.
logo_->render(X, Y);
}
}
Notifier::get().render();
// Capa de fosa: durant FADE_IN i FADE_OUT pinta el negre semitransparent
// per damunt del logo i del Notifier (no del RenderInfo, que és overlay
// de debug i ha de mantenir-se llegible).
// Capa de fosa: només FADE_OUT pinta negre semitransparent (el
// FADE_IN s'ha substituït per `scan_`). Va per damunt del logo i
// del Notifier, però per sota de RenderInfo (overlay de debug).
fade_.render();
RenderInfo::get().render();
Screen::get().present();