feat(effects): heat-haze sinusoidal al fons del títol (configurable a ui.yaml)
This commit is contained in:
1 parent
9233bd8d75
commit
1fc3ab8e31
9 files changed
+150
-3
No files matched your search
@@ -0,0 +1,48 @@
|
||||
#include "core/rendering/effects/heat_haze.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
#include "core/rendering/surface.hpp"
|
||||
|
||||
namespace Effects {
|
||||
|
||||
namespace {
|
||||
constexpr float TWO_PI = 2.0F * std::numbers::pi_v<float>;
|
||||
}
|
||||
|
||||
HeatHaze::HeatHaze(Params params)
|
||||
: params_(params) {}
|
||||
|
||||
void HeatHaze::tick(int delta_ms) {
|
||||
const float DT = static_cast<float>(delta_ms) / 1000.0F;
|
||||
phase_ = std::fmod(phase_ + (TWO_PI * params_.speed_hz * DT), TWO_PI);
|
||||
}
|
||||
|
||||
void HeatHaze::render(const Surface& src, int x, int y) const {
|
||||
// Pas 1 — blit pla de tota la Surface al destí. És la base que
|
||||
// tapa els marges que les files desplaçades deixarien al
|
||||
// descobert, evitant haver de demanar al caller un pre-fill. Per
|
||||
// a fons amb gradient continu (cels, sorres) la costura amb el
|
||||
// pas 2 no es nota; per a fons d'alt contrast cal moderar
|
||||
// l'amplitud.
|
||||
src.render(x, y);
|
||||
|
||||
// Pas 2 — re-blit fila a fila amb desplaçament horitzontal sin.
|
||||
// Wavelength <=0 dóna divisió absurda: cau a 1 px com a salvaguarda;
|
||||
// a la pràctica el caller passa un valor >0 vingut d'ui.yaml.
|
||||
const float WL = (params_.wavelength_px > 0.0F) ? params_.wavelength_px : 1.0F;
|
||||
const int H = src.getHeight();
|
||||
const auto W = static_cast<float>(src.getWidth());
|
||||
for (int row = 0; row < H; ++row) {
|
||||
const float ARG = (TWO_PI * static_cast<float>(row) / WL) + phase_;
|
||||
const int DX = static_cast<int>(std::lround(params_.amplitude_px * std::sin(ARG)));
|
||||
if (DX == 0) { continue; } // El pas 1 ja ha pintat aquesta fila on toca.
|
||||
SDL_FRect row_rect{0.0F, static_cast<float>(row), W, 1.0F};
|
||||
src.render(x + DX, y + row, &row_rect);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Effects
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
class Surface;
|
||||
|
||||
namespace Effects {
|
||||
|
||||
// Distorsió sinusoidal horitzontal de cada fila: dx(y) =
|
||||
// amplitude · sin(2π·y/wavelength + phase). La phase avança al
|
||||
// ritme marcat per `speed_hz` (cicles per segon). Es pinta sobre
|
||||
// qualsevol Surface — habitualment un fons de canvas — i manté el
|
||||
// seu propi estat temporal, així dues instàncies poden tenir
|
||||
// paràmetres i fases independents.
|
||||
//
|
||||
// `render()` fa dos passos: primer un blit pla de tota la Surface
|
||||
// (perquè els marges no quedin descoberts pel desplaçament) i
|
||||
// després el re-blit fila a fila amb el sin. La costura és
|
||||
// invisible en fons amb gradient continu i pràcticament invisible
|
||||
// en altres si l'amplitud és moderada.
|
||||
class HeatHaze {
|
||||
public:
|
||||
struct Params {
|
||||
float amplitude_px;
|
||||
float wavelength_px;
|
||||
float speed_hz;
|
||||
};
|
||||
|
||||
explicit HeatHaze(Params params);
|
||||
|
||||
void tick(int delta_ms);
|
||||
void render(const Surface& src, int x, int y) const;
|
||||
|
||||
private:
|
||||
Params params_;
|
||||
float phase_{0.0F};
|
||||
};
|
||||
|
||||
} // namespace Effects
|
||||
Reference in new issue
Block a user