570 lines
22 KiB
C++
570 lines
22 KiB
C++
// IWYU pragma: no_include <bits/std_abs.h>
|
|
#include "core/rendering/surface.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <algorithm> // Para min, max, copy_n, fill
|
|
#include <cmath> // Para abs
|
|
#include <cstdint> // Para uint32_t
|
|
#include <cstring> // Para memcpy, size_t
|
|
#include <fstream> // Para basic_ifstream, basic_ostream, basic_ist...
|
|
#include <iostream> // Para cerr
|
|
#include <memory> // Para shared_ptr, __shared_ptr_access, default...
|
|
#include <sstream> // Para basic_istringstream
|
|
#include <stdexcept> // Para runtime_error
|
|
#include <vector> // Para vector
|
|
|
|
#include "core/rendering/gif.hpp" // Para Gif
|
|
#include "core/rendering/screen.hpp" // Para Screen
|
|
#include "core/resources/resource_list.hpp" // Para Resource::List::get()->getPrintWidth
|
|
#include "core/resources/resource_helper.hpp" // Para ResourceHelper
|
|
#include "utils/utils.hpp" // Para printWithDots
|
|
|
|
// Carga una paleta desde un archivo .gif
|
|
auto loadPalette(const std::string& file_path) -> Palette {
|
|
// Load file using ResourceHelper (supports both filesystem and pack)
|
|
auto buffer = Resource::Helper::loadFile(file_path);
|
|
if (buffer.empty()) {
|
|
throw std::runtime_error("Error opening file: " + file_path);
|
|
}
|
|
|
|
// Cargar la paleta usando los datos del buffer
|
|
std::vector<uint32_t> pal = GIF::Gif::loadPalette(buffer.data());
|
|
if (pal.empty()) {
|
|
throw std::runtime_error("No palette found in GIF file: " + file_path);
|
|
}
|
|
|
|
// Crear la paleta y copiar los datos desde 'pal'
|
|
Palette palette = {}; // Inicializa la paleta con ceros
|
|
std::copy_n(pal.begin(), std::min(pal.size(), palette.size()), palette.begin());
|
|
|
|
// Mensaje de depuración
|
|
printWithDots("Palette : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]", Resource::List::get()->getPrintWidth());
|
|
|
|
return palette;
|
|
}
|
|
|
|
// Carga una paleta desde un archivo .pal
|
|
auto readPalFile(const std::string& file_path) -> Palette {
|
|
Palette palette{};
|
|
palette.fill(0); // Inicializar todo con 0 (transparente por defecto)
|
|
|
|
// Load file using ResourceHelper (supports both filesystem and pack)
|
|
auto file_data = Resource::Helper::loadFile(file_path);
|
|
if (file_data.empty()) {
|
|
throw std::runtime_error("No se pudo abrir el archivo .pal: " + file_path);
|
|
}
|
|
|
|
// Convert bytes to string for parsing
|
|
std::string content(file_data.begin(), file_data.end());
|
|
std::istringstream stream(content);
|
|
|
|
std::string line;
|
|
int line_number = 0;
|
|
int color_index = 0;
|
|
|
|
while (std::getline(stream, line)) {
|
|
++line_number;
|
|
|
|
// Ignorar las tres primeras líneas del archivo
|
|
if (line_number <= 3) {
|
|
continue;
|
|
}
|
|
|
|
// Procesar las líneas restantes con valores RGB
|
|
std::istringstream ss(line);
|
|
int r;
|
|
int g;
|
|
int b;
|
|
if (ss >> r >> g >> b) {
|
|
// Construir el color ARGB (A = 255 por defecto)
|
|
Uint32 color = (255 << 24) | (r << 16) | (g << 8) | b;
|
|
palette[color_index++] = color;
|
|
|
|
// Limitar a un máximo de 256 colores (opcional)
|
|
if (color_index >= 256) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
printWithDots("Palette : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]", Resource::List::get()->getPrintWidth());
|
|
return palette;
|
|
}
|
|
|
|
// Constructor
|
|
Surface::Surface(int w, int h)
|
|
: surface_data_(std::make_shared<SurfaceData>(w, h)),
|
|
transparent_color_(Color::index(Color::Cpc::CLEAR)) { initializeSubPalette(sub_palette_); }
|
|
|
|
Surface::Surface(const std::string& file_path)
|
|
: transparent_color_(Color::index(Color::Cpc::CLEAR)) {
|
|
SurfaceData loaded_data = loadSurface(file_path);
|
|
surface_data_ = std::make_shared<SurfaceData>(std::move(loaded_data));
|
|
|
|
initializeSubPalette(sub_palette_);
|
|
}
|
|
|
|
// Carga una superficie desde un archivo
|
|
auto Surface::loadSurface(const std::string& file_path) -> SurfaceData {
|
|
// Load file using ResourceHelper (supports both filesystem and pack)
|
|
std::vector<Uint8> buffer = Resource::Helper::loadFile(file_path);
|
|
if (buffer.empty()) {
|
|
std::cerr << "Error opening file: " << file_path << '\n';
|
|
throw std::runtime_error("Error opening file");
|
|
}
|
|
|
|
// Crear un objeto Gif y llamar a la función loadGif
|
|
Uint16 w = 0;
|
|
Uint16 h = 0;
|
|
std::vector<Uint8> raw_pixels = GIF::Gif::loadGif(buffer.data(), w, h);
|
|
if (raw_pixels.empty()) {
|
|
std::cerr << "Error loading GIF from file: " << file_path << '\n';
|
|
throw std::runtime_error("Error loading GIF");
|
|
}
|
|
|
|
// Si el constructor de Surface espera un std::shared_ptr<Uint8[]>,
|
|
// reservamos un bloque dinámico y copiamos los datos del vector.
|
|
size_t pixel_count = raw_pixels.size();
|
|
auto pixels = std::shared_ptr<Uint8[]>(new Uint8[pixel_count], std::default_delete<Uint8[]>());
|
|
std::memcpy(pixels.get(), raw_pixels.data(), pixel_count);
|
|
|
|
// Crear y devolver directamente el objeto SurfaceData
|
|
printWithDots("Surface : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]", Resource::List::get()->getPrintWidth());
|
|
return {static_cast<float>(w), static_cast<float>(h), pixels};
|
|
}
|
|
|
|
// Carga una paleta desde un archivo
|
|
void Surface::loadPalette(const std::string& file_path) {
|
|
palette_ = ::loadPalette(file_path);
|
|
}
|
|
|
|
// Carga una paleta desde otra paleta
|
|
void Surface::loadPalette(const Palette& palette) {
|
|
palette_ = palette;
|
|
}
|
|
|
|
// Establece un color en la paleta
|
|
void Surface::setColor(int index, Uint32 color) {
|
|
palette_.at(index) = color;
|
|
}
|
|
|
|
// Rellena la superficie con un color
|
|
void Surface::clear(Uint8 color) {
|
|
const size_t TOTAL_PIXELS = surface_data_->width * surface_data_->height;
|
|
Uint8* data_ptr = surface_data_->data.get();
|
|
std::fill(data_ptr, data_ptr + TOTAL_PIXELS, color);
|
|
}
|
|
|
|
// Pone un pixel en la SurfaceData
|
|
void Surface::putPixel(int x, int y, Uint8 color) {
|
|
if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) {
|
|
return; // Coordenadas fuera de rango
|
|
}
|
|
|
|
const int INDEX = x + (y * surface_data_->width);
|
|
surface_data_->data.get()[INDEX] = color;
|
|
}
|
|
|
|
// Obtiene el color de un pixel de la surface_data
|
|
auto Surface::getPixel(int x, int y) -> Uint8 { return surface_data_->data.get()[x + (y * static_cast<int>(surface_data_->width))]; }
|
|
|
|
// Dibuja un rectangulo relleno
|
|
void Surface::fillRect(const SDL_FRect* rect, Uint8 color) {
|
|
// Limitar los valores del rectángulo al tamaño de la superficie
|
|
float x_start = std::max(0.0F, rect->x);
|
|
float y_start = std::max(0.0F, rect->y);
|
|
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
|
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
|
|
|
// Recorrer cada píxel dentro del rectángulo directamente
|
|
for (int y = y_start; y < y_end; ++y) {
|
|
for (int x = x_start; x < x_end; ++x) {
|
|
const int INDEX = x + (y * surface_data_->width);
|
|
surface_data_->data.get()[INDEX] = color;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dibuja el borde de un rectangulo
|
|
void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) {
|
|
// Limitar los valores del rectángulo al tamaño de la superficie
|
|
float x_start = std::max(0.0F, rect->x);
|
|
float y_start = std::max(0.0F, rect->y);
|
|
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
|
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
|
|
|
// Dibujar bordes horizontales
|
|
for (int x = x_start; x < x_end; ++x) {
|
|
// Borde superior
|
|
const int TOP_INDEX = x + (y_start * surface_data_->width);
|
|
surface_data_->data.get()[TOP_INDEX] = color;
|
|
|
|
// Borde inferior
|
|
const int BOTTOM_INDEX = x + ((y_end - 1) * surface_data_->width);
|
|
surface_data_->data.get()[BOTTOM_INDEX] = color;
|
|
}
|
|
|
|
// Dibujar bordes verticales
|
|
for (int y = y_start; y < y_end; ++y) {
|
|
// Borde izquierdo
|
|
const int LEFT_INDEX = x_start + (y * surface_data_->width);
|
|
surface_data_->data.get()[LEFT_INDEX] = color;
|
|
|
|
// Borde derecho
|
|
const int RIGHT_INDEX = (x_end - 1) + (y * surface_data_->width);
|
|
surface_data_->data.get()[RIGHT_INDEX] = color;
|
|
}
|
|
}
|
|
|
|
// Dibuja una linea
|
|
void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) {
|
|
// Calcula las diferencias
|
|
float dx = std::abs(x2 - x1);
|
|
float dy = std::abs(y2 - y1);
|
|
|
|
// Determina la dirección del incremento
|
|
float sx = (x1 < x2) ? 1 : -1;
|
|
float sy = (y1 < y2) ? 1 : -1;
|
|
|
|
float err = dx - dy;
|
|
|
|
while (true) {
|
|
// Asegúrate de no dibujar fuera de los límites de la superficie
|
|
if (x1 >= 0 && x1 < surface_data_->width && y1 >= 0 && y1 < surface_data_->height) {
|
|
surface_data_->data.get()[static_cast<size_t>(x1 + (y1 * surface_data_->width))] = color;
|
|
}
|
|
|
|
// Si alcanzamos el punto final, salimos
|
|
if (x1 == x2 && y1 == y2) {
|
|
break;
|
|
}
|
|
|
|
int e2 = 2 * err;
|
|
if (e2 > -dy) {
|
|
err -= dy;
|
|
x1 += sx;
|
|
}
|
|
if (e2 < dx) {
|
|
err += dx;
|
|
y1 += sy;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
|
|
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
|
|
|
// Limitar la región para evitar accesos fuera de rango en origen
|
|
w = std::min(w, surface_data_->width - sx);
|
|
h = std::min(h, surface_data_->height - sy);
|
|
|
|
// Limitar la región para evitar accesos fuera de rango en destino
|
|
w = std::min(w, surface_data->width - dx);
|
|
h = std::min(h, surface_data->height - dy);
|
|
|
|
for (int iy = 0; iy < h; ++iy) {
|
|
for (int ix = 0; ix < w; ++ix) {
|
|
// Verificar que las coordenadas de destino están dentro de los límites
|
|
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width) {
|
|
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height) {
|
|
int src_x = sx + ix;
|
|
int src_y = sy + iy;
|
|
|
|
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
|
if (color != transparent_color_) {
|
|
surface_data->data.get()[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) {
|
|
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
|
|
|
|
// Determina la región de origen (clip) a renderizar
|
|
float sx = ((src_rect) != nullptr) ? src_rect->x : 0;
|
|
float sy = ((src_rect) != nullptr) ? src_rect->y : 0;
|
|
float w = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width;
|
|
float h = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height;
|
|
|
|
// Limitar la región para evitar accesos fuera de rango en origen
|
|
w = std::min(w, surface_data_->width - sx);
|
|
h = std::min(h, surface_data_->height - sy);
|
|
w = std::min(w, surface_data_dest->width - x);
|
|
h = std::min(h, surface_data_dest->height - y);
|
|
|
|
// Limitar la región para evitar accesos fuera de rango en destino
|
|
w = std::min(w, surface_data_dest->width - x);
|
|
h = std::min(h, surface_data_dest->height - y);
|
|
|
|
// Renderiza píxel por píxel aplicando el flip si es necesario
|
|
for (int iy = 0; iy < h; ++iy) {
|
|
for (int ix = 0; ix < w; ++ix) {
|
|
// Coordenadas de origen
|
|
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
|
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
|
|
|
// Coordenadas de destino
|
|
int dest_x = x + ix;
|
|
int dest_y = y + iy;
|
|
|
|
// Verificar que las coordenadas de destino están dentro de los límites
|
|
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
|
|
// Copia el píxel si no es transparente
|
|
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
|
if (color != transparent_color_) {
|
|
surface_data_dest->data[dest_x + (dest_y * surface_data_dest->width)] = sub_palette_[color];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper para calcular coordenadas con flip
|
|
void Surface::calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y) {
|
|
src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
|
src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
|
}
|
|
|
|
// Helper para copiar un pixel si no es transparente
|
|
void Surface::copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const {
|
|
if (dest_x < 0 || dest_y < 0) {
|
|
return;
|
|
}
|
|
|
|
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
|
if (color != transparent_color_) {
|
|
dest_data[dest_x + (dest_y * dest_width)] = sub_palette_[color];
|
|
}
|
|
}
|
|
|
|
// Copia una región de la superficie de origen a la de destino
|
|
void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip) {
|
|
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
|
|
|
// Si srcRect es nullptr, tomar toda la superficie fuente
|
|
float sx = ((src_rect) != nullptr) ? src_rect->x : 0;
|
|
float sy = ((src_rect) != nullptr) ? src_rect->y : 0;
|
|
float sw = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width;
|
|
float sh = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height;
|
|
|
|
// Si dstRect es nullptr, asignar las mismas dimensiones que srcRect
|
|
float dx = ((dst_rect) != nullptr) ? dst_rect->x : 0;
|
|
float dy = ((dst_rect) != nullptr) ? dst_rect->y : 0;
|
|
float dw = ((dst_rect) != nullptr) ? dst_rect->w : sw;
|
|
float dh = ((dst_rect) != nullptr) ? dst_rect->h : sh;
|
|
|
|
// Asegurarse de que srcRect y dstRect tienen las mismas dimensiones
|
|
if (sw != dw || sh != dh) {
|
|
dw = sw; // Respetar las dimensiones de srcRect
|
|
dh = sh;
|
|
}
|
|
|
|
// Limitar la región para evitar accesos fuera de rango en src y dst
|
|
sw = std::min(sw, surface_data_->width - sx);
|
|
sh = std::min(sh, surface_data_->height - sy);
|
|
dw = std::min(dw, surface_data->width - dx);
|
|
dh = std::min(dh, surface_data->height - dy);
|
|
|
|
int final_width = std::min(sw, dw);
|
|
int final_height = std::min(sh, dh);
|
|
|
|
// Renderiza píxel por píxel aplicando el flip si es necesario
|
|
for (int iy = 0; iy < final_height; ++iy) {
|
|
for (int ix = 0; ix < final_width; ++ix) {
|
|
int src_x = 0;
|
|
int src_y = 0;
|
|
calculateFlippedCoords(ix, iy, sx, sy, final_width, final_height, flip, src_x, src_y);
|
|
|
|
int dest_x = dx + ix;
|
|
int dest_y = dy + iy;
|
|
|
|
// Verificar límites de destino antes de copiar
|
|
if (dest_x >= 0 && dest_x < surface_data->width && dest_y >= 0 && dest_y < surface_data->height) {
|
|
copyPixelIfNotTransparent(surface_data->data.get(), dest_x, dest_y, surface_data->width, src_x, src_y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
|
void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect, SDL_FlipMode flip) {
|
|
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
|
|
|
// Determina la región de origen (clip) a renderizar
|
|
float sx = ((src_rect) != nullptr) ? src_rect->x : 0;
|
|
float sy = ((src_rect) != nullptr) ? src_rect->y : 0;
|
|
float w = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width;
|
|
float h = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height;
|
|
|
|
// Limitar la región para evitar accesos fuera de rango
|
|
w = std::min(w, surface_data_->width - sx);
|
|
h = std::min(h, surface_data_->height - sy);
|
|
|
|
// Renderiza píxel por píxel aplicando el flip si es necesario
|
|
for (int iy = 0; iy < h; ++iy) {
|
|
for (int ix = 0; ix < w; ++ix) {
|
|
// Coordenadas de origen
|
|
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
|
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
|
|
|
// Coordenadas de destino
|
|
int dest_x = x + ix;
|
|
int dest_y = y + iy;
|
|
|
|
// Verifica que las coordenadas de destino estén dentro de los límites
|
|
if (dest_x < 0 || dest_y < 0 || dest_x >= surface_data->width || dest_y >= surface_data->height) {
|
|
continue; // Saltar píxeles fuera del rango del destino
|
|
}
|
|
|
|
// Copia el píxel si no es transparente
|
|
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
|
if (color != transparent_color_) {
|
|
surface_data->data[dest_x + (dest_y * surface_data->width)] =
|
|
(color == source_color) ? target_color : color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Vuelca la superficie a una textura
|
|
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
|
|
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
|
|
throw std::runtime_error("Renderer or texture is null.");
|
|
}
|
|
|
|
if (surface_data_->width <= 0 || surface_data_->height <= 0 || (surface_data_->data == nullptr)) {
|
|
throw std::runtime_error("Invalid surface dimensions or data.");
|
|
}
|
|
|
|
Uint32* pixels = nullptr;
|
|
int pitch = 0;
|
|
|
|
// Bloquea la textura para modificar los píxeles directamente
|
|
if (!SDL_LockTexture(texture, nullptr, reinterpret_cast<void**>(&pixels), &pitch)) {
|
|
throw std::runtime_error("Failed to lock texture: " + std::string(SDL_GetError()));
|
|
}
|
|
|
|
// Convertir `pitch` de bytes a Uint32 (asegurando alineación correcta en hardware)
|
|
int row_stride = pitch / sizeof(Uint32);
|
|
|
|
for (int y = 0; y < surface_data_->height; ++y) {
|
|
for (int x = 0; x < surface_data_->width; ++x) {
|
|
// Calcular la posición correcta en la textura teniendo en cuenta el stride
|
|
int texture_index = (y * row_stride) + x;
|
|
int surface_index = (y * surface_data_->width) + x;
|
|
|
|
pixels[texture_index] = palette_[surface_data_->data.get()[surface_index]];
|
|
}
|
|
}
|
|
|
|
SDL_UnlockTexture(texture); // Desbloquea la textura
|
|
|
|
// Renderiza la textura en la pantalla completa
|
|
if (!SDL_RenderTexture(renderer, texture, nullptr, nullptr)) {
|
|
throw std::runtime_error("Failed to copy texture to renderer: " + std::string(SDL_GetError()));
|
|
}
|
|
}
|
|
|
|
// Vuelca la superficie a una textura
|
|
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect) {
|
|
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
|
|
throw std::runtime_error("Renderer or texture is null.");
|
|
}
|
|
|
|
if (surface_data_->width <= 0 || surface_data_->height <= 0 || (surface_data_->data == nullptr)) {
|
|
throw std::runtime_error("Invalid surface dimensions or data.");
|
|
}
|
|
|
|
Uint32* pixels = nullptr;
|
|
int pitch = 0;
|
|
|
|
SDL_Rect lock_rect;
|
|
if (dest_rect != nullptr) {
|
|
lock_rect.x = static_cast<int>(dest_rect->x);
|
|
lock_rect.y = static_cast<int>(dest_rect->y);
|
|
lock_rect.w = static_cast<int>(dest_rect->w);
|
|
lock_rect.h = static_cast<int>(dest_rect->h);
|
|
}
|
|
|
|
// Usa lockRect solo si destRect no es nulo
|
|
if (!SDL_LockTexture(texture, (dest_rect != nullptr) ? &lock_rect : nullptr, reinterpret_cast<void**>(&pixels), &pitch)) {
|
|
throw std::runtime_error("Failed to lock texture: " + std::string(SDL_GetError()));
|
|
}
|
|
|
|
int row_stride = pitch / sizeof(Uint32);
|
|
|
|
for (int y = 0; y < surface_data_->height; ++y) {
|
|
for (int x = 0; x < surface_data_->width; ++x) {
|
|
int texture_index = (y * row_stride) + x;
|
|
int surface_index = (y * surface_data_->width) + x;
|
|
|
|
pixels[texture_index] = palette_[surface_data_->data.get()[surface_index]];
|
|
}
|
|
}
|
|
|
|
SDL_UnlockTexture(texture);
|
|
|
|
// Renderiza la textura con los rectángulos especificados
|
|
if (!SDL_RenderTexture(renderer, texture, src_rect, dest_rect)) {
|
|
throw std::runtime_error("Failed to copy texture to renderer: " + std::string(SDL_GetError()));
|
|
}
|
|
}
|
|
|
|
// Realiza un efecto de fundido en la paleta principal
|
|
auto Surface::fadePalette() -> bool {
|
|
// Verificar que el tamaño mínimo de palette_ sea adecuado
|
|
static constexpr int PALETTE_SIZE = 19;
|
|
if (sizeof(palette_) / sizeof(palette_[0]) < PALETTE_SIZE) {
|
|
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
|
|
}
|
|
|
|
// Desplazar colores (pares e impares)
|
|
for (int i = 18; i > 1; --i) {
|
|
palette_[i] = palette_[i - 2];
|
|
}
|
|
|
|
// Ajustar el primer color
|
|
palette_[1] = palette_[0];
|
|
|
|
// Devolver si el índice 15 coincide con el índice 0
|
|
return palette_[15] == palette_[0];
|
|
}
|
|
|
|
// Realiza un efecto de fundido en la paleta secundaria
|
|
auto Surface::fadeSubPalette(Uint32 delay) -> bool {
|
|
// Variable estática para almacenar el último tick
|
|
static Uint32 last_tick_ = 0;
|
|
|
|
// Obtener el tiempo actual
|
|
Uint32 current_tick = SDL_GetTicks();
|
|
|
|
// Verificar si ha pasado el tiempo de retardo
|
|
if (current_tick - last_tick_ < delay) {
|
|
return false; // No se realiza el fade
|
|
}
|
|
|
|
// Actualizar el último tick
|
|
last_tick_ = current_tick;
|
|
|
|
// Verificar que el tamaño mínimo de sub_palette_ sea adecuado
|
|
static constexpr int SUB_PALETTE_SIZE = 19;
|
|
if (sizeof(sub_palette_) / sizeof(sub_palette_[0]) < SUB_PALETTE_SIZE) {
|
|
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
|
|
}
|
|
|
|
// Desplazar colores (pares e impares)
|
|
for (int i = 18; i > 1; --i) {
|
|
sub_palette_[i] = sub_palette_[i - 2];
|
|
}
|
|
|
|
// Ajustar el primer color
|
|
sub_palette_[1] = sub_palette_[0];
|
|
|
|
// Devolver si el índice 15 coincide con el índice 0
|
|
return sub_palette_[15] == sub_palette_[0];
|
|
}
|