#include "core/rendering/sprites/dissolve_sprite.hpp" #include // Para min #include // Para uint32_t #include "core/rendering/surface.hpp" // Para Surface // Hash 2D estable per a dithering (rank aleatori per posició de píxel) static auto pixelRank(int col, int row) -> float { auto h = (static_cast(col) * 2246822519U) ^ (static_cast(row) * 2654435761U); h ^= (h >> 13); h *= 1274126177U; h ^= (h >> 16); return static_cast(h & 0xFFFFU) / 65536.0F; } // Rang per a un píxel tenint en compte direcció (70% direccional + 30% aleatori) auto DissolveSprite::computePixelRank(int col, int row, int frame_h, DissolveDirection dir) -> float { const float RANDOM = pixelRank(col, row); if (dir == DissolveDirection::NONE || frame_h <= 0) { return RANDOM; } float y_factor = 0.0F; if (dir == DissolveDirection::DOWN) { y_factor = static_cast(row) / static_cast(frame_h); } else { y_factor = static_cast(frame_h - 1 - row) / static_cast(frame_h); } return (y_factor * 0.7F) + (RANDOM * 0.3F); } // Constructor per a surface directa (sense AnimationResource) DissolveSprite::DissolveSprite(std::shared_ptr surface, SDL_FRect pos) : AnimatedSprite(std::move(surface), pos) { if (surface_) { const int W = static_cast(surface_->getWidth()); const int H = static_cast(surface_->getHeight()); surface_display_ = std::make_shared(W, H); surface_display_->setTransparentColor(surface_->getTransparentColor()); surface_display_->clear(surface_->getTransparentColor()); } } // Constructor DissolveSprite::DissolveSprite(const AnimationResource& data) : AnimatedSprite(data) { if (surface_) { const int W = static_cast(surface_->getWidth()); const int H = static_cast(surface_->getHeight()); surface_display_ = std::make_shared(W, H); surface_display_->setTransparentColor(surface_->getTransparentColor()); // Inicialitza tots els píxels com a transparents surface_display_->clear(surface_->getTransparentColor()); } } // Reconstrueix la surface_display_ filtrant píxels per progress_ void DissolveSprite::rebuildDisplaySurface() { if (!surface_ || !surface_display_) { return; } const SDL_FRect CLIP = clip_; const int SX = static_cast(CLIP.x); const int SY = static_cast(CLIP.y); const int SW = static_cast(CLIP.w); const int SH = static_cast(CLIP.h); if (SW <= 0 || SH <= 0) { return; } auto src_data = surface_->getSurfaceData(); auto dst_data = surface_display_->getSurfaceData(); const int SRC_W = static_cast(src_data->width); const int DST_W = static_cast(dst_data->width); const Uint8 TRANSPARENT = surface_->getTransparentColor(); // Esborra frame anterior si ha canviat if (prev_clip_.w > 0 && prev_clip_.h > 0 && (prev_clip_.x != CLIP.x || prev_clip_.y != CLIP.y || prev_clip_.w != CLIP.w || prev_clip_.h != CLIP.h)) { surface_display_->fillRect(&prev_clip_, TRANSPARENT); } // Esborra la zona del frame actual (reconstrucció neta) surface_display_->fillRect(&CLIP, TRANSPARENT); // Copia píxels filtrats per progress_ for (int row = 0; row < SH; ++row) { for (int col = 0; col < SW; ++col) { const Uint8 COLOR = src_data->data[((SY + row) * SRC_W) + (SX + col)]; if (COLOR == TRANSPARENT) { continue; } const float RANK = computePixelRank(col, row, SH, direction_); if (RANK >= progress_) { const Uint8 OUT = (COLOR == source_color_) ? target_color_ : COLOR; dst_data->data[((SY + row) * DST_W) + (SX + col)] = OUT; } } } prev_clip_ = CLIP; needs_rebuild_ = false; } // Actualitza animació, moviment i transició temporal void DissolveSprite::update(float delta_time) { const SDL_FRect OLD_CLIP = clip_; AnimatedSprite::update(delta_time); // Detecta canvi de frame d'animació if (clip_.x != OLD_CLIP.x || clip_.y != OLD_CLIP.y || clip_.w != OLD_CLIP.w || clip_.h != OLD_CLIP.h) { needs_rebuild_ = true; } // Actualitza transició temporal si activa if (transition_mode_ != TransitionMode::NONE) { transition_elapsed_ += delta_time * 1000.0F; const float T = std::min(transition_elapsed_ / transition_duration_, 1.0F); progress_ = (transition_mode_ == TransitionMode::DISSOLVING) ? T : (1.0F - T); needs_rebuild_ = true; if (T >= 1.0F) { transition_mode_ = TransitionMode::NONE; } } if (needs_rebuild_) { rebuildDisplaySurface(); } } // Renderitza: usa surface_display_ (amb color replace) si disponible void DissolveSprite::render() { if (!surface_display_) { AnimatedSprite::render(); return; } surface_display_->render(static_cast(pos_.x), static_cast(pos_.y), &clip_, flip_); } // Estableix el progrés manualment void DissolveSprite::setProgress(float progress) { progress_ = std::min(std::max(progress, 0.0F), 1.0F); needs_rebuild_ = true; } // Inicia dissolució temporal (visible → invisible) void DissolveSprite::startDissolve(float duration_ms, DissolveDirection dir) { direction_ = dir; transition_mode_ = TransitionMode::DISSOLVING; transition_duration_ = duration_ms; transition_elapsed_ = 0.0F; progress_ = 0.0F; needs_rebuild_ = true; } // Inicia generació temporal (invisible → visible) void DissolveSprite::startGenerate(float duration_ms, DissolveDirection dir) { direction_ = dir; transition_mode_ = TransitionMode::GENERATING; transition_duration_ = duration_ms; transition_elapsed_ = 0.0F; progress_ = 1.0F; needs_rebuild_ = true; } // Atura la transició temporal void DissolveSprite::stopTransition() { transition_mode_ = TransitionMode::NONE; } // Retorna si la transició ha acabat auto DissolveSprite::isTransitionDone() const -> bool { return transition_mode_ == TransitionMode::NONE; } // Configura substitució de color per a la reconstrucció void DissolveSprite::setColorReplace(Uint8 source, Uint8 target) { source_color_ = source; target_color_ = target; needs_rebuild_ = true; }