Files
logo_02/source/surface.h
2025-04-08 08:23:18 +02:00

171 lines
6.3 KiB
C++

#pragma once
#include <SDL3/SDL_rect.h> // for SDL_Rect, SDL_FRect
#include <SDL3/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL3/SDL_stdinc.h> // for Uint8, Uint16, Uint32
#include <SDL3/SDL_surface.h> // for SDL_FlipMode
#include <array> // for array
#include <memory> // for default_delete, shared_ptr, __shared_p...
#include <numeric> // for iota
#include <stdexcept> // for invalid_argument
#include <string> // for string
#include <utility> // for move
// Alias
using Palette = std::array<Uint32, 256>;
using SubPalette = std::array<Uint8, 256>;
// Carga una paleta desde un archivo .gif
Palette loadPalette(const std::string &file_path);
// Carga una paleta desde un archivo .pal
Palette readPalFile(const std::string &file_path);
struct SurfaceData
{
std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática
Uint16 width; // Ancho de la imagen
Uint16 height; // Alto de la imagen
// Constructor por defecto
SurfaceData() : data(nullptr), width(0), height(0) {}
// Constructor que inicializa dimensiones y asigna memoria
SurfaceData(Uint16 w, Uint16 h)
: data(std::shared_ptr<Uint8[]>(new Uint8[w * h](), std::default_delete<Uint8[]>())), width(w), height(h) {}
// Constructor para inicializar directamente con datos
SurfaceData(Uint16 w, Uint16 h, std::shared_ptr<Uint8[]> pixels)
: data(std::move(pixels)), width(w), height(h) {}
// Constructor de movimiento
SurfaceData(SurfaceData &&other) noexcept = default;
// Operador de movimiento
SurfaceData &operator=(SurfaceData &&other) noexcept = default;
// Evita copias accidentales
SurfaceData(const SurfaceData &) = delete;
SurfaceData &operator=(const SurfaceData &) = delete;
// Escala la superficie por un factor entero
void scale(int factor)
{
if (factor <= 1)
{
throw std::invalid_argument("El factor debe ser mayor a 1.");
}
// Calcular nuevas dimensiones
Uint16 newWidth = width * factor;
Uint16 newHeight = height * factor;
// Crear un nuevo buffer para los datos redimensionados
auto newData = std::shared_ptr<Uint8[]>(new Uint8[newWidth * newHeight](), std::default_delete<Uint8[]>());
// Rellenar los datos del nuevo buffer replicando los píxeles
for (Uint16 y = 0; y < height; ++y)
{
for (Uint16 x = 0; x < width; ++x)
{
Uint8 value = data[y * width + x]; // Obtener el valor del píxel original
// Copiar el píxel a la región escalada
for (int dy = 0; dy < factor; ++dy)
{
for (int dx = 0; dx < factor; ++dx)
{
newData[(y * factor + dy) * newWidth + (x * factor + dx)] = value;
}
}
}
}
// Actualizar los datos de la superficie
data = std::move(newData);
width = newWidth;
height = newHeight;
}
};
class Surface
{
private:
std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar
Palette palette_; // Paleta para volcar la SurfaceData a una Textura
SubPalette sub_palette_; // Paleta para reindexar colores
int transparent_color_; // Indice de la paleta que se omite en la copia de datos
public:
// Constructor
Surface(int w, int h);
explicit Surface(const std::string &file_path);
// Destructor
~Surface() = default;
// Carga una SurfaceData desde un archivo
SurfaceData loadSurface(const std::string &file_path);
// Carga una paleta desde un archivo
void loadPalette(const std::string &file_path);
void loadPalette(Palette palette);
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
void render(int dx, int dy, int sx, int sy, int w, int h);
void render(int x, int y, SDL_Rect *clip = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
void render(SDL_Rect *srcRect = nullptr, SDL_Rect *dstRect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_Rect *srcRect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
// Establece un color en la paleta
void setColor(int index, Uint32 color);
// Rellena la SurfaceData con un color
void clear(Uint8 color);
// Vuelca la SurfaceData a una textura
void copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture);
void copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_FRect *srcRect, SDL_FRect *destRect);
// Realiza un efecto de fundido en las paletas
bool fadePalette();
bool fadeSubPalette(Uint32 delay = 0);
// Pone un pixel en la SurfaceData
void putPixel(int x, int y, Uint8 color);
// Obtiene el color de un pixel de la surface_data
Uint8 getPixel(int x, int y);
// Dibuja un rectangulo relleno
void fillRect(const SDL_Rect *rect, Uint8 color);
// Dibuja el borde de un rectangulo
void drawRectBorder(const SDL_Rect *rect, Uint8 color);
// Dibuja una linea
void drawLine(int x1, int y1, int x2, int y2, Uint8 color);
// Metodos para gestionar surface_data_
std::shared_ptr<SurfaceData> getSurfaceData() const { return surface_data_; }
void setSurfaceData(std::shared_ptr<SurfaceData> new_data) { surface_data_ = new_data; }
// Obtien ancho y alto
int getWidth() const { return surface_data_->width; }
int getHeight() const { return surface_data_->height; }
// Color transparente
Uint8 getTransparentColor() const { return transparent_color_; }
void setTransparentColor(Uint8 color = 255) { transparent_color_ = color; }
// Paleta
void setPalette(const std::array<Uint32, 256> &palette) { palette_ = palette; }
// Inicializa la sub paleta
void initializeSubPalette(SubPalette &palette) { std::iota(palette.begin(), palette.end(), 0); }
// Escala el tamaño de la Surface
void scale(int factor) { surface_data_->scale(factor); }
};