esqueleto nivel 1
This commit is contained in:
188
source/core/rendering/sprites/dissolve_sprite.cpp
Normal file
188
source/core/rendering/sprites/dissolve_sprite.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "core/rendering/sprites/dissolve_sprite.hpp"
|
||||
|
||||
#include <algorithm> // Para min
|
||||
#include <cstdint> // 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<uint32_t>(col) * 2246822519U) ^ (static_cast<uint32_t>(row) * 2654435761U);
|
||||
h ^= (h >> 13);
|
||||
h *= 1274126177U;
|
||||
h ^= (h >> 16);
|
||||
return static_cast<float>(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<float>(row) / static_cast<float>(frame_h);
|
||||
} else {
|
||||
y_factor = static_cast<float>(frame_h - 1 - row) / static_cast<float>(frame_h);
|
||||
}
|
||||
|
||||
return (y_factor * 0.7F) + (RANDOM * 0.3F);
|
||||
}
|
||||
|
||||
// Constructor per a surface directa (sense AnimationResource)
|
||||
DissolveSprite::DissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
|
||||
: AnimatedSprite(std::move(surface), pos) {
|
||||
if (surface_) {
|
||||
const int W = static_cast<int>(surface_->getWidth());
|
||||
const int H = static_cast<int>(surface_->getHeight());
|
||||
surface_display_ = std::make_shared<Surface>(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<int>(surface_->getWidth());
|
||||
const int H = static_cast<int>(surface_->getHeight());
|
||||
surface_display_ = std::make_shared<Surface>(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<int>(CLIP.x);
|
||||
const int SY = static_cast<int>(CLIP.y);
|
||||
const int SW = static_cast<int>(CLIP.w);
|
||||
const int SH = static_cast<int>(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<int>(src_data->width);
|
||||
const int DST_W = static_cast<int>(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<int>(pos_.x), static_cast<int>(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;
|
||||
}
|
||||
Reference in New Issue
Block a user