retocat gif.cpp
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
521
source/gif.cpp
521
source/gif.cpp
@@ -1,262 +1,317 @@
|
||||
#include "gif.h"
|
||||
#include <cstdio> // Para fprintf, stderr
|
||||
#include <cstdlib> // Para exit, malloc, calloc, free, realloc
|
||||
#include <vector> // Para vector
|
||||
#include <cstdio> // for fprintf, stderr
|
||||
#include <cstring> // for memcpy, size_t
|
||||
#include <stdexcept> // for runtime_error
|
||||
#include <string> // 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<DictionaryEntry> 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<DictionaryEntry> 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<uint8_t>(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<uint8_t>(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<size_t>(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<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer)
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &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<uint8_t> compressed_data = readSubBlocks(buffer);
|
||||
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
||||
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
||||
|
||||
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> 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<uint32_t> 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<uint8_t> 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<char *>(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<RGB> 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<uint8_t>{};
|
||||
}
|
||||
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<uint8_t>{};
|
||||
}
|
||||
}
|
||||
|
||||
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<uint8_t> 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);
|
||||
}
|
||||
} // namespace GIF
|
||||
|
||||
161
source/gif.h
161
source/gif.h
@@ -1,85 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // Para uint8_t, uint16_t, uint32_t
|
||||
#include <cstring> // Para memcpy
|
||||
#include <cstdint> // for uint8_t, uint16_t, uint32_t
|
||||
#include <vector> // 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);
|
||||
};
|
||||
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<uint32_t> 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<uint8_t> 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<uint8_t>.
|
||||
std::vector<uint8_t> readSubBlocks(const uint8_t *&buffer);
|
||||
|
||||
// Procesa el Image Descriptor y retorna el vector de datos sin comprimir.
|
||||
std::vector<uint8_t> processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits);
|
||||
|
||||
// Procesa el stream completo del GIF y devuelve los datos sin comprimir.
|
||||
std::vector<uint8_t> processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h);
|
||||
};
|
||||
|
||||
} // namespace GIF
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "jail_shader.h"
|
||||
#include <SDL2/SDL_opengl.h> // Para GLuint, glTexCoord2f, glVertex2f, GLfloat
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Point
|
||||
#include <SDL2/SDL_stdinc.h> // Para SDL_bool
|
||||
#include <cstring> // Para strncmp
|
||||
@@ -8,18 +7,16 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "CoreFoundation/CoreFoundation.h"
|
||||
#include <OpenGL/OpenGL.h>
|
||||
|
||||
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
|
||||
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
|
||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl3.h>
|
||||
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl.h>
|
||||
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
|
||||
#else // SI NO ES __APPLE__
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#endif // __APPLE__
|
||||
#include <OpenGL/gl3.h> // Para OpenGL 3 en macOS
|
||||
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS
|
||||
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#else // SI NO ES __APPLE__
|
||||
#include <SDL2/SDL_opengl.h> // Para GLuint, glTexCoord2f, glVertex2f, GLfloat
|
||||
#endif // __APPLE__
|
||||
|
||||
namespace shader
|
||||
{
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "texture.h"
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_surface.h> // Para SDL_CreateRGBSurfaceWithFormatFrom
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ifstream
|
||||
#include <iostream> // Para cerr, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para char_traits, operator<<, operator+
|
||||
#include <vector> // 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 <SDL2/SDL_error.h> // for SDL_GetError
|
||||
#include <SDL2/SDL_surface.h> // for SDL_CreateRGBSurfaceWithFormatFrom
|
||||
#include <stdint.h> // for uint32_t
|
||||
#include <cstring> // for memcpy, size_t
|
||||
#include <fstream> // for basic_ostream, operator<<, basic_ifstream
|
||||
#include <iostream> // for cerr, cout
|
||||
#include <stdexcept> // for runtime_error
|
||||
#include <string> // for char_traits, operator<<, operator+
|
||||
#include <vector> // 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<Surface> 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<Surface> 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<Uint8> 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<Uint8[]>(rawPixels, std::default_delete<Uint8[]>());
|
||||
// Si el constructor de Surface espera un std::shared_ptr<Uint8[]>,
|
||||
// reservamos un bloque dinámico y copiamos los datos del vector.
|
||||
size_t pixelCount = rawPixels.size();
|
||||
auto pixels = std::shared_ptr<Uint8[]>(new Uint8[pixelCount], std::default_delete<Uint8[]>());
|
||||
std::memcpy(pixels.get(), rawPixels.data(), pixelCount);
|
||||
|
||||
auto surface = std::make_shared<Surface>(w, h, pixels);
|
||||
|
||||
// Actualizar la anchura y altura
|
||||
// Actualizar las dimensiones
|
||||
width_ = w;
|
||||
height_ = h;
|
||||
|
||||
@@ -327,6 +322,7 @@ std::vector<Uint32> Texture::loadPaletteFromFile(const std::string &file_path)
|
||||
{
|
||||
std::vector<Uint32> palette;
|
||||
|
||||
// Abrir el archivo GIF
|
||||
std::ifstream file(file_path, std::ios::binary | std::ios::ate);
|
||||
if (!file)
|
||||
{
|
||||
@@ -338,7 +334,8 @@ std::vector<Uint32> 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<Uint8> buffer(size);
|
||||
@@ -347,17 +344,20 @@ std::vector<Uint32> 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<uint32_t>
|
||||
GIF::Gif gif;
|
||||
std::vector<uint32_t> 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;
|
||||
|
||||
Reference in New Issue
Block a user