optimitzacions en Surface

This commit is contained in:
2026-04-18 12:40:13 +02:00
parent f5b6bc3ef9
commit 412df1316f
6 changed files with 105 additions and 167 deletions

View File

@@ -134,7 +134,7 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: MovingSprite(std::move(surface), pos) { : MovingSprite(std::move(surface), pos) {
// animations_ queda buit (protegit per el guard de animate()) // animations_ queda buit (protegit per el guard de animate())
if (surface_) { if (surface_) {
clip_ = {.x = 0, .y = 0, .w = surface_->getWidth(), .h = surface_->getHeight()}; clip_ = {.x = 0, .y = 0, .w = static_cast<float>(surface_->getWidth()), .h = static_cast<float>(surface_->getHeight())};
} }
} }

View File

@@ -19,7 +19,7 @@ Sprite::Sprite() = default;
Sprite::Sprite(std::shared_ptr<Surface> surface) Sprite::Sprite(std::shared_ptr<Surface> surface)
: surface_(std::move(surface)), : surface_(std::move(surface)),
pos_{0.0F, 0.0F, surface_->getWidth(), surface_->getHeight()}, pos_{0.0F, 0.0F, static_cast<float>(surface_->getWidth()), static_cast<float>(surface_->getHeight())},
clip_(pos_) {} clip_(pos_) {}
// Muestra el sprite por pantalla // Muestra el sprite por pantalla

View File

@@ -129,7 +129,7 @@ auto Surface::loadSurface(const std::string& file_path) -> SurfaceData {
// Crear y devolver directamente el objeto SurfaceData // Crear y devolver directamente el objeto SurfaceData
printWithDots("Surface : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]"); printWithDots("Surface : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
return {static_cast<float>(w), static_cast<float>(h), pixels}; return {static_cast<int>(w), static_cast<int>(h), pixels};
} }
// Carga una paleta desde un archivo // Carga una paleta desde un archivo
@@ -148,14 +148,14 @@ void Surface::setColor(int index, Uint32 color) {
} }
// Rellena la superficie con un color // Rellena la superficie con un color
void Surface::clear(Uint8 color) { void Surface::clear(Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
const size_t TOTAL_PIXELS = surface_data_->width * surface_data_->height; const size_t TOTAL_PIXELS = static_cast<size_t>(surface_data_->width) * static_cast<size_t>(surface_data_->height);
Uint8* data_ptr = surface_data_->data.get(); Uint8* data_ptr = surface_data_->data.get();
std::fill(data_ptr, data_ptr + TOTAL_PIXELS, color); std::fill(data_ptr, data_ptr + TOTAL_PIXELS, color);
} }
// Pone un pixel en la SurfaceData // Pone un pixel en la SurfaceData
void Surface::putPixel(int x, int y, Uint8 color) { void Surface::putPixel(int x, int y, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) { if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) {
return; // Coordenadas fuera de rango return; // Coordenadas fuera de rango
} }
@@ -165,39 +165,39 @@ void Surface::putPixel(int x, int y, Uint8 color) {
} }
// Obtiene el color de un pixel de la surface_data // 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))]; } auto Surface::getPixel(int x, int y) -> Uint8 { return surface_data_->data.get()[x + (y * surface_data_->width)]; }
// Dibuja un rectangulo relleno // Dibuja un rectangulo relleno
void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Limitar los valores del rectángulo al tamaño de la superficie // Limitar los valores del rectángulo al tamaño de la superficie
float x_start = std::max(0.0F, rect->x); float x_start = std::max(0.0F, rect->x);
float y_start = std::max(0.0F, rect->y); float y_start = std::max(0.0F, rect->y);
float x_end = std::min(rect->x + rect->w, surface_data_->width); float x_end = std::min(rect->x + rect->w, static_cast<float>(surface_data_->width));
float y_end = std::min(rect->y + rect->h, surface_data_->height); float y_end = std::min(rect->y + rect->h, static_cast<float>(surface_data_->height));
// Rellenar fila a fila con memset (memoria contigua por fila) // Rellenar fila a fila con memset (memoria contigua por fila)
Uint8* data_ptr = surface_data_->data.get(); Uint8* data_ptr = surface_data_->data.get();
const auto SURF_WIDTH = static_cast<size_t>(surface_data_->width); const int SURF_WIDTH = surface_data_->width;
const auto ROW_WIDTH = static_cast<size_t>(static_cast<int>(x_end) - static_cast<int>(x_start)); const int ROW_WIDTH = static_cast<int>(x_end) - static_cast<int>(x_start);
for (int y = static_cast<int>(y_start); y < static_cast<int>(y_end); ++y) { for (int y = static_cast<int>(y_start); y < static_cast<int>(y_end); ++y) {
std::memset(data_ptr + (static_cast<size_t>(y) * SURF_WIDTH) + static_cast<size_t>(x_start), color, ROW_WIDTH); std::memset(data_ptr + (y * SURF_WIDTH) + static_cast<int>(x_start), color, ROW_WIDTH);
} }
} }
// Dibuja el borde de un rectangulo // Dibuja el borde de un rectangulo
void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Limitar los valores del rectángulo al tamaño de la superficie // Limitar los valores del rectángulo al tamaño de la superficie
float x_start = std::max(0.0F, rect->x); float x_start = std::max(0.0F, rect->x);
float y_start = std::max(0.0F, rect->y); float y_start = std::max(0.0F, rect->y);
float x_end = std::min(rect->x + rect->w, surface_data_->width); float x_end = std::min(rect->x + rect->w, static_cast<float>(surface_data_->width));
float y_end = std::min(rect->y + rect->h, surface_data_->height); float y_end = std::min(rect->y + rect->h, static_cast<float>(surface_data_->height));
// Dibujar bordes horizontales con memset (líneas contiguas en memoria) // Dibujar bordes horizontales con memset (líneas contiguas en memoria)
Uint8* data_ptr = surface_data_->data.get(); Uint8* data_ptr = surface_data_->data.get();
const auto SURF_WIDTH = static_cast<size_t>(surface_data_->width); const int SURF_WIDTH = surface_data_->width;
const auto ROW_WIDTH = static_cast<size_t>(static_cast<int>(x_end) - static_cast<int>(x_start)); const int ROW_WIDTH = static_cast<int>(x_end) - static_cast<int>(x_start);
std::memset(data_ptr + (static_cast<size_t>(y_start) * SURF_WIDTH) + static_cast<size_t>(x_start), color, ROW_WIDTH); std::memset(data_ptr + (static_cast<int>(y_start) * SURF_WIDTH) + static_cast<int>(x_start), color, ROW_WIDTH);
std::memset(data_ptr + ((static_cast<size_t>(y_end) - 1) * SURF_WIDTH) + static_cast<size_t>(x_start), color, ROW_WIDTH); std::memset(data_ptr + ((static_cast<int>(y_end) - 1) * SURF_WIDTH) + static_cast<int>(x_start), color, ROW_WIDTH);
// Dibujar bordes verticales // Dibujar bordes verticales
for (int y = y_start; y < y_end; ++y) { for (int y = y_start; y < y_end; ++y) {
@@ -211,72 +211,38 @@ void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) {
} }
} }
// Dibuja una linea // Dibuja una linea (Bresenham en enteros)
void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) { void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Calcula las diferencias int ix1 = static_cast<int>(std::lround(x1));
float dx = std::abs(x2 - x1); int iy1 = static_cast<int>(std::lround(y1));
float dy = std::abs(y2 - y1); const int IX2 = static_cast<int>(std::lround(x2));
const int IY2 = static_cast<int>(std::lround(y2));
// Determina la dirección del incremento const int DX = std::abs(IX2 - ix1);
float sx = (x1 < x2) ? 1 : -1; const int DY = std::abs(IY2 - iy1);
float sy = (y1 < y2) ? 1 : -1; const int SX = (ix1 < IX2) ? 1 : -1;
const int SY = (iy1 < IY2) ? 1 : -1;
float err = dx - dy; const int SURF_W = surface_data_->width;
const int SURF_H = surface_data_->height;
Uint8* data_ptr = surface_data_->data.get();
int err = DX - DY;
while (true) { while (true) {
// Asegúrate de no dibujar fuera de los límites de la superficie if (ix1 >= 0 && ix1 < SURF_W && iy1 >= 0 && iy1 < SURF_H) {
if (x1 >= 0 && x1 < surface_data_->width && y1 >= 0 && y1 < surface_data_->height) { data_ptr[ix1 + (iy1 * SURF_W)] = color;
surface_data_->data.get()[static_cast<size_t>(x1 + (y1 * surface_data_->width))] = color;
} }
if (ix1 == IX2 && iy1 == IY2) {
// Si alcanzamos el punto final, salimos
if (x1 == x2 && y1 == y2) {
break; break;
} }
int e2 = 2 * err; int e2 = 2 * err;
if (e2 > -dy) { if (e2 > -DY) {
err -= dy; err -= DY;
x1 += sx; ix1 += SX;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
}
}
void Surface::render(float dx, float dy, float sx, float sy, float w, float h) { // NOLINT(readability-make-member-function-const)
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
// Aplicar render offset
dx += Screen::get()->getRenderOffsetX();
dy += Screen::get()->getRenderOffsetY();
// 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);
const Uint8* src_ptr = surface_data_->data.get();
Uint8* dst_ptr = surface_data->data.get();
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 = src_ptr[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != static_cast<Uint8>(transparent_color_)) {
dst_ptr[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color];
}
}
} }
if (e2 < DX) {
err += DX;
iy1 += SY;
} }
} }
} }
@@ -284,44 +250,34 @@ void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { // NOLINT(readability-make-member-function-const) void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { // NOLINT(readability-make-member-function-const)
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
// Aplicar render offset
x += Screen::get()->getRenderOffsetX();
y += Screen::get()->getRenderOffsetY();
// Determina la región de origen (clip) a renderizar // Determina la región de origen (clip) a renderizar
float sx = (src_rect != nullptr) ? src_rect->x : 0; float sx = (src_rect != nullptr) ? src_rect->x : 0;
float sy = (src_rect != nullptr) ? src_rect->y : 0; float sy = (src_rect != nullptr) ? src_rect->y : 0;
float w = (src_rect != nullptr) ? src_rect->w : surface_data_->width; float w = (src_rect != nullptr) ? src_rect->w : static_cast<float>(surface_data_->width);
float h = (src_rect != nullptr) ? src_rect->h : surface_data_->height; float h = (src_rect != nullptr) ? src_rect->h : static_cast<float>(surface_data_->height);
// Guardar dimensiones originales antes del clipping (necesarias para flip) // Limitar la región para evitar accesos fuera de rango (origen y destino)
float orig_w = (src_rect != nullptr) ? src_rect->w : surface_data_->width; w = std::min(w, static_cast<float>(surface_data_->width) - sx);
float orig_h = (src_rect != nullptr) ? src_rect->h : surface_data_->height; h = std::min(h, static_cast<float>(surface_data_->height) - sy);
w = std::min(w, static_cast<float>(surface_data_dest->width - x));
// Limitar la región para evitar accesos fuera de rango en origen h = std::min(h, static_cast<float>(surface_data_dest->height - y));
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_dest->width - static_cast<float>(x));
h = std::min(h, surface_data_dest->height - static_cast<float>(y));
// Renderiza píxel por píxel aplicando el flip si es necesario // Renderiza píxel por píxel aplicando el flip si es necesario
const Uint8* src_ptr = surface_data_->data.get(); const Uint8* src_ptr = surface_data_->data.get();
Uint8* dst_ptr = surface_data_dest->data.get(); Uint8* dst_ptr = surface_data_dest->data.get();
for (int iy = 0; iy < h; ++iy) { for (int iy = 0; iy < h; ++iy) {
for (int ix = 0; ix < w; ++ix) { for (int ix = 0; ix < w; ++ix) {
// Coordenadas de origen (flip usa dimensiones originales, no clipped) // Coordenadas de origen
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? static_cast<int>(sx + orig_w - 1 - ix) : static_cast<int>(sx + ix); int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
int src_y = (flip == SDL_FLIP_VERTICAL) ? static_cast<int>(sy + orig_h - 1 - iy) : static_cast<int>(sy + iy); int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
// Coordenadas de destino // Coordenadas de destino
int dest_x = x + ix; int dest_x = x + ix;
int dest_y = y + iy; int dest_y = y + iy;
// Verificar que las coordenadas están dentro de los límites // 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 && if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
src_x >= 0 && src_x < surface_data_->width && src_y >= 0 && src_y < surface_data_->height) { // Copia el píxel si no es transparente
Uint8 color = src_ptr[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = src_ptr[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != static_cast<Uint8>(transparent_color_)) { if (color != static_cast<Uint8>(transparent_color_)) {
dst_ptr[static_cast<size_t>(dest_x + (dest_y * surface_data_dest->width))] = sub_palette_[color]; dst_ptr[static_cast<size_t>(dest_x + (dest_y * surface_data_dest->width))] = sub_palette_[color];
@@ -332,7 +288,7 @@ void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { //
} }
// Helper para calcular coordenadas con flip // 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) { void Surface::calculateFlippedCoords(int ix, int iy, int sx, int sy, int w, int h, SDL_FlipMode flip, int& src_x, int& src_y) {
src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix); src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy); src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
} }
@@ -362,10 +318,6 @@ void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip
// Si dstRect es nullptr, asignar las mismas dimensiones que srcRect // Si dstRect es nullptr, asignar las mismas dimensiones que srcRect
float dx = (dst_rect != nullptr) ? dst_rect->x : 0; float dx = (dst_rect != nullptr) ? dst_rect->x : 0;
float dy = (dst_rect != nullptr) ? dst_rect->y : 0; float dy = (dst_rect != nullptr) ? dst_rect->y : 0;
// Aplicar render offset
dx += Screen::get()->getRenderOffsetX();
dy += Screen::get()->getRenderOffsetY();
float dw = (dst_rect != nullptr) ? dst_rect->w : sw; float dw = (dst_rect != nullptr) ? dst_rect->w : sw;
float dh = (dst_rect != nullptr) ? dst_rect->h : sh; float dh = (dst_rect != nullptr) ? dst_rect->h : sh;
@@ -406,10 +358,6 @@ void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip
void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect, SDL_FlipMode flip) const { void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect, SDL_FlipMode flip) const {
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
// Aplicar render offset
x += Screen::get()->getRenderOffsetX();
y += Screen::get()->getRenderOffsetY();
// Determina la región de origen (clip) a renderizar // Determina la región de origen (clip) a renderizar
float sx = (src_rect != nullptr) ? src_rect->x : 0; float sx = (src_rect != nullptr) ? src_rect->x : 0;
float sy = (src_rect != nullptr) ? src_rect->y : 0; float sy = (src_rect != nullptr) ? src_rect->y : 0;
@@ -436,11 +384,11 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
continue; // Saltar píxeles fuera del rango del destino continue; // Saltar píxeles fuera del rango del destino
} }
// Copia el píxel si no es transparente // Copia el píxel si no es transparente; aplica sub_palette_ como el resto de render*
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != static_cast<Uint8>(transparent_color_)) { if (color != static_cast<Uint8>(transparent_color_)) {
surface_data->data[dest_x + (dest_y * surface_data->width)] = surface_data->data[dest_x + (dest_y * surface_data->width)] =
(color == source_color) ? target_color : color; (color == source_color) ? target_color : sub_palette_[color];
} }
} }
} }
@@ -467,21 +415,17 @@ static auto computeFadeDensity(int screen_y, int fade_h, int canvas_height) -> f
} }
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig) // Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, const SDL_FRect* src_rect) const { void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect) const {
// Aplicar render offset
x += Screen::get()->getRenderOffsetX();
y += Screen::get()->getRenderOffsetY();
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0; const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0;
const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0; const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0;
const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width); const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : surface_data_->width;
const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height); const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : surface_data_->height;
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
for (int row = 0; row < SH; row++) { for (int row = 0; row < SH; row++) {
const int SCREEN_Y = y + row; const int SCREEN_Y = y + row;
if (SCREEN_Y < 0 || SCREEN_Y >= static_cast<int>(surface_data_dest->height)) { if (SCREEN_Y < 0 || SCREEN_Y >= surface_data_dest->height) {
continue; continue;
} }
@@ -489,11 +433,11 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
for (int col = 0; col < SW; col++) { for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col; const int SCREEN_X = x + col;
if (SCREEN_X < 0 || SCREEN_X >= static_cast<int>(surface_data_dest->width)) { if (SCREEN_X < 0 || SCREEN_X >= surface_data_dest->width) {
continue; continue;
} }
const Uint8 COLOR = surface_data_->data[((SY + row) * static_cast<int>(surface_data_->width)) + (SX + col)]; const Uint8 COLOR = surface_data_->data[((SY + row) * surface_data_->width) + (SX + col)];
if (COLOR == static_cast<Uint8>(transparent_color_)) { if (COLOR == static_cast<Uint8>(transparent_color_)) {
continue; continue;
} }
@@ -502,27 +446,23 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
continue; // Pixel tapat per la zona de fade continue; // Pixel tapat per la zona de fade
} }
surface_data_dest->data[SCREEN_X + (SCREEN_Y * static_cast<int>(surface_data_dest->width))] = sub_palette_[COLOR]; surface_data_dest->data[SCREEN_X + (SCREEN_Y * surface_data_dest->width)] = sub_palette_[COLOR];
} }
} }
} }
// Idem però reemplaçant un color índex // Idem però reemplaçant un color índex
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, const SDL_FRect* src_rect) const { void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect) const {
// Aplicar render offset
x += Screen::get()->getRenderOffsetX();
y += Screen::get()->getRenderOffsetY();
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0; const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0;
const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0; const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0;
const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width); const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : surface_data_->width;
const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height); const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : surface_data_->height;
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
for (int row = 0; row < SH; row++) { for (int row = 0; row < SH; row++) {
const int SCREEN_Y = y + row; const int SCREEN_Y = y + row;
if (SCREEN_Y < 0 || SCREEN_Y >= static_cast<int>(surface_data_dest->height)) { if (SCREEN_Y < 0 || SCREEN_Y >= surface_data_dest->height) {
continue; continue;
} }
@@ -530,11 +470,11 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
for (int col = 0; col < SW; col++) { for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col; const int SCREEN_X = x + col;
if (SCREEN_X < 0 || SCREEN_X >= static_cast<int>(surface_data_dest->width)) { if (SCREEN_X < 0 || SCREEN_X >= surface_data_dest->width) {
continue; continue;
} }
const Uint8 COLOR = surface_data_->data[((SY + row) * static_cast<int>(surface_data_->width)) + (SX + col)]; const Uint8 COLOR = surface_data_->data[((SY + row) * surface_data_->width) + (SX + col)];
if (COLOR == static_cast<Uint8>(transparent_color_)) { if (COLOR == static_cast<Uint8>(transparent_color_)) {
continue; continue;
} }
@@ -544,7 +484,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
} }
const Uint8 OUT_COLOR = (COLOR == source_color) ? target_color : sub_palette_[COLOR]; const Uint8 OUT_COLOR = (COLOR == source_color) ? target_color : sub_palette_[COLOR];
surface_data_dest->data[SCREEN_X + (SCREEN_Y * static_cast<int>(surface_data_dest->width))] = OUT_COLOR; surface_data_dest->data[SCREEN_X + (SCREEN_Y * surface_data_dest->width)] = OUT_COLOR;
} }
} }
} }
@@ -553,8 +493,8 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
void Surface::toARGBBuffer(Uint32* buffer) const { void Surface::toARGBBuffer(Uint32* buffer) const {
if (!surface_data_ || !surface_data_->data || (buffer == nullptr)) { return; } if (!surface_data_ || !surface_data_->data || (buffer == nullptr)) { return; }
const int WIDTH = static_cast<int>(surface_data_->width); const int WIDTH = surface_data_->width;
const int HEIGHT = static_cast<int>(surface_data_->height); const int HEIGHT = surface_data_->height;
const Uint8* src = surface_data_->data.get(); const Uint8* src = surface_data_->data.get();
// Obtenemos el tamaño de la paleta para evitar accesos fuera de rango // Obtenemos el tamaño de la paleta para evitar accesos fuera de rango
@@ -573,7 +513,7 @@ void Surface::toARGBBuffer(Uint32* buffer) const {
} }
// Vuelca la superficie a una textura // Vuelca la superficie a una textura
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { // NOLINT(readability-convert-member-functions-to-static)
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) { if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
throw std::runtime_error("Renderer or texture is null."); throw std::runtime_error("Renderer or texture is null.");
} }
@@ -599,8 +539,8 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
const int WIDTH = surface_data_->width; const int WIDTH = surface_data_->width;
const int HEIGHT = surface_data_->height; const int HEIGHT = surface_data_->height;
for (int y = 0; y < HEIGHT; ++y) { for (int y = 0; y < HEIGHT; ++y) {
const Uint8* src_row = src + (static_cast<size_t>(y) * static_cast<size_t>(WIDTH)); const Uint8* src_row = src + (y * WIDTH);
Uint32* dst_row = pixels + (static_cast<size_t>(y) * static_cast<size_t>(row_stride)); Uint32* dst_row = pixels + (y * row_stride);
for (int x = 0; x < WIDTH; ++x) { for (int x = 0; x < WIDTH; ++x) {
dst_row[x] = pal[src_row[x]]; dst_row[x] = pal[src_row[x]];
} }
@@ -615,7 +555,7 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
} }
// Vuelca la superficie a una textura // Vuelca la superficie a una textura
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect) { void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect) { // NOLINT(readability-convert-member-functions-to-static)
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) { if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
throw std::runtime_error("Renderer or texture is null."); throw std::runtime_error("Renderer or texture is null.");
} }
@@ -648,8 +588,8 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FR
const int WIDTH = surface_data_->width; const int WIDTH = surface_data_->width;
const int HEIGHT = surface_data_->height; const int HEIGHT = surface_data_->height;
for (int y = 0; y < HEIGHT; ++y) { for (int y = 0; y < HEIGHT; ++y) {
const Uint8* src_row = src + (static_cast<size_t>(y) * static_cast<size_t>(WIDTH)); const Uint8* src_row = src + (y * WIDTH);
Uint32* dst_row = pixels + (static_cast<size_t>(y) * static_cast<size_t>(row_stride)); Uint32* dst_row = pixels + (y * row_stride);
for (int x = 0; x < WIDTH; ++x) { for (int x = 0; x < WIDTH; ++x) {
dst_row[x] = pal[src_row[x]]; dst_row[x] = pal[src_row[x]];
} }
@@ -664,12 +604,9 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FR
} }
// Realiza un efecto de fundido en la paleta principal // Realiza un efecto de fundido en la paleta principal
auto Surface::fadePalette() -> bool { auto Surface::fadePalette() -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Verificar que el tamaño mínimo de palette_ sea adecuado
static constexpr int PALETTE_SIZE = 19; static constexpr int PALETTE_SIZE = 19;
if (sizeof(palette_) / sizeof(palette_[0]) < PALETTE_SIZE) { static_assert(std::tuple_size_v<Palette> >= PALETTE_SIZE, "Palette size is insufficient for fadePalette operation.");
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
}
// Desplazar colores (pares e impares) // Desplazar colores (pares e impares)
for (int i = 18; i > 1; --i) { for (int i = 18; i > 1; --i) {
@@ -684,7 +621,7 @@ auto Surface::fadePalette() -> bool {
} }
// Realiza un efecto de fundido en la paleta secundaria // Realiza un efecto de fundido en la paleta secundaria
auto Surface::fadeSubPalette(Uint32 delay) -> bool { auto Surface::fadeSubPalette(Uint32 delay) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Variable estática para almacenar el último tick // Variable estática para almacenar el último tick
static Uint32 last_tick_ = 0; static Uint32 last_tick_ = 0;
@@ -699,11 +636,8 @@ auto Surface::fadeSubPalette(Uint32 delay) -> bool {
// Actualizar el último tick // Actualizar el último tick
last_tick_ = current_tick; last_tick_ = current_tick;
// Verificar que el tamaño mínimo de sub_palette_ sea adecuado
static constexpr int SUB_PALETTE_SIZE = 19; static constexpr int SUB_PALETTE_SIZE = 19;
if (sizeof(sub_palette_) / sizeof(sub_palette_[0]) < SUB_PALETTE_SIZE) { static_assert(std::tuple_size_v<SubPalette> >= SUB_PALETTE_SIZE, "Sub-palette size is insufficient for fadeSubPalette operation.");
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
}
// Desplazar colores (pares e impares) // Desplazar colores (pares e impares)
for (int i = 18; i > 1; --i) { for (int i = 18; i > 1; --i) {
@@ -718,4 +652,4 @@ auto Surface::fadeSubPalette(Uint32 delay) -> bool {
} }
// Restaura la sub paleta a su estado original // Restaura la sub paleta a su estado original
void Surface::resetSubPalette() { initializeSubPalette(sub_palette_); } void Surface::resetSubPalette() { initializeSubPalette(sub_palette_); } // NOLINT(readability-convert-member-functions-to-static)

View File

@@ -22,8 +22,8 @@ auto readPalFile(const std::string& file_path) -> Palette;
struct SurfaceData { struct SurfaceData {
std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática
float width; // Ancho de la imagen int width; // Ancho de la imagen
float height; // Alto de la imagen int height; // Alto de la imagen
// Constructor por defecto // Constructor por defecto
SurfaceData() SurfaceData()
@@ -32,13 +32,13 @@ struct SurfaceData {
height(0) {} height(0) {}
// Constructor que inicializa dimensiones y asigna memoria // Constructor que inicializa dimensiones y asigna memoria
SurfaceData(float w, float h) SurfaceData(int w, int h)
: data(std::shared_ptr<Uint8[]>(new Uint8[static_cast<size_t>(w * h)](), std::default_delete<Uint8[]>())), : data(std::shared_ptr<Uint8[]>(new Uint8[static_cast<size_t>(w) * static_cast<size_t>(h)](), std::default_delete<Uint8[]>())),
width(w), width(w),
height(h) {} height(h) {}
// Constructor para inicializar directamente con datos // Constructor para inicializar directamente con datos
SurfaceData(float w, float h, std::shared_ptr<Uint8[]> pixels) SurfaceData(int w, int h, std::shared_ptr<Uint8[]> pixels)
: data(std::move(pixels)), : data(std::move(pixels)),
width(w), width(w),
height(h) {} height(h) {}
@@ -56,6 +56,9 @@ struct SurfaceData {
class Surface { class Surface {
private: private:
// shared_ptr porque render() accede al SurfaceData propio y al del renderer
// surface (ver getRendererSurface()) de forma efímera; con self-blit ambos
// pueden alias y el refcount evita free accidental durante el recorrido.
std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar
Palette palette_; // Paleta para volcar la SurfaceData a una Textura Palette palette_; // Paleta para volcar la SurfaceData a una Textura
SubPalette sub_palette_; // Paleta para reindexar colores SubPalette sub_palette_; // Paleta para reindexar colores
@@ -77,7 +80,6 @@ class Surface {
void loadPalette(const Palette& palette); void loadPalette(const Palette& palette);
// Copia una región de la SurfaceData de origen a la SurfaceData de destino // Copia una región de la SurfaceData de origen a la SurfaceData de destino
void render(float dx, float dy, float sx, float sy, float w, float h);
void render(int x, int y, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); void render(int x, int y, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
@@ -85,10 +87,10 @@ class Surface {
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE) const; void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE) const;
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig) // Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, const SDL_FRect* src_rect = nullptr) const; void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr) const;
// Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color) // Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, const SDL_FRect* src_rect = nullptr) const; void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect = nullptr) const;
// Establece un color en la paleta // Establece un color en la paleta
void setColor(int index, Uint32 color); void setColor(int index, Uint32 color);
@@ -127,11 +129,10 @@ class Surface {
// Metodos para gestionar surface_data_ // Metodos para gestionar surface_data_
[[nodiscard]] auto getSurfaceData() const -> std::shared_ptr<SurfaceData> { return surface_data_; } [[nodiscard]] auto getSurfaceData() const -> std::shared_ptr<SurfaceData> { return surface_data_; }
void setSurfaceData(std::shared_ptr<SurfaceData> new_data) { surface_data_ = std::move(new_data); }
// Obtien ancho y alto // Obtien ancho y alto
[[nodiscard]] auto getWidth() const -> float { return surface_data_->width; } [[nodiscard]] auto getWidth() const -> int { return surface_data_->width; }
[[nodiscard]] auto getHeight() const -> float { return surface_data_->height; } [[nodiscard]] auto getHeight() const -> int { return surface_data_->height; }
// Color transparente // Color transparente
[[nodiscard]] auto getTransparentColor() const -> Uint8 { return transparent_color_; } [[nodiscard]] auto getTransparentColor() const -> Uint8 { return transparent_color_; }
@@ -139,7 +140,6 @@ class Surface {
// Paleta // Paleta
void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; } void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; }
[[nodiscard]] auto getPalette() const -> const Palette& { return palette_; }
[[nodiscard]] auto getPaletteColor(Uint8 index) const -> Uint32 { return palette_[index]; } [[nodiscard]] auto getPaletteColor(Uint8 index) const -> Uint32 { return palette_[index]; }
// Inicializa la sub paleta // Inicializa la sub paleta
@@ -147,7 +147,7 @@ class Surface {
private: private:
// Helper para calcular coordenadas con flip // Helper para calcular coordenadas con flip
static void calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y); static void calculateFlippedCoords(int ix, int iy, int sx, int sy, int w, int h, SDL_FlipMode flip, int& src_x, int& src_y);
// Helper para copiar un pixel si no es transparente // Helper para copiar un pixel si no es transparente
void copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const; void copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const;

View File

@@ -384,7 +384,11 @@ void MiniMap::handleEvent(const SDL_Event& event, const std::string& current_roo
Screen::get()->setRendererSurface(prev); Screen::get()->setRendererSurface(prev);
} }
auto game_surface = Screen::get()->getRendererSurface(); auto game_surface = Screen::get()->getRendererSurface();
if (game_surface) { map_surface_->setPalette(game_surface->getPalette()); } if (game_surface) {
Palette src_palette{};
for (int i = 0; i < 256; ++i) { src_palette[i] = game_surface->getPaletteColor(static_cast<Uint8>(i)); }
map_surface_->setPalette(src_palette);
}
std::string file = Screenshot::save(*map_surface_); std::string file = Screenshot::save(*map_surface_);
if (!file.empty()) { std::cout << "MiniMap screenshot: " << file << "\n"; } if (!file.empty()) { std::cout << "MiniMap screenshot: " << file << "\n"; }
// Recomponer para limpiar los números de la surface // Recomponer para limpiar los números de la surface

View File

@@ -256,7 +256,7 @@ void Notifier::show(std::vector<std::string> texts, const Style& style, int icon
else if (SHAPE == Shape::SQUARED) { else if (SHAPE == Shape::SQUARED) {
n.surface->clear(style.bg_color); n.surface->clear(style.bg_color);
SDL_FRect squared_rect = {.x = 0, .y = 0, .w = n.surface->getWidth(), .h = n.surface->getHeight()}; SDL_FRect squared_rect = {.x = 0, .y = 0, .w = static_cast<float>(n.surface->getWidth()), .h = static_cast<float>(n.surface->getHeight())};
n.surface->drawRectBorder(&squared_rect, style.border_color); n.surface->drawRectBorder(&squared_rect, style.border_color);
} }