forked from jaildesigner-jailgames/jaildoctors_dilemma
canviat Options de struct a namespace
This commit is contained in:
@@ -1,316 +1,275 @@
|
||||
#include "core/rendering/gif.hpp"
|
||||
#include <iostream> // Para std::cout
|
||||
#include <cstring> // Para memcpy, size_t
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para allocator, char_traits, operator==, basic_string
|
||||
|
||||
namespace GIF
|
||||
{
|
||||
#include <cstring> // Para memcpy, size_t
|
||||
#include <iostream> // Para std::cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para allocator, char_traits, operator==, basic_string
|
||||
|
||||
// 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)
|
||||
{
|
||||
std::memcpy(dst, buffer, size);
|
||||
buffer += size;
|
||||
namespace GIF {
|
||||
|
||||
// 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) {
|
||||
std::memcpy(dst, buffer, size);
|
||||
buffer += size;
|
||||
}
|
||||
|
||||
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
|
||||
// Verifica que el code_length tenga un rango razonable.
|
||||
if (code_length < 2 || code_length > 12) {
|
||||
throw std::runtime_error("Invalid LZW code length");
|
||||
}
|
||||
|
||||
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out)
|
||||
{
|
||||
// Verifica que el code_length tenga un rango razonable.
|
||||
if (code_length < 2 || code_length > 12)
|
||||
{
|
||||
throw std::runtime_error("Invalid LZW code length");
|
||||
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;
|
||||
|
||||
// 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
|
||||
|
||||
// Bucle principal: procesar el stream comprimido.
|
||||
while (input_length > 0) {
|
||||
int code = 0;
|
||||
// Lee (code_length + 1) bits para formar el código.
|
||||
for (i = 0; i < (code_length + 1); i++) {
|
||||
if (input_length <= 0) {
|
||||
throw std::runtime_error("Unexpected end of input in decompress");
|
||||
}
|
||||
bit = ((*input & mask) != 0) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
if (mask == 0x100) {
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
code |= (bit << i);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
dictionary_ind += 2; // Reservamos espacio para clear y stop codes
|
||||
|
||||
// Bucle principal: procesar el stream comprimido.
|
||||
while (input_length > 0)
|
||||
{
|
||||
int code = 0;
|
||||
// Lee (code_length + 1) bits para formar el código.
|
||||
for (i = 0; i < (code_length + 1); i++)
|
||||
{
|
||||
if (input_length <= 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected end of input in decompress");
|
||||
}
|
||||
bit = ((*input & mask) != 0) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
if (mask == 0x100)
|
||||
{
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
code |= (bit << i);
|
||||
if (prev > -1 && code_length < 12) {
|
||||
if (code > dictionary_ind) {
|
||||
std::cerr << "code = " << std::hex << code
|
||||
<< ", but dictionary_ind = " << dictionary_ind << std::endl;
|
||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||
}
|
||||
|
||||
if (code == clear_code)
|
||||
{
|
||||
// Reinicia el diccionario.
|
||||
code_length = reset_code_length;
|
||||
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));
|
||||
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::cerr << "code = " << std::hex << code
|
||||
<< ", but dictionary_ind = " << dictionary_ind << std::endl;
|
||||
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::cerr << "Invalid LZW code " << code
|
||||
<< ", dictionary size " << dictionary.size() << std::endl;
|
||||
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::cerr << "Internal error; self-reference detected." << std::endl;
|
||||
throw std::runtime_error("Internal error in decompress: 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;
|
||||
prev = code;
|
||||
|
||||
// Verifica que 'code' sea un índice válido antes de usarlo.
|
||||
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
|
||||
std::cerr << "Invalid LZW code " << code
|
||||
<< ", dictionary size " << dictionary.size() << std::endl;
|
||||
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::cerr << "Internal error; self-reference detected." << std::endl;
|
||||
throw std::runtime_error("Internal error in decompress: 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++;
|
||||
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 data;
|
||||
}
|
||||
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.");
|
||||
}
|
||||
|
||||
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));
|
||||
// Leer el Screen Descriptor (7 bytes, empaquetado sin padding)
|
||||
ScreenDescriptor screen_descriptor;
|
||||
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
|
||||
|
||||
uint8_t lzw_code_size;
|
||||
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
||||
// Asigna ancho y alto
|
||||
w = screen_descriptor.width;
|
||||
h = screen_descriptor.height;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
// 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
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
// 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
|
||||
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)
|
||||
{
|
||||
while (subBlockSize != 0) {
|
||||
buffer += subBlockSize;
|
||||
subBlockSize = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APPLICATION_EXTENSION: // 0xFF
|
||||
case COMMENT_EXTENSION: // 0xFE
|
||||
case PLAINTEXT_EXTENSION: // 0x01
|
||||
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)
|
||||
{
|
||||
while (subBlockSize != 0) {
|
||||
buffer += subBlockSize;
|
||||
subBlockSize = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
std::cerr << "Unrecognized block type " << std::hex << static_cast<int>(block_type) << std::endl;
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
block_type = *buffer++;
|
||||
} 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 {
|
||||
std::cerr << "Unrecognized block type " << std::hex << static_cast<int>(block_type) << std::endl;
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>{};
|
||||
block_type = *buffer++;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h)
|
||||
{
|
||||
return processGifStream(buffer, w, h);
|
||||
}
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
|
||||
} // namespace GIF
|
||||
std::vector<uint8_t> Gif::loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) {
|
||||
return processGifStream(buffer, w, h);
|
||||
}
|
||||
|
||||
} // namespace GIF
|
||||
|
||||
@@ -1,102 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // Para uint8_t, uint16_t, uint32_t
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para uint8_t, uint16_t, uint32_t
|
||||
#include <vector> // Para vector
|
||||
|
||||
namespace GIF
|
||||
{
|
||||
namespace GIF {
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ScreenDescriptor
|
||||
{
|
||||
struct ScreenDescriptor {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t fields;
|
||||
uint8_t background_color_index;
|
||||
uint8_t pixel_aspect_ratio;
|
||||
};
|
||||
};
|
||||
|
||||
struct RGB
|
||||
{
|
||||
struct RGB {
|
||||
uint8_t r, g, b;
|
||||
};
|
||||
};
|
||||
|
||||
struct ImageDescriptor
|
||||
{
|
||||
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 DictionaryEntry
|
||||
{
|
||||
struct DictionaryEntry {
|
||||
uint8_t byte;
|
||||
int prev;
|
||||
int len;
|
||||
};
|
||||
};
|
||||
|
||||
struct Extension
|
||||
{
|
||||
struct Extension {
|
||||
uint8_t extension_code;
|
||||
uint8_t block_size;
|
||||
};
|
||||
};
|
||||
|
||||
struct GraphicControlExtension
|
||||
{
|
||||
struct GraphicControlExtension {
|
||||
uint8_t fields;
|
||||
uint16_t delay_time;
|
||||
uint8_t transparent_color_index;
|
||||
};
|
||||
};
|
||||
|
||||
struct ApplicationExtension
|
||||
{
|
||||
struct ApplicationExtension {
|
||||
uint8_t application_id[8];
|
||||
uint8_t version[3];
|
||||
};
|
||||
};
|
||||
|
||||
struct PlaintextExtension
|
||||
{
|
||||
struct PlaintextExtension {
|
||||
uint16_t left, top, width, height;
|
||||
uint8_t cell_width, cell_height;
|
||||
uint8_t foreground_color, background_color;
|
||||
};
|
||||
};
|
||||
|
||||
class Gif
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
};
|
||||
std::vector<uint8_t> processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h);
|
||||
};
|
||||
|
||||
} // namespace GIF
|
||||
} // namespace GIF
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "core/rendering/opengl/opengl_shader.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
@@ -40,12 +41,12 @@ bool OpenGLShader::initGLExtensions() {
|
||||
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray");
|
||||
|
||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram && glDeleteProgram && glGetUniformLocation && glUniform2f &&
|
||||
glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays &&
|
||||
glGenBuffers && glBindBuffer && glBufferData && glDeleteBuffers &&
|
||||
glVertexAttribPointer && glEnableVertexAttribArray;
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram && glDeleteProgram && glGetUniformLocation && glUniform2f &&
|
||||
glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays &&
|
||||
glGenBuffers && glBindBuffer && glBufferData && glDeleteBuffers &&
|
||||
glVertexAttribPointer && glEnableVertexAttribArray;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -53,14 +54,16 @@ void OpenGLShader::checkGLError(const char* operation) {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error OpenGL en %s: 0x%x", operation, error);
|
||||
"Error OpenGL en %s: 0x%x",
|
||||
operation,
|
||||
error);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint OpenGLShader::compileShader(const std::string& source, GLenum shader_type) {
|
||||
if (source.empty()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"ERROR: El código fuente del shader está vacío");
|
||||
"ERROR: El código fuente del shader está vacío");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -83,14 +86,15 @@ GLuint OpenGLShader::compileShader(const std::string& source, GLenum shader_type
|
||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled);
|
||||
if (compiled != GL_TRUE) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error en compilación del shader");
|
||||
"Error en compilación del shader");
|
||||
GLint log_length;
|
||||
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if (log_length > 0) {
|
||||
std::vector<char> log(log_length);
|
||||
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Log de compilación: %s", log.data());
|
||||
"Log de compilación: %s",
|
||||
log.data());
|
||||
}
|
||||
glDeleteShader(shader_id);
|
||||
return 0;
|
||||
@@ -103,7 +107,7 @@ GLuint OpenGLShader::linkProgram(GLuint vertex_shader, GLuint fragment_shader) {
|
||||
GLuint program = glCreateProgram();
|
||||
if (program == 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error al crear programa de shaders");
|
||||
"Error al crear programa de shaders");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -120,14 +124,15 @@ GLuint OpenGLShader::linkProgram(GLuint vertex_shader, GLuint fragment_shader) {
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &linked);
|
||||
if (linked != GL_TRUE) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error al enlazar programa");
|
||||
"Error al enlazar programa");
|
||||
GLint log_length;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if (log_length > 0) {
|
||||
std::vector<char> log(log_length);
|
||||
glGetProgramInfoLog(program, log_length, &log_length, log.data());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Log de enlace: %s", log.data());
|
||||
"Log de enlace: %s",
|
||||
log.data());
|
||||
}
|
||||
glDeleteProgram(program);
|
||||
return 0;
|
||||
@@ -144,16 +149,32 @@ void OpenGLShader::createQuadGeometry() {
|
||||
// Formato: x, y, u, v
|
||||
float vertices[] = {
|
||||
// Posición // TexCoords
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, // Inferior izquierda
|
||||
1.0f, -1.0f, 1.0f, 0.0f, // Inferior derecha
|
||||
1.0f, 1.0f, 1.0f, 1.0f, // Superior derecha
|
||||
-1.0f, 1.0f, 0.0f, 1.0f // Superior izquierda
|
||||
-1.0f,
|
||||
-1.0f,
|
||||
0.0f,
|
||||
0.0f, // Inferior izquierda
|
||||
1.0f,
|
||||
-1.0f,
|
||||
1.0f,
|
||||
0.0f, // Inferior derecha
|
||||
1.0f,
|
||||
1.0f,
|
||||
1.0f,
|
||||
1.0f, // Superior derecha
|
||||
-1.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f // Superior izquierda
|
||||
};
|
||||
|
||||
// Índices para dibujar el quad con dos triángulos
|
||||
unsigned int indices[] = {
|
||||
0, 1, 2, // Primer triángulo
|
||||
2, 3, 0 // Segundo triángulo
|
||||
0,
|
||||
1,
|
||||
2, // Primer triángulo
|
||||
2,
|
||||
3,
|
||||
0 // Segundo triángulo
|
||||
};
|
||||
|
||||
// Generar y configurar VAO
|
||||
@@ -207,7 +228,7 @@ GLuint OpenGLShader::getTextureID(SDL_Texture* texture) {
|
||||
|
||||
if (texture_id == 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"No se pudo obtener ID de textura OpenGL, usando 1 por defecto");
|
||||
"No se pudo obtener ID de textura OpenGL, usando 1 por defecto");
|
||||
texture_id = 1;
|
||||
}
|
||||
|
||||
@@ -215,16 +236,16 @@ GLuint OpenGLShader::getTextureID(SDL_Texture* texture) {
|
||||
}
|
||||
|
||||
bool OpenGLShader::init(SDL_Window* window,
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) {
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) {
|
||||
window_ = window;
|
||||
back_buffer_ = texture;
|
||||
renderer_ = SDL_GetRenderer(window);
|
||||
|
||||
if (!renderer_) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error: No se pudo obtener el renderer");
|
||||
"Error: No se pudo obtener el renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -233,14 +254,18 @@ bool OpenGLShader::init(SDL_Window* window,
|
||||
SDL_GetTextureSize(back_buffer_, &texture_width_, &texture_height_);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Inicializando shaders: ventana=%dx%d, textura=%.0fx%.0f",
|
||||
window_width_, window_height_, texture_width_, texture_height_);
|
||||
"Inicializando shaders: ventana=%dx%d, textura=%.0fx%.0f",
|
||||
window_width_,
|
||||
window_height_,
|
||||
texture_width_,
|
||||
texture_height_);
|
||||
|
||||
// Verificar que es OpenGL
|
||||
const char* renderer_name = SDL_GetRendererName(renderer_);
|
||||
if (!renderer_name || strncmp(renderer_name, "opengl", 6) != 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Renderer no es OpenGL: %s", renderer_name ? renderer_name : "unknown");
|
||||
"Renderer no es OpenGL: %s",
|
||||
renderer_name ? renderer_name : "unknown");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -248,7 +273,7 @@ bool OpenGLShader::init(SDL_Window* window,
|
||||
// Inicializar extensiones OpenGL en Windows/Linux
|
||||
if (!initGLExtensions()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error al inicializar extensiones OpenGL");
|
||||
"Error al inicializar extensiones OpenGL");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -265,7 +290,7 @@ bool OpenGLShader::init(SDL_Window* window,
|
||||
|
||||
if (vertex_shader == 0 || fragment_shader == 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error al compilar shaders");
|
||||
"Error al compilar shaders");
|
||||
if (vertex_shader != 0) glDeleteShader(vertex_shader);
|
||||
if (fragment_shader != 0) glDeleteShader(fragment_shader);
|
||||
return false;
|
||||
@@ -280,7 +305,7 @@ bool OpenGLShader::init(SDL_Window* window,
|
||||
|
||||
if (program_id_ == 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error al crear programa de shaders");
|
||||
"Error al crear programa de shaders");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -292,19 +317,20 @@ bool OpenGLShader::init(SDL_Window* window,
|
||||
texture_size_location_ = glGetUniformLocation(program_id_, "TextureSize");
|
||||
if (texture_size_location_ != -1) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Configurando TextureSize uniform: %.0fx%.0f",
|
||||
texture_width_, texture_height_);
|
||||
"Configurando TextureSize uniform: %.0fx%.0f",
|
||||
texture_width_,
|
||||
texture_height_);
|
||||
glUniform2f(texture_size_location_, texture_width_, texture_height_);
|
||||
checkGLError("glUniform2f(TextureSize)");
|
||||
} else {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Uniform 'TextureSize' no encontrado en shader");
|
||||
"Uniform 'TextureSize' no encontrado en shader");
|
||||
}
|
||||
glUseProgram(0);
|
||||
|
||||
is_initialized_ = true;
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"** OpenGL 3.3 Shader Backend inicializado correctamente");
|
||||
"** OpenGL 3.3 Shader Backend inicializado correctamente");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -459,4 +485,4 @@ void OpenGLShader::cleanup() {
|
||||
back_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -19,80 +19,80 @@ namespace Rendering {
|
||||
* - Shaders GLSL #version 330 core
|
||||
*/
|
||||
class OpenGLShader : public ShaderBackend {
|
||||
public:
|
||||
OpenGLShader() = default;
|
||||
~OpenGLShader() override;
|
||||
public:
|
||||
OpenGLShader() = default;
|
||||
~OpenGLShader() override;
|
||||
|
||||
bool init(SDL_Window* window,
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) override;
|
||||
bool init(SDL_Window* window,
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) override;
|
||||
|
||||
void render() override;
|
||||
void setTextureSize(float width, float height) override;
|
||||
void cleanup() override;
|
||||
bool isHardwareAccelerated() const override { return is_initialized_; }
|
||||
void render() override;
|
||||
void setTextureSize(float width, float height) override;
|
||||
void cleanup() override;
|
||||
bool isHardwareAccelerated() const override { return is_initialized_; }
|
||||
|
||||
private:
|
||||
// Funciones auxiliares
|
||||
bool initGLExtensions();
|
||||
GLuint compileShader(const std::string& source, GLenum shader_type);
|
||||
GLuint linkProgram(GLuint vertex_shader, GLuint fragment_shader);
|
||||
void createQuadGeometry();
|
||||
GLuint getTextureID(SDL_Texture* texture);
|
||||
void checkGLError(const char* operation);
|
||||
private:
|
||||
// Funciones auxiliares
|
||||
bool initGLExtensions();
|
||||
GLuint compileShader(const std::string& source, GLenum shader_type);
|
||||
GLuint linkProgram(GLuint vertex_shader, GLuint fragment_shader);
|
||||
void createQuadGeometry();
|
||||
GLuint getTextureID(SDL_Texture* texture);
|
||||
void checkGLError(const char* operation);
|
||||
|
||||
// Estado SDL
|
||||
SDL_Window* window_ = nullptr;
|
||||
SDL_Renderer* renderer_ = nullptr;
|
||||
SDL_Texture* back_buffer_ = nullptr;
|
||||
// Estado SDL
|
||||
SDL_Window* window_ = nullptr;
|
||||
SDL_Renderer* renderer_ = nullptr;
|
||||
SDL_Texture* back_buffer_ = nullptr;
|
||||
|
||||
// Estado OpenGL
|
||||
GLuint program_id_ = 0;
|
||||
GLuint vao_ = 0; // Vertex Array Object
|
||||
GLuint vbo_ = 0; // Vertex Buffer Object
|
||||
GLuint ebo_ = 0; // Element Buffer Object
|
||||
// Estado OpenGL
|
||||
GLuint program_id_ = 0;
|
||||
GLuint vao_ = 0; // Vertex Array Object
|
||||
GLuint vbo_ = 0; // Vertex Buffer Object
|
||||
GLuint ebo_ = 0; // Element Buffer Object
|
||||
|
||||
// Ubicaciones de uniforms
|
||||
GLint texture_size_location_ = -1;
|
||||
// Ubicaciones de uniforms
|
||||
GLint texture_size_location_ = -1;
|
||||
|
||||
// Tamaños
|
||||
int window_width_ = 0;
|
||||
int window_height_ = 0;
|
||||
float texture_width_ = 0.0f;
|
||||
float texture_height_ = 0.0f;
|
||||
// Tamaños
|
||||
int window_width_ = 0;
|
||||
int window_height_ = 0;
|
||||
float texture_width_ = 0.0f;
|
||||
float texture_height_ = 0.0f;
|
||||
|
||||
// Estado
|
||||
bool is_initialized_ = false;
|
||||
// Estado
|
||||
bool is_initialized_ = false;
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Punteros a funciones OpenGL en Windows/Linux
|
||||
PFNGLCREATESHADERPROC glCreateShader = nullptr;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
|
||||
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
|
||||
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
|
||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
|
||||
PFNGLUNIFORM2FPROC glUniform2f = nullptr;
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
|
||||
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
|
||||
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
|
||||
PFNGLBUFFERDATAPROC glBufferData = nullptr;
|
||||
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
|
||||
// Punteros a funciones OpenGL en Windows/Linux
|
||||
PFNGLCREATESHADERPROC glCreateShader = nullptr;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
|
||||
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
|
||||
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
|
||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
|
||||
PFNGLUNIFORM2FPROC glUniform2f = nullptr;
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
|
||||
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
|
||||
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
|
||||
PFNGLBUFFERDATAPROC glBufferData = nullptr;
|
||||
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
#include <iterator> // Para istreambuf_iterator, operator==
|
||||
#include <string> // Para char_traits, string, operator+, operator==
|
||||
|
||||
#include "core/resources/asset.hpp" // Para Asset, AssetType
|
||||
#include "core/input/mouse.hpp" // Para updateCursorVisibility
|
||||
#include "game/gameplay/options.hpp" // Para Options, options, OptionsVideo, Border
|
||||
#include "core/input/mouse.hpp" // Para updateCursorVisibility
|
||||
#include "core/rendering/opengl/opengl_shader.hpp" // Para OpenGLShader
|
||||
#include "core/resources/resource.hpp" // Para Resource
|
||||
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
#include "core/rendering/surface.hpp" // Para Surface, readPalFile
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
#include "core/resources/asset.hpp" // Para Asset, AssetType
|
||||
#include "core/resources/resource.hpp" // Para Resource
|
||||
#include "game/gameplay/options.hpp" // Para Options, options, OptionsVideo, Border
|
||||
#include "game/ui/notifier.hpp" // Para Notifier
|
||||
|
||||
// [SINGLETON]
|
||||
@@ -43,40 +43,40 @@ Screen::Screen()
|
||||
initSDLVideo();
|
||||
|
||||
// Ajusta los tamaños
|
||||
game_surface_dstrect_ = {options.video.border.width, options.video.border.height, options.game.width, options.game.height};
|
||||
//adjustWindowSize();
|
||||
current_palette_ = findPalette(options.video.palette);
|
||||
game_surface_dstrect_ = {Options::video.border.width, Options::video.border.height, Options::game.width, Options::game.height};
|
||||
// adjustWindowSize();
|
||||
current_palette_ = findPalette(Options::video.palette);
|
||||
|
||||
// Define el color del borde para el modo de pantalla completa
|
||||
border_color_ = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
|
||||
// Crea la textura donde se dibujan los graficos del juego
|
||||
game_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, options.game.width, options.game.height);
|
||||
game_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Options::game.width, Options::game.height);
|
||||
if (!game_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Error: game_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
SDL_SetTextureScaleMode(game_texture_, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
// Crea la textura donde se dibuja el borde que rodea el area de juego
|
||||
border_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, options.game.width + options.video.border.width * 2, options.game.height + options.video.border.height * 2);
|
||||
border_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, Options::game.width + Options::video.border.width * 2, Options::game.height + Options::video.border.height * 2);
|
||||
if (!border_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Error: border_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
SDL_SetTextureScaleMode(border_texture_, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
// Crea la surface donde se dibujan los graficos del juego
|
||||
game_surface_ = std::make_shared<Surface>(options.game.width, options.game.height);
|
||||
game_surface_ = std::make_shared<Surface>(Options::game.width, Options::game.height);
|
||||
game_surface_->setPalette(readPalFile(palettes_.at(current_palette_)));
|
||||
game_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Crea la surface para el borde de colores
|
||||
border_surface_ = std::make_shared<Surface>(options.game.width + options.video.border.width * 2, options.game.height + options.video.border.height * 2);
|
||||
border_surface_ = std::make_shared<Surface>(Options::game.width + Options::video.border.width * 2, Options::game.height + Options::video.border.height * 2);
|
||||
border_surface_->setPalette(readPalFile(palettes_.at(current_palette_)));
|
||||
border_surface_->clear(border_color_);
|
||||
|
||||
@@ -127,29 +127,29 @@ void Screen::render() {
|
||||
// Establece el modo de video
|
||||
void Screen::setVideoMode(bool mode) {
|
||||
// Actualiza las opciones
|
||||
options.video.fullscreen = mode;
|
||||
Options::video.fullscreen = mode;
|
||||
|
||||
// Configura el modo de pantalla y ajusta la ventana
|
||||
SDL_SetWindowFullscreen(window_, options.video.fullscreen);
|
||||
SDL_SetWindowFullscreen(window_, Options::video.fullscreen);
|
||||
adjustWindowSize();
|
||||
adjustRenderLogicalSize();
|
||||
}
|
||||
|
||||
// Camibia entre pantalla completa y ventana
|
||||
void Screen::toggleVideoMode() {
|
||||
options.video.fullscreen = !options.video.fullscreen;
|
||||
setVideoMode(options.video.fullscreen);
|
||||
Options::video.fullscreen = !Options::video.fullscreen;
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Reduce el tamaño de la ventana
|
||||
bool Screen::decWindowZoom() {
|
||||
if (options.video.fullscreen == 0) {
|
||||
const int PREVIOUS_ZOOM = options.window.zoom;
|
||||
--options.window.zoom;
|
||||
options.window.zoom = std::max(options.window.zoom, 1);
|
||||
if (Options::video.fullscreen == 0) {
|
||||
const int PREVIOUS_ZOOM = Options::window.zoom;
|
||||
--Options::window.zoom;
|
||||
Options::window.zoom = std::max(Options::window.zoom, 1);
|
||||
|
||||
if (options.window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(options.video.fullscreen);
|
||||
if (Options::window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -159,13 +159,13 @@ bool Screen::decWindowZoom() {
|
||||
|
||||
// Aumenta el tamaño de la ventana
|
||||
bool Screen::incWindowZoom() {
|
||||
if (options.video.fullscreen == 0) {
|
||||
const int PREVIOUS_ZOOM = options.window.zoom;
|
||||
++options.window.zoom;
|
||||
options.window.zoom = std::min(options.window.zoom, options.window.max_zoom);
|
||||
if (Options::video.fullscreen == 0) {
|
||||
const int PREVIOUS_ZOOM = Options::window.zoom;
|
||||
++Options::window.zoom;
|
||||
Options::window.zoom = std::min(Options::window.zoom, Options::window.max_zoom);
|
||||
|
||||
if (options.window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(options.video.fullscreen);
|
||||
if (Options::window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -181,8 +181,8 @@ void Screen::setBorderColor(Uint8 color) {
|
||||
|
||||
// Cambia entre borde visible y no visible
|
||||
void Screen::toggleBorder() {
|
||||
options.video.border.enabled = !options.video.border.enabled;
|
||||
setVideoMode(options.video.fullscreen);
|
||||
Options::video.border.enabled = !Options::video.border.enabled;
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
initShaders();
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ void Screen::renderNotifications() {
|
||||
|
||||
// Cambia el estado de los shaders
|
||||
void Screen::toggleShaders() {
|
||||
options.video.shaders = !options.video.shaders;
|
||||
Options::video.shaders = !Options::video.shaders;
|
||||
initShaders();
|
||||
}
|
||||
|
||||
@@ -208,28 +208,28 @@ void Screen::update() {
|
||||
|
||||
// Calcula el tamaño de la ventana
|
||||
void Screen::adjustWindowSize() {
|
||||
window_width_ = options.game.width + (options.video.border.enabled ? options.video.border.width * 2 : 0);
|
||||
window_height_ = options.game.height + (options.video.border.enabled ? options.video.border.height * 2 : 0);
|
||||
window_width_ = Options::game.width + (Options::video.border.enabled ? Options::video.border.width * 2 : 0);
|
||||
window_height_ = Options::game.height + (Options::video.border.enabled ? Options::video.border.height * 2 : 0);
|
||||
|
||||
// Establece el nuevo tamaño
|
||||
if (options.video.fullscreen == 0) {
|
||||
if (Options::video.fullscreen == 0) {
|
||||
int old_width, old_height;
|
||||
SDL_GetWindowSize(window_, &old_width, &old_height);
|
||||
|
||||
int old_pos_x, old_pos_y;
|
||||
SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y);
|
||||
|
||||
const int NEW_POS_X = old_pos_x + (old_width - (window_width_ * options.window.zoom)) / 2;
|
||||
const int NEW_POS_Y = old_pos_y + (old_height - (window_height_ * options.window.zoom)) / 2;
|
||||
const int NEW_POS_X = old_pos_x + (old_width - (window_width_ * Options::window.zoom)) / 2;
|
||||
const int NEW_POS_Y = old_pos_y + (old_height - (window_height_ * Options::window.zoom)) / 2;
|
||||
|
||||
SDL_SetWindowSize(window_, window_width_ * options.window.zoom, window_height_ * options.window.zoom);
|
||||
SDL_SetWindowSize(window_, window_width_ * Options::window.zoom, window_height_ * Options::window.zoom);
|
||||
SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS), std::max(NEW_POS_Y, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Ajusta el tamaño lógico del renderizador
|
||||
void Screen::adjustRenderLogicalSize() {
|
||||
SDL_SetRenderLogicalPresentation(renderer_, window_width_, window_height_, options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
SDL_SetRenderLogicalPresentation(renderer_, window_width_, window_height_, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
}
|
||||
|
||||
// Establece el renderizador para las surfaces
|
||||
@@ -263,16 +263,16 @@ void Screen::setPalete() {
|
||||
game_surface_->loadPalette(Resource::get()->getPalette(palettes_.at(current_palette_)));
|
||||
border_surface_->loadPalette(Resource::get()->getPalette(palettes_.at(current_palette_)));
|
||||
|
||||
options.video.palette = palettes_.at(current_palette_);
|
||||
Options::video.palette = palettes_.at(current_palette_);
|
||||
|
||||
// Eliminar ".gif"
|
||||
size_t pos = options.video.palette.find(".pal");
|
||||
size_t pos = Options::video.palette.find(".pal");
|
||||
if (pos != std::string::npos) {
|
||||
options.video.palette.erase(pos, 4);
|
||||
Options::video.palette.erase(pos, 4);
|
||||
}
|
||||
|
||||
// Convertir a mayúsculas
|
||||
std::transform(options.video.palette.begin(), options.video.palette.end(), options.video.palette.begin(), ::toupper);
|
||||
std::transform(Options::video.palette.begin(), Options::video.palette.end(), Options::video.palette.begin(), ::toupper);
|
||||
}
|
||||
|
||||
// Extrae los nombres de las paletas
|
||||
@@ -284,7 +284,7 @@ void Screen::processPaletteList() {
|
||||
|
||||
// Copia la surface a la textura
|
||||
void Screen::surfaceToTexture() {
|
||||
if (options.video.border.enabled) {
|
||||
if (Options::video.border.enabled) {
|
||||
border_surface_->copyToTexture(renderer_, border_texture_);
|
||||
game_surface_->copyToTexture(renderer_, border_texture_, nullptr, &game_surface_dstrect_);
|
||||
} else {
|
||||
@@ -294,9 +294,9 @@ void Screen::surfaceToTexture() {
|
||||
|
||||
// Copia la textura al renderizador
|
||||
void Screen::textureToRenderer() {
|
||||
SDL_Texture* texture_to_render = options.video.border.enabled ? border_texture_ : game_texture_;
|
||||
SDL_Texture* texture_to_render = Options::video.border.enabled ? border_texture_ : game_texture_;
|
||||
|
||||
if (options.video.shaders && shader_backend_) {
|
||||
if (Options::video.shaders && shader_backend_) {
|
||||
shader_backend_->render();
|
||||
} else {
|
||||
SDL_SetRenderTarget(renderer_, nullptr);
|
||||
@@ -333,7 +333,7 @@ void Screen::renderInfo() {
|
||||
|
||||
// FPS
|
||||
const std::string FPS_TEXT = std::to_string(fps_.lastValue) + " FPS";
|
||||
text->writeColored(options.game.width - text->lenght(FPS_TEXT), 0, FPS_TEXT, color);
|
||||
text->writeColored(Options::game.width - text->lenght(FPS_TEXT), 0, FPS_TEXT, color);
|
||||
|
||||
// Resolution
|
||||
text->writeColored(0, 0, info_resolution_, color);
|
||||
@@ -344,13 +344,13 @@ void Screen::renderInfo() {
|
||||
void Screen::clearSurface(Uint8 index) { game_surface_->clear(index); }
|
||||
|
||||
// Establece el tamaño del borde
|
||||
void Screen::setBorderWidth(int width) { options.video.border.width = width; }
|
||||
void Screen::setBorderWidth(int width) { Options::video.border.width = width; }
|
||||
|
||||
// Establece el tamaño del borde
|
||||
void Screen::setBorderHeight(int height) { options.video.border.height = height; }
|
||||
void Screen::setBorderHeight(int height) { Options::video.border.height = height; }
|
||||
|
||||
// Establece si se ha de ver el borde en el modo ventana
|
||||
void Screen::setBorderEnabled(bool value) { options.video.border.enabled = value; }
|
||||
void Screen::setBorderEnabled(bool value) { Options::video.border.enabled = value; }
|
||||
|
||||
// Muestra la ventana
|
||||
void Screen::show() { SDL_ShowWindow(window_); }
|
||||
@@ -366,8 +366,8 @@ void Screen::toggleDebugInfo() { show_debug_info_ = !show_debug_info_; }
|
||||
|
||||
// Alterna entre activar y desactivar el escalado entero
|
||||
void Screen::toggleIntegerScale() {
|
||||
options.video.integer_scale = !options.video.integer_scale;
|
||||
SDL_SetRenderLogicalPresentation(renderer_, options.game.width, options.game.height, options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
Options::video.integer_scale = !Options::video.integer_scale;
|
||||
SDL_SetRenderLogicalPresentation(renderer_, Options::game.width, Options::game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
}
|
||||
|
||||
// Getters
|
||||
@@ -436,13 +436,13 @@ void Screen::loadShaders() {
|
||||
// Inicializa los shaders
|
||||
void Screen::initShaders() {
|
||||
#ifndef __APPLE__
|
||||
if (options.video.shaders) {
|
||||
if (Options::video.shaders) {
|
||||
loadShaders();
|
||||
if (!shader_backend_) {
|
||||
shader_backend_ = std::make_unique<Rendering::OpenGLShader>();
|
||||
}
|
||||
shader_backend_->init(window_, options.video.border.enabled ? border_texture_ : game_texture_, vertex_shader_source_, fragment_shader_source_);
|
||||
//shader_backend_->init(window_, shaders_texture_, vertex_shader_source_, fragment_shader_source_);
|
||||
shader_backend_->init(window_, Options::video.border.enabled ? border_texture_ : game_texture_, vertex_shader_source_, fragment_shader_source_);
|
||||
// shader_backend_->init(window_, shaders_texture_, vertex_shader_source_, fragment_shader_source_);
|
||||
}
|
||||
#else
|
||||
// En macOS, OpenGL está deprecated y rinde mal
|
||||
@@ -475,23 +475,23 @@ void Screen::getDisplayInfo() {
|
||||
display_monitor_.refresh_rate = static_cast<int>(dm->refresh_rate);
|
||||
|
||||
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
|
||||
options.window.max_zoom = std::min(dm->w / options.game.width, dm->h / options.game.height);
|
||||
options.window.zoom = std::min(options.window.zoom, options.window.max_zoom);
|
||||
Options::window.max_zoom = std::min(dm->w / Options::game.width, dm->h / Options::game.height);
|
||||
Options::window.zoom = std::min(Options::window.zoom, Options::window.max_zoom);
|
||||
|
||||
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Current display mode: %dx%d @ %dHz", static_cast<int>(dm->w), static_cast<int>(dm->h), static_cast<int>(dm->refresh_rate));
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Window resolution: %dx%d x%d", static_cast<int>(options.game.width), static_cast<int>(options.game.height), options.window.zoom);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Window resolution: %dx%d x%d", static_cast<int>(Options::game.width), static_cast<int>(Options::game.height), Options::window.zoom);
|
||||
|
||||
options.video.info = std::to_string(static_cast<int>(dm->w)) + "x" +
|
||||
Options::video.info = std::to_string(static_cast<int>(dm->w)) + "x" +
|
||||
std::to_string(static_cast<int>(dm->h)) + " @ " +
|
||||
std::to_string(static_cast<int>(dm->refresh_rate)) + " Hz";
|
||||
|
||||
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
|
||||
const int MAX_ZOOM = std::min(dm->w / options.game.width, (dm->h - WINDOWS_DECORATIONS) / options.game.height);
|
||||
const int MAX_ZOOM = std::min(dm->w / Options::game.width, (dm->h - WINDOWS_DECORATIONS) / Options::game.height);
|
||||
|
||||
// Normaliza los valores de zoom
|
||||
options.window.zoom = std::min(options.window.zoom, MAX_ZOOM);
|
||||
Options::window.zoom = std::min(Options::window.zoom, MAX_ZOOM);
|
||||
|
||||
SDL_free(displays);
|
||||
}
|
||||
@@ -536,17 +536,17 @@ auto Screen::initSDLVideo() -> bool {
|
||||
#endif
|
||||
|
||||
// Crear ventana
|
||||
const auto WINDOW_WIDTH = options.video.border.enabled ? options.game.width + options.video.border.width * 2 : options.game.width;
|
||||
const auto WINDOW_HEIGHT = options.video.border.enabled ? options.game.height + options.video.border.height * 2 : options.game.height;
|
||||
const auto WINDOW_WIDTH = Options::video.border.enabled ? Options::game.width + Options::video.border.width * 2 : Options::game.width;
|
||||
const auto WINDOW_HEIGHT = Options::video.border.enabled ? Options::game.height + Options::video.border.height * 2 : Options::game.height;
|
||||
#ifdef __APPLE__
|
||||
SDL_WindowFlags window_flags = SDL_WINDOW_METAL;
|
||||
#else
|
||||
SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL;
|
||||
#endif
|
||||
if (options.video.fullscreen) {
|
||||
if (Options::video.fullscreen) {
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
window_ = SDL_CreateWindow(options.window.caption.c_str(), WINDOW_WIDTH * options.window.zoom, WINDOW_HEIGHT * options.window.zoom, window_flags);
|
||||
window_ = SDL_CreateWindow(Options::window.caption.c_str(), WINDOW_WIDTH * Options::window.zoom, WINDOW_HEIGHT * Options::window.zoom, window_flags);
|
||||
|
||||
if (window_ == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
@@ -569,16 +569,16 @@ auto Screen::initSDLVideo() -> bool {
|
||||
}
|
||||
|
||||
// Configurar renderer
|
||||
const int EXTRA_WIDTH = options.video.border.enabled ? options.video.border.width * 2 : 0;
|
||||
const int EXTRA_HEIGHT = options.video.border.enabled ? options.video.border.height * 2 : 0;
|
||||
const int EXTRA_WIDTH = Options::video.border.enabled ? Options::video.border.width * 2 : 0;
|
||||
const int EXTRA_HEIGHT = Options::video.border.enabled ? Options::video.border.height * 2 : 0;
|
||||
SDL_SetRenderLogicalPresentation(
|
||||
renderer_,
|
||||
options.game.width + EXTRA_WIDTH,
|
||||
options.game.height + EXTRA_HEIGHT,
|
||||
options.video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
Options::game.width + EXTRA_WIDTH,
|
||||
Options::game.height + EXTRA_HEIGHT,
|
||||
Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderVSync(renderer_, options.video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
SDL_SetRenderVSync(renderer_, Options::video.vertical_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Video system initialized successfully");
|
||||
return true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Rendering {
|
||||
@@ -12,44 +13,44 @@ namespace Rendering {
|
||||
* deben cumplir (OpenGL, Metal, Vulkan, etc.)
|
||||
*/
|
||||
class ShaderBackend {
|
||||
public:
|
||||
virtual ~ShaderBackend() = default;
|
||||
public:
|
||||
virtual ~ShaderBackend() = default;
|
||||
|
||||
/**
|
||||
* @brief Inicializa el backend de shaders
|
||||
* @param window Ventana SDL
|
||||
* @param texture Textura de backbuffer a la que aplicar shaders
|
||||
* @param vertex_source Código fuente del vertex shader
|
||||
* @param fragment_source Código fuente del fragment shader
|
||||
* @return true si la inicialización fue exitosa
|
||||
*/
|
||||
virtual bool init(SDL_Window* window,
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) = 0;
|
||||
/**
|
||||
* @brief Inicializa el backend de shaders
|
||||
* @param window Ventana SDL
|
||||
* @param texture Textura de backbuffer a la que aplicar shaders
|
||||
* @param vertex_source Código fuente del vertex shader
|
||||
* @param fragment_source Código fuente del fragment shader
|
||||
* @return true si la inicialización fue exitosa
|
||||
*/
|
||||
virtual bool init(SDL_Window* window,
|
||||
SDL_Texture* texture,
|
||||
const std::string& vertex_source,
|
||||
const std::string& fragment_source) = 0;
|
||||
|
||||
/**
|
||||
* @brief Renderiza la textura con los shaders aplicados
|
||||
*/
|
||||
virtual void render() = 0;
|
||||
/**
|
||||
* @brief Renderiza la textura con los shaders aplicados
|
||||
*/
|
||||
virtual void render() = 0;
|
||||
|
||||
/**
|
||||
* @brief Establece el tamaño de la textura como parámetro del shader
|
||||
* @param width Ancho de la textura
|
||||
* @param height Alto de la textura
|
||||
*/
|
||||
virtual void setTextureSize(float width, float height) = 0;
|
||||
/**
|
||||
* @brief Establece el tamaño de la textura como parámetro del shader
|
||||
* @param width Ancho de la textura
|
||||
* @param height Alto de la textura
|
||||
*/
|
||||
virtual void setTextureSize(float width, float height) = 0;
|
||||
|
||||
/**
|
||||
* @brief Limpia y libera recursos del backend
|
||||
*/
|
||||
virtual void cleanup() = 0;
|
||||
/**
|
||||
* @brief Limpia y libera recursos del backend
|
||||
*/
|
||||
virtual void cleanup() = 0;
|
||||
|
||||
/**
|
||||
* @brief Verifica si el backend está usando aceleración por hardware
|
||||
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
||||
*/
|
||||
virtual bool isHardwareAccelerated() const = 0;
|
||||
/**
|
||||
* @brief Verifica si el backend está usando aceleración por hardware
|
||||
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
||||
*/
|
||||
virtual bool isHardwareAccelerated() const = 0;
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "utils/utils.hpp" // Para printWithDots
|
||||
#include "utils/utils.hpp" // Para printWithDots
|
||||
|
||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||
Animations loadAnimationsFromFile(const std::string& file_path) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/rendering/surface_moving_sprite.hpp" // Para SMovingSprite
|
||||
class Surface; // lines 9-9
|
||||
class Surface; // lines 9-9
|
||||
|
||||
struct AnimationData {
|
||||
std::string name; // Nombre de la animacion
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <memory> // Para shared_ptr
|
||||
|
||||
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
class Surface; // lines 8-8
|
||||
|
||||
// Clase SMovingSprite. Añade movimiento y flip al sprite
|
||||
class SMovingSprite : public SSprite {
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#include <iostream> // Para cerr
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "utils/utils.hpp" // Para getFileName, stringToColor, printWithDots
|
||||
#include "utils/utils.hpp" // Para getFileName, stringToColor, printWithDots
|
||||
|
||||
// Llena una estructuta TextFile desde un fichero
|
||||
std::shared_ptr<TextFile> loadTextFile(const std::string& file_path) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string> // Para string
|
||||
|
||||
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
class Surface; // lines 8-8
|
||||
|
||||
constexpr int TEXT_COLOR = 1;
|
||||
constexpr int TEXT_SHADOW = 2;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
#include "core/rendering/texture.hpp"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <iostream> // Para basic_ostream, operator<<, endl, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
@@ -64,7 +64,7 @@ bool Texture::loadFromFile(const std::string& file_path) {
|
||||
SDL_Texture* newTexture = nullptr;
|
||||
|
||||
// Carga la imagen desde una ruta específica
|
||||
auto *loaded_surface = SDL_CreateSurfaceFrom(width, height, pixel_format, static_cast<void *>(data), pitch);
|
||||
auto* loaded_surface = SDL_CreateSurfaceFrom(width, height, pixel_format, static_cast<void*>(data), pitch);
|
||||
if (loaded_surface == nullptr) {
|
||||
std::cout << "Unable to load image " << file_path << std::endl;
|
||||
} else {
|
||||
|
||||
@@ -14,8 +14,8 @@ class Texture {
|
||||
|
||||
// Variables
|
||||
std::string path_; // Ruta de la imagen de la textura
|
||||
float width_ = 0.0F; // Ancho de la imagen
|
||||
float height_ = 0.0F; // Alto de la imagen
|
||||
float width_ = 0.0F; // Ancho de la imagen
|
||||
float height_ = 0.0F; // Alto de la imagen
|
||||
std::vector<std::vector<Uint32>> palettes_; // Vector con las diferentes paletas
|
||||
|
||||
// Libera la memoria de la textura
|
||||
|
||||
Reference in New Issue
Block a user