Files

49 lines
1.8 KiB
C++

#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