#include "core/rendering/pixel_reveal.hpp" #include // Para min #include // Para iota #include // Para mt19937, shuffle #include "core/rendering/surface.hpp" // Para Surface #include "utils/utils.hpp" // Para PaletteColor // Constructor PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps) : cover_surface_(std::make_shared(width, height)), reveal_order_(height), row_step_(height, 0), width_(width), height_(height), pixels_per_second_(pixels_per_second), step_duration_(step_duration), num_steps_(num_steps) { // Rellena la máscara con negro sólido cover_surface_->clear(static_cast(PaletteColor::BLACK)); // Genera el orden aleatorio de columnas por fila usando la fila como semilla (reproducible) for (int r = 0; r < height_; r++) { reveal_order_[r].resize(width_); std::iota(reveal_order_[r].begin(), reveal_order_[r].end(), 0); std::mt19937 rng(static_cast(r)); std::shuffle(reveal_order_[r].begin(), reveal_order_[r].end(), rng); } } // Destructor PixelReveal::~PixelReveal() = default; // Actualiza el estado del revelado void PixelReveal::update(float time_active) { const auto TRANSPARENT = static_cast(PaletteColor::TRANSPARENT); for (int r = 0; r < height_; r++) { const float T_START = static_cast(r) / pixels_per_second_; const float TIME_IN_ROW = time_active - T_START; if (TIME_IN_ROW < 0.0F) { continue; // Esta fila aún no ha empezado } const int STEPS = std::min(num_steps_, static_cast(TIME_IN_ROW / step_duration_)); if (STEPS > row_step_[r]) { // Revela los píxeles de los pasos pendientes for (int step = row_step_[r]; step < STEPS; step++) { const int START_IDX = step * width_ / num_steps_; const int END_IDX = (step == num_steps_ - 1) ? width_ : (step + 1) * width_ / num_steps_; for (int idx = START_IDX; idx < END_IDX; idx++) { const int COL = reveal_order_[r][idx]; cover_surface_->putPixel(COL, r, TRANSPARENT); } } row_step_[r] = STEPS; } } } // Dibuja la máscara en la posición indicada void PixelReveal::render(int dst_x, int dst_y) const { cover_surface_->render(dst_x, dst_y); } // Indica si el revelado ha completado todas las filas bool PixelReveal::isComplete() const { for (const int step : row_step_) { if (step < num_steps_) { return false; } } return true; }