72 lines
2.7 KiB
C++
72 lines
2.7 KiB
C++
#include "core/rendering/transitions/mosaic.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
|
|
#include "core/rendering/screen.hpp"
|
|
|
|
namespace Transitions {
|
|
|
|
Mosaic::Mosaic(Params params)
|
|
: params_(params) {}
|
|
|
|
void Mosaic::begin(int duration_ms) {
|
|
duration_ms_ = duration_ms;
|
|
elapsed_ms_ = 0;
|
|
}
|
|
|
|
void Mosaic::tick(int delta_ms) {
|
|
if (duration_ms_ <= 0) { return; }
|
|
elapsed_ms_ = std::min(elapsed_ms_ + delta_ms, duration_ms_);
|
|
}
|
|
|
|
auto Mosaic::progress() const -> float {
|
|
if (duration_ms_ <= 0) { return 0.0F; }
|
|
return std::clamp(static_cast<float>(elapsed_ms_) / static_cast<float>(duration_ms_), 0.0F, 1.0F);
|
|
}
|
|
|
|
void Mosaic::render() const {
|
|
if (duration_ms_ <= 0) { return; }
|
|
const float P = progress();
|
|
const int MAX_BLOCK = std::max(1, params_.max_block_size);
|
|
// Blocs de mida creixent al llarg del fade. A p=0 → 1 px (sense
|
|
// efecte visible); a p=1 → max_block. Es fa cap-amunt amb ceil
|
|
// perquè el primer increment arribi aviat (el salt visual de
|
|
// 1→2 ja es nota).
|
|
const int BLOCK = std::clamp(static_cast<int>(std::ceil(static_cast<float>(MAX_BLOCK) * P)), 1, MAX_BLOCK);
|
|
|
|
auto& screen = Screen::get();
|
|
std::uint32_t* canvas = screen.getCanvasArgb();
|
|
const int W = screen.getCanvasWidth();
|
|
const int H = screen.getCanvasHeight();
|
|
|
|
if (BLOCK > 1) {
|
|
// Sample-and-fill in-place. Per a cada bloc, mostregem el
|
|
// píxel central (les vores poden caure fora del canvas en
|
|
// blocs de la última columna/fila → clamp).
|
|
for (int by = 0; by < H; by += BLOCK) {
|
|
const int Y_END = std::min(by + BLOCK, H);
|
|
const int SY = std::min(by + (BLOCK / 2), H - 1);
|
|
for (int bx = 0; bx < W; bx += BLOCK) {
|
|
const int X_END = std::min(bx + BLOCK, W);
|
|
const int SX = std::min(bx + (BLOCK / 2), W - 1);
|
|
const std::uint32_t COLOR = canvas[(SY * W) + SX];
|
|
for (int yy = by; yy < Y_END; ++yy) {
|
|
std::uint32_t* row = canvas + (static_cast<std::ptrdiff_t>(yy) * W);
|
|
std::fill(row + bx, row + X_END, COLOR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fade-to-black quadràtic per damunt: la mascara fosca arriba
|
|
// tard (a p=0.5 només 25% d'alpha) perquè es vegin els blocs.
|
|
const auto ALPHA = static_cast<std::uint8_t>(std::round(255.0F * P * P));
|
|
if (ALPHA > 0) {
|
|
screen.blendRect(0, 0, W, H, 0x00000000U, ALPHA);
|
|
}
|
|
}
|
|
|
|
} // namespace Transitions
|