feat(logo): scanline reveal CRT amb glitch, bursts VHS i pulse de banda
This commit is contained in:
1 parent
243ced7498
commit
e32cff9dac
9 files changed
+440
-20
No files matched your search
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
|
||||
class Surface;
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Revelat tipus "scanline CRT" d'una Surface. Una banda lluminosa
|
||||
// baixa des de dalt cap a baix de la imatge: les files damunt de la
|
||||
// banda es renderitzen normalment (ja revelades), les files sota
|
||||
// queden invisibles, i a la banda mateixa s'aplica un overlay
|
||||
// blanc semi-transparent. Al voltant de la banda les files reben un
|
||||
// jitter horitzontal aleatori (falloff lineal amb la distància) i
|
||||
// damunt la part ja revelada apareixen ocasionalment "bursts VHS" —
|
||||
// franges horitzontals desplaçades durant uns ms — per a un toc
|
||||
// demoscene/VHS deteriorat.
|
||||
//
|
||||
// Quan la banda surt per sota del logo i s'esgota `duration_ms`,
|
||||
// dispara un flash blanc breu i passa a `isFinished()=true`. El
|
||||
// caller decideix què fa amb el control de fase a partir d'aquí.
|
||||
//
|
||||
// Ús:
|
||||
// ScanReveal sr;
|
||||
// sr.begin({.duration_ms = 1500, ...});
|
||||
// // cada frame:
|
||||
// sr.tick(delta_ms);
|
||||
// sr.render(*logo, x, y);
|
||||
// if (sr.isFinished()) { ... canvi de fase ... }
|
||||
class ScanReveal {
|
||||
public:
|
||||
struct Params {
|
||||
int duration_ms;
|
||||
int band_height_px;
|
||||
int band_alpha;
|
||||
float band_pulse_hz;
|
||||
float band_pulse_depth;
|
||||
int glitch_amplitude_px;
|
||||
int glitch_band_radius_px;
|
||||
int vhs_burst_per_sec;
|
||||
int vhs_burst_duration_ms;
|
||||
int vhs_burst_height_px;
|
||||
int vhs_burst_amplitude_px;
|
||||
int flash_ms;
|
||||
};
|
||||
|
||||
ScanReveal();
|
||||
|
||||
void begin(const Params& params);
|
||||
void tick(int delta_ms);
|
||||
|
||||
// Renderitza un frame del revelat sobre la Surface `src`. El
|
||||
// caller s'encarrega de pintar negre per sota (les files no
|
||||
// revelades simplement no es dibuixen — queda el que hi haja al
|
||||
// canvas, normalment negre).
|
||||
void render(const Surface& src, int x, int y) const;
|
||||
|
||||
[[nodiscard]] auto isActive() const -> bool;
|
||||
[[nodiscard]] auto isFinished() const -> bool;
|
||||
|
||||
private:
|
||||
Params params_{};
|
||||
int elapsed_ms_{0};
|
||||
// Flash post-scan: arranca quan el scan toca fons; decreix amb
|
||||
// `delta_ms` fins a 0. Mentre `flash_active_` és true encara no
|
||||
// hem reportat finished (donant marge per pintar el flash sencer).
|
||||
int flash_remaining_ms_{0};
|
||||
bool flash_started_{false};
|
||||
|
||||
// Burst VHS actiu (com a màxim un alhora — simplifica i ja és
|
||||
// suficient per al ritme visual). y_norm ∈ [0,1] es resol en
|
||||
// píxels al `render()` perquè aquí no coneixem l'alçada del logo.
|
||||
int burst_remaining_ms_{0};
|
||||
float burst_y_norm_{0.0F};
|
||||
int burst_dx_{0};
|
||||
|
||||
// RNG per als bursts. Seed des de random_device a `begin()`
|
||||
// perquè cada execució sigui visualment diferent.
|
||||
std::minstd_rand rng_;
|
||||
};
|
||||
|
||||
} // namespace Effects
|
||||
Reference in new issue
Block a user