From b3215bf381864b897109c21d1b4ea4354f67f707 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 16 Mar 2025 12:44:38 +0100 Subject: [PATCH] retocat gif.cpp --- linux_utils/run_cppcheck.sh | 1 + source/director.cpp | 2 +- source/gif.cpp | 521 ++++++++++++++++++++---------------- source/gif.h | 161 ++++++----- source/jail_shader.cpp | 21 +- source/texture.cpp | 82 +++--- 6 files changed, 429 insertions(+), 359 deletions(-) diff --git a/linux_utils/run_cppcheck.sh b/linux_utils/run_cppcheck.sh index 6d41d6d..48327a7 100644 --- a/linux_utils/run_cppcheck.sh +++ b/linux_utils/run_cppcheck.sh @@ -29,6 +29,7 @@ done case $opcion in w) cppcheck --force --enable=warning,style,performance --std=c++20 \ + --check-level=exhaustive \ --suppressions-list=./cppcheck_suppressions \ ../source/ \ 2>./cppcheck-result-warning-style-performance.txt diff --git a/source/director.cpp b/source/director.cpp index 875bd39..d82fc3f 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -55,7 +55,7 @@ Director::Director(int argc, const char *argv[]) section::name = section::Name::GAME; section::options = section::Options::GAME_PLAY_1P; #elif DEBUG - section::name = section::Name::CREDITS; + section::name = section::Name::LOGO; #else // NORMAL GAME section::name = section::Name::LOGO; section::options = section::Options::NONE; diff --git a/source/gif.cpp b/source/gif.cpp index 2caac41..c13e236 100644 --- a/source/gif.cpp +++ b/source/gif.cpp @@ -1,262 +1,317 @@ #include "gif.h" -#include // Para fprintf, stderr -#include // Para exit, malloc, calloc, free, realloc -#include // Para vector +#include // for fprintf, stderr +#include // for memcpy, size_t +#include // for runtime_error +#include // for allocator, char_traits, operator==, basic_string -void Gif::uncompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) +namespace GIF { - int i, bit; - int code, prev = -1; - std::vector dictionary; - int dictionary_ind; - unsigned int mask = 0x01; - int reset_code_length; - int clear_code; - int stop_code; - int match_len; - clear_code = 1 << (code_length); - stop_code = clear_code + 1; - reset_code_length = code_length; - - dictionary.resize(1 << (code_length + 1)); - - for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) + // Función inline para reemplazar el macro READ. + // Actualiza el puntero 'buffer' tras copiar 'size' bytes a 'dst'. + inline void readBytes(const uint8_t *&buffer, void *dst, size_t size) { - dictionary[dictionary_ind].byte = dictionary_ind; - dictionary[dictionary_ind].prev = -1; - dictionary[dictionary_ind].len = 1; + std::memcpy(dst, buffer, size); + buffer += size; } - dictionary_ind += 2; - - while (input_length) + void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) { - code = 0x0; - for (i = 0; i < (code_length + 1); i++) + // Verifica que el code_length tenga un rango razonable. + if (code_length < 2 || code_length > 12) { - bit = (*input & mask) ? 1 : 0; - mask <<= 1; - - if (mask == 0x100) - { - mask = 0x01; - input++; - input_length--; - } - - code = code | (bit << i); + throw std::runtime_error("Invalid LZW code length"); } - if (code == clear_code) - { - code_length = reset_code_length; - dictionary.resize(1 << (code_length + 1)); + int i, bit; + int prev = -1; + std::vector dictionary; + int dictionary_ind; + unsigned int mask = 0x01; + int reset_code_length = code_length; + int clear_code = 1 << code_length; + int stop_code = clear_code + 1; + int match_len = 0; - for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) - { - dictionary[dictionary_ind].byte = dictionary_ind; - dictionary[dictionary_ind].prev = -1; - dictionary[dictionary_ind].len = 1; - } - dictionary_ind += 2; - prev = -1; - continue; - } - else if (code == stop_code) - { - break; + // Inicializamos el diccionario con el tamaño correspondiente. + dictionary.resize(1 << (code_length + 1)); + for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) + { + dictionary[dictionary_ind].byte = static_cast(dictionary_ind); + dictionary[dictionary_ind].prev = -1; + dictionary[dictionary_ind].len = 1; } + dictionary_ind += 2; // Reservamos espacio para clear y stop codes - if ((prev > -1) && (code_length < 12)) + // Bucle principal: procesar el stream comprimido. + while (input_length > 0) { - if (code > dictionary_ind) + int code = 0; + // Lee (code_length + 1) bits para formar el código. + for (i = 0; i < (code_length + 1); i++) { - fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind); - exit(0); - } - - if (code == dictionary_ind) - { - int ptr = prev; - while (dictionary[ptr].prev != -1) + if (input_length <= 0) { - ptr = dictionary[ptr].prev; + throw std::runtime_error("Unexpected end of input in uncompress"); } - dictionary[dictionary_ind].byte = dictionary[ptr].byte; + bit = ((*input & mask) != 0) ? 1 : 0; + mask <<= 1; + if (mask == 0x100) + { + mask = 0x01; + input++; + input_length--; + } + code |= (bit << i); + } + + if (code == clear_code) + { + // Reinicia el diccionario. + code_length = reset_code_length; + dictionary.resize(1 << (code_length + 1)); + for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) + { + dictionary[dictionary_ind].byte = static_cast(dictionary_ind); + dictionary[dictionary_ind].prev = -1; + dictionary[dictionary_ind].len = 1; + } + dictionary_ind += 2; + prev = -1; + continue; + } + else if (code == stop_code) + { + break; + } + + if (prev > -1 && code_length < 12) + { + if (code > dictionary_ind) + { + std::fprintf(stderr, "code = %.02x, but dictionary_ind = %d\n", code, dictionary_ind); + throw std::runtime_error("LZW error: code exceeds dictionary_ind."); + } + + int ptr; + if (code == dictionary_ind) + { + ptr = prev; + while (dictionary[ptr].prev != -1) + ptr = dictionary[ptr].prev; + dictionary[dictionary_ind].byte = dictionary[ptr].byte; + } + else + { + ptr = code; + while (dictionary[ptr].prev != -1) + ptr = dictionary[ptr].prev; + dictionary[dictionary_ind].byte = dictionary[ptr].byte; + } + dictionary[dictionary_ind].prev = prev; + dictionary[dictionary_ind].len = dictionary[prev].len + 1; + dictionary_ind++; + + if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) + { + code_length++; + dictionary.resize(1 << (code_length + 1)); + } + } + + prev = code; + + // Verifica que 'code' sea un índice válido antes de usarlo. + if (code < 0 || static_cast(code) >= dictionary.size()) + { + std::fprintf(stderr, "Invalid LZW code %d, dictionary size %zu\n", code, dictionary.size()); + throw std::runtime_error("LZW error: invalid code encountered"); + } + + int curCode = code; // Variable temporal para recorrer la cadena. + match_len = dictionary[curCode].len; + while (curCode != -1) + { + // Se asume que dictionary[curCode].len > 0. + out[dictionary[curCode].len - 1] = dictionary[curCode].byte; + if (dictionary[curCode].prev == curCode) + { + std::fprintf(stderr, "Internal error; self-reference detected.\n"); + throw std::runtime_error("Internal error in uncompress: self-reference"); + } + curCode = dictionary[curCode].prev; + } + out += match_len; + } + } + + std::vector Gif::readSubBlocks(const uint8_t *&buffer) + { + std::vector data; + uint8_t block_size = *buffer; + buffer++; + while (block_size != 0) + { + data.insert(data.end(), buffer, buffer + block_size); + buffer += block_size; + block_size = *buffer; + buffer++; + } + return data; + } + + std::vector Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector &gct, int resolution_bits) + { + ImageDescriptor image_descriptor; + // Lee 9 bytes para el image descriptor. + readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor)); + + uint8_t lzw_code_size; + readBytes(buffer, &lzw_code_size, sizeof(uint8_t)); + + std::vector compressed_data = readSubBlocks(buffer); + int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height; + std::vector uncompressed_data(uncompressed_data_length); + + decompress(lzw_code_size, compressed_data.data(), static_cast(compressed_data.size()), uncompressed_data.data()); + return uncompressed_data; + } + + std::vector Gif::loadPalette(const uint8_t *buffer) + { + uint8_t header[6]; + std::memcpy(header, buffer, 6); + buffer += 6; + + ScreenDescriptor screen_descriptor; + std::memcpy(&screen_descriptor, buffer, sizeof(ScreenDescriptor)); + buffer += sizeof(ScreenDescriptor); + + std::vector global_color_table; + if (screen_descriptor.fields & 0x80) + { + int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); + global_color_table.resize(global_color_table_size); + for (int i = 0; i < global_color_table_size; ++i) + { + uint8_t r = buffer[0]; + uint8_t g = buffer[1]; + uint8_t b = buffer[2]; + global_color_table[i] = (r << 16) | (g << 8) | b; + buffer += 3; + } + } + return global_color_table; + } + + std::vector Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) + { + // Leer la cabecera de 6 bytes ("GIF87a" o "GIF89a") + uint8_t header[6]; + std::memcpy(header, buffer, 6); + buffer += 6; + + // Opcional: Validar header + std::string headerStr(reinterpret_cast(header), 6); + if (headerStr != "GIF87a" && headerStr != "GIF89a") + { + throw std::runtime_error("Formato de archivo GIF inválido."); + } + + // Leer el Screen Descriptor (7 bytes, empaquetado sin padding) + ScreenDescriptor screen_descriptor; + readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor)); + + // Asigna ancho y alto + w = screen_descriptor.width; + h = screen_descriptor.height; + + // Imprime para depuración + std::fprintf(stderr, "Screen Descriptor - Width: %d, Height: %d\n", w, h); + + int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; + std::vector global_color_table; + if (screen_descriptor.fields & 0x80) + { + int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); + global_color_table.resize(global_color_table_size); + std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size); + buffer += 3 * global_color_table_size; + } + + // Supongamos que 'buffer' es el puntero actual y TRAILER es 0x3B + uint8_t block_type = *buffer++; + while (block_type != TRAILER) + { + if (block_type == EXTENSION_INTRODUCER) // 0x21 + { + // Se lee la etiqueta de extensión, la cual indica el tipo de extensión. + uint8_t extension_label = *buffer++; + switch (extension_label) + { + case GRAPHIC_CONTROL: // 0xF9 + { + // Procesar Graphic Control Extension: + uint8_t blockSize = *buffer++; // Normalmente, blockSize == 4 + buffer += blockSize; // Saltamos los 4 bytes del bloque fijo + // Saltar los sub-bloques + uint8_t subBlockSize = *buffer++; + while (subBlockSize != 0) + { + buffer += subBlockSize; + subBlockSize = *buffer++; + } + break; + } + case APPLICATION_EXTENSION: // 0xFF + case COMMENT_EXTENSION: // 0xFE + case PLAINTEXT_EXTENSION: // 0x01 + { + // Para estas extensiones, saltamos el bloque fijo y los sub-bloques. + uint8_t blockSize = *buffer++; + buffer += blockSize; + uint8_t subBlockSize = *buffer++; + while (subBlockSize != 0) + { + buffer += subBlockSize; + subBlockSize = *buffer++; + } + break; + } + default: + { + // Si la etiqueta de extensión es desconocida, saltarla también: + uint8_t blockSize = *buffer++; + buffer += blockSize; + uint8_t subBlockSize = *buffer++; + while (subBlockSize != 0) + { + buffer += subBlockSize; + subBlockSize = *buffer++; + } + break; + } + } + } + else if (block_type == IMAGE_DESCRIPTOR) + { + // Procesar el Image Descriptor y retornar los datos de imagen + return processImageDescriptor(buffer, global_color_table, color_resolution_bits); } else { - int ptr = code; - while (dictionary[ptr].prev != -1) - { - ptr = dictionary[ptr].prev; - } - dictionary[dictionary_ind].byte = dictionary[ptr].byte; - } - - dictionary[dictionary_ind].prev = prev; - dictionary[dictionary_ind].len = dictionary[prev].len + 1; - dictionary_ind++; - - if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) - { - code_length++; - dictionary.resize(1 << (code_length + 1)); + std::fprintf(stderr, "Unrecognized block type %.02x\n", block_type); + return std::vector{}; } + block_type = *buffer++; } - prev = code; - - match_len = dictionary[code].len; - while (code != -1) - { - out[dictionary[code].len - 1] = dictionary[code].byte; - if (dictionary[code].prev == code) - { - fprintf(stderr, "Internal error; self-reference."); - exit(0); - } - code = dictionary[code].prev; - } - - out += match_len; + return std::vector{}; } -} -int Gif::read_sub_blocks(uint8_t *buffer, uint8_t **data) -{ - int data_length = 0; - int index = 0; - uint8_t block_size; - - *data = nullptr; - - while (true) + std::vector Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) { - READ(&block_size, 1); - - if (block_size == 0) - { - break; - } - - data_length += block_size; - *data = (uint8_t *)realloc(*data, data_length); - - READ(*data + index, block_size); - index += block_size; + return processGifStream(buffer, w, h); } - return data_length; -} - -uint8_t *Gif::process_image_descriptor(uint8_t *buffer, RGB *gct, int gct_size, int resolution_bits) -{ - ImageDescriptor image_descriptor; - int compressed_data_length; - uint8_t *compressed_data = nullptr; - uint8_t lzw_code_size; - int uncompressed_data_length = 0; - uint8_t *uncompressed_data = nullptr; - - READ(&image_descriptor, 9); - READ(&lzw_code_size, 1); - - compressed_data_length = read_sub_blocks(buffer, &compressed_data); - uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height; - uncompressed_data = (uint8_t *)malloc(uncompressed_data_length); - - uncompress(lzw_code_size, compressed_data, compressed_data_length, uncompressed_data); - - if (compressed_data) - { - free(compressed_data); - } - - return uncompressed_data; -} - -uint32_t *Gif::LoadPalette(uint8_t *buffer) -{ - uint8_t header[7]; - ScreenDescriptor screen_descriptor; - int global_color_table_size = 0; - uint32_t *global_color_table = nullptr; - - READ(header, 6); - READ(&screen_descriptor, 7); - - global_color_table = (uint32_t *)calloc(1, 1024); - - if (screen_descriptor.fields & 0x80) - { - global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); - - for (int i = 0; i < global_color_table_size; ++i) - { - global_color_table[i] = (buffer[0] << 16) + (buffer[1] << 8) + buffer[2]; - buffer += 3; - } - } - return global_color_table; -} - -uint8_t *Gif::process_gif_stream(uint8_t *buffer, uint16_t *w, uint16_t *h) -{ - uint8_t header[7]; - ScreenDescriptor screen_descriptor; - int color_resolution_bits; - int global_color_table_size = 0; - RGB *global_color_table = nullptr; - uint8_t block_type = 0x0; - - READ(header, 6); - header[6] = 0x0; - - READ(&screen_descriptor, 7); - *w = screen_descriptor.width; - *h = screen_descriptor.height; - - color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; - - if (screen_descriptor.fields & 0x80) - { - global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); - global_color_table = (RGB *)malloc(3 * global_color_table_size); - READ(global_color_table, 3 * global_color_table_size); - } - - while (block_type != TRAILER) - { - READ(&block_type, 1); - - uint8_t size; - switch (block_type) - { - case IMAGE_DESCRIPTOR: - return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits); - case EXTENSION_INTRODUCER: - buffer++; - size = *(buffer++); - buffer += size; - do - { - size = *(buffer++); - buffer += size; - } while (size != 0); - break; - case TRAILER: - break; - default: - fprintf(stderr, "Bailing on unrecognized block type %.02x\n", block_type); - return nullptr; - } - } - return nullptr; -} - -uint8_t *Gif::LoadGif(uint8_t *buffer, uint16_t *w, uint16_t *h) -{ - return process_gif_stream(buffer, w, h); -} \ No newline at end of file +} // namespace GIF diff --git a/source/gif.h b/source/gif.h index 3c3ccb5..54ceef6 100644 --- a/source/gif.h +++ b/source/gif.h @@ -1,85 +1,102 @@ #pragma once -#include // Para uint8_t, uint16_t, uint32_t -#include // Para memcpy +#include // for uint8_t, uint16_t, uint32_t +#include // for vector -#define EXTENSION_INTRODUCER 0x21 -#define IMAGE_DESCRIPTOR 0x2C -#define TRAILER 0x3B -#define GRAPHIC_CONTROL 0xF9 -#define APPLICATION_EXTENSION 0xFF -#define COMMENT_EXTENSION 0xFE -#define PLAINTEXT_EXTENSION 0x01 - -#define READ(dst, size) \ - memcpy(dst, buffer, size); \ - buffer += size - -struct ScreenDescriptor +namespace GIF { - uint16_t width; - uint16_t height; - uint8_t fields; - uint8_t background_color_index; - uint8_t pixel_aspect_ratio; -}; -struct RGB -{ - uint8_t r, g, b; -}; + // Constantes definidas con constexpr, en lugar de macros + constexpr uint8_t EXTENSION_INTRODUCER = 0x21; + constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C; + constexpr uint8_t TRAILER = 0x3B; + constexpr uint8_t GRAPHIC_CONTROL = 0xF9; + constexpr uint8_t APPLICATION_EXTENSION = 0xFF; + constexpr uint8_t COMMENT_EXTENSION = 0xFE; + constexpr uint8_t PLAINTEXT_EXTENSION = 0x01; -struct ImageDescriptor -{ - uint16_t image_left_position; - uint16_t image_top_position; - uint16_t image_width; - uint16_t image_height; - uint8_t fields; -}; +#pragma pack(push, 1) + struct ScreenDescriptor + { + uint16_t width; + uint16_t height; + uint8_t fields; + uint8_t background_color_index; + uint8_t pixel_aspect_ratio; + }; -struct DictionaryEntry -{ - uint8_t byte; - int prev; - int len; -}; + struct RGB + { + uint8_t r, g, b; + }; -struct Extension -{ - uint8_t extension_code; - uint8_t block_size; -}; + struct ImageDescriptor + { + uint16_t image_left_position; + uint16_t image_top_position; + uint16_t image_width; + uint16_t image_height; + uint8_t fields; + }; +#pragma pack(pop) -struct GraphicControlExtension -{ - uint8_t fields; - uint16_t delay_time; - uint8_t transparent_color_index; -}; + struct DictionaryEntry + { + uint8_t byte; + int prev; + int len; + }; -struct ApplicationExtension -{ - uint8_t application_id[8]; - uint8_t version[3]; -}; + struct Extension + { + uint8_t extension_code; + uint8_t block_size; + }; -struct PlaintextExtension -{ - uint16_t left, top, width, height; - uint8_t cell_width, cell_height; - uint8_t foreground_color, background_color; -}; + struct GraphicControlExtension + { + uint8_t fields; + uint16_t delay_time; + uint8_t transparent_color_index; + }; -class Gif -{ -public: - void uncompress(int code_length, const uint8_t *input, int input_length, uint8_t *out); - uint32_t *LoadPalette(uint8_t *buffer); - uint8_t *LoadGif(uint8_t *buffer, uint16_t *w, uint16_t *h); + struct ApplicationExtension + { + uint8_t application_id[8]; + uint8_t version[3]; + }; -private: - int read_sub_blocks(uint8_t *buffer, uint8_t **data); - uint8_t *process_image_descriptor(uint8_t *buffer, RGB *gct, int gct_size, int resolution_bits); - uint8_t *process_gif_stream(uint8_t *buffer, uint16_t *w, uint16_t *h); -}; \ No newline at end of file + struct PlaintextExtension + { + uint16_t left, top, width, height; + uint8_t cell_width, cell_height; + uint8_t foreground_color, background_color; + }; + + class Gif + { + public: + // Descompone (uncompress) el bloque comprimido usando LZW. + // Este método puede lanzar std::runtime_error en caso de error. + void decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out); + + // Carga la paleta (global color table) a partir de un buffer, + // retornándola en un vector de uint32_t (cada color se compone de R, G, B). + std::vector loadPalette(const uint8_t *buffer); + + // Carga el stream GIF; devuelve un vector con los datos de imagen sin comprimir y + // asigna el ancho y alto mediante referencias. + std::vector loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h); + + private: + // Lee los sub-bloques de datos y los acumula en un std::vector. + std::vector readSubBlocks(const uint8_t *&buffer); + + // Procesa el Image Descriptor y retorna el vector de datos sin comprimir. + std::vector processImageDescriptor(const uint8_t *&buffer, const std::vector &gct, int resolution_bits); + + // Procesa el stream completo del GIF y devuelve los datos sin comprimir. + std::vector processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h); + }; + +} // namespace GIF diff --git a/source/jail_shader.cpp b/source/jail_shader.cpp index 5424ed6..b7b832f 100644 --- a/source/jail_shader.cpp +++ b/source/jail_shader.cpp @@ -1,5 +1,4 @@ #include "jail_shader.h" -#include // Para GLuint, glTexCoord2f, glVertex2f, GLfloat #include // Para SDL_Point #include // Para SDL_bool #include // Para strncmp @@ -8,18 +7,16 @@ #include // Para vector #ifdef __APPLE__ -#include "CoreFoundation/CoreFoundation.h" -#include - +#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS +#include // Para OpenGL en macOS #if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 -#include -#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 -#include -#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 - -#else // SI NO ES __APPLE__ -#include -#endif // __APPLE__ +#include // Para OpenGL 3 en macOS +#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 +#include // Para OpenGL (compatibilidad) en macOS +#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 +#else // SI NO ES __APPLE__ +#include // Para GLuint, glTexCoord2f, glVertex2f, GLfloat +#endif // __APPLE__ namespace shader { diff --git a/source/texture.cpp b/source/texture.cpp index cee08f5..af1aaca 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -1,14 +1,15 @@ #include "texture.h" -#include // Para SDL_GetError -#include // Para SDL_CreateRGBSurfaceWithFormatFrom -#include // Para basic_ostream, operator<<, basic_ifstream -#include // Para cerr, cout -#include // Para runtime_error -#include // Para char_traits, operator<<, operator+ -#include // Para vector -#include "gif.h" // Para LoadGif, LoadPalette -#include "stb_image.h" // Para stbi_image_free, stbi_load, STBI_rgb_a... -#include "utils.h" // Para getFileName, printWithDots +#include // for SDL_GetError +#include // for SDL_CreateRGBSurfaceWithFormatFrom +#include // for uint32_t +#include // for memcpy, size_t +#include // for basic_ostream, operator<<, basic_ifstream +#include // for cerr, cout +#include // for runtime_error +#include // for char_traits, operator<<, operator+ +#include // for vector +#include "gif.h" // for Gif +#include "utils.h" // for getFileName, Color, printWithDots #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" // Para stbi_failure_reason, stbi_image_free @@ -38,7 +39,6 @@ Texture::Texture(SDL_Renderer *renderer, const std::string &path) // Añade la propia paleta del fichero a la lista addPaletteFromFile(path_); - // setPaletteColor(0, 0, 0x00000000); // Crea la textura, establece el BlendMode y copia la surface a la textura createBlank(width_, height_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING); @@ -77,18 +77,11 @@ bool Texture::loadFromFile(const std::string &file_path) int depth, pitch; Uint32 pixel_format; - /*if (req_format == STBI_rgb) - { - depth = 24; - pitch = 3 * width; // 3 bytes por pixel * pixels por linea - pixel_format = SDL_PIXELFORMAT_RGB24; - } - else*/ - { // STBI_rgb_alpha (RGBA) - depth = 32; - pitch = 4 * width; - pixel_format = SDL_PIXELFORMAT_RGBA32; - } + + // STBI_rgb_alpha (RGBA) + depth = 32; + pitch = 4 * width; + pixel_format = SDL_PIXELFORMAT_RGBA32; // Limpia unloadTexture(); @@ -249,7 +242,7 @@ void Texture::unloadSurface() // Crea una surface desde un fichero .gif std::shared_ptr Texture::loadSurface(const std::string &file_path) { - // Desencadenar la superficie actual + // Libera la superficie actual unloadSurface(); // Abrir el archivo usando std::ifstream para manejo automático del recurso @@ -271,24 +264,26 @@ std::shared_ptr Texture::loadSurface(const std::string &file_path) std::cerr << "Error al leer el fichero " << file_path << std::endl; throw std::runtime_error("Error al leer el fichero: " + file_path); } - - // Cerrar el archivo (automáticamente manejado por std::ifstream) file.close(); - // Crear un objeto Gif y llamar a la función LoadGif - Gif gif; - Uint16 w, h; - Uint8 *rawPixels = gif.LoadGif(buffer.data(), &w, &h); - if (!rawPixels) + // Crear un objeto Gif y llamar a la función loadGif + GIF::Gif gif; + Uint16 w = 0, h = 0; + std::vector rawPixels = gif.loadGif(buffer.data(), w, h); + if (rawPixels.empty()) { return nullptr; } - // Crear un std::shared_ptr con std::make_shared para pixels - auto pixels = std::shared_ptr(rawPixels, std::default_delete()); + // Si el constructor de Surface espera un std::shared_ptr, + // reservamos un bloque dinámico y copiamos los datos del vector. + size_t pixelCount = rawPixels.size(); + auto pixels = std::shared_ptr(new Uint8[pixelCount], std::default_delete()); + std::memcpy(pixels.get(), rawPixels.data(), pixelCount); + auto surface = std::make_shared(w, h, pixels); - // Actualizar la anchura y altura + // Actualizar las dimensiones width_ = w; height_ = h; @@ -327,6 +322,7 @@ std::vector Texture::loadPaletteFromFile(const std::string &file_path) { std::vector palette; + // Abrir el archivo GIF std::ifstream file(file_path, std::ios::binary | std::ios::ate); if (!file) { @@ -338,7 +334,8 @@ std::vector Texture::loadPaletteFromFile(const std::string &file_path) printWithDots("Image : ", getFileName(file_path), "[ LOADED ]"); } - auto size = file.tellg(); + // Obtener el tamaño del archivo y leerlo en un buffer + std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); std::vector buffer(size); @@ -347,17 +344,20 @@ std::vector Texture::loadPaletteFromFile(const std::string &file_path) std::cerr << "Error: No se pudo leer completamente el fichero " << getFileName(file_path) << std::endl; throw std::runtime_error("Error al leer el fichero: " + getFileName(file_path)); } + file.close(); - Gif gif; - const auto *PAL = gif.LoadPalette(buffer.data()); - if (!PAL) + // Usar la nueva función loadPalette, que devuelve un vector + GIF::Gif gif; + std::vector pal = gif.loadPalette(buffer.data()); + if (pal.empty()) { - return palette; + return palette; // Devuelve un vector vacío si no hay paleta } - for (int i = 0; i < 256; ++i) + // Modificar la conversión para obtener formato RGBA (0xRRGGBBAA) + for (const auto &color : pal) { - palette.push_back((PAL[i] << 8) + 255); + palette.push_back((color << 8) | 0xFF); // Resultado: 0xRRGGBBAA } return palette;