pasaeta loca de clang-format (despres m'arrepentiré pero bueno)

This commit is contained in:
2025-07-18 20:01:13 +02:00
parent 734c220fb0
commit dabba41179
112 changed files with 22361 additions and 26474 deletions

View File

@@ -1,249 +1,214 @@
#include "gif.h"
#include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, SDL_LogInfo
#include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, SDL_LogInfo
#include <cstring> // Para memcpy, size_t
#include <stdexcept> // Para runtime_error
#include <string> // Para char_traits, operator==, basic_string, string
namespace GIF
{
inline void readBytes(const uint8_t *&buffer, void *dst, size_t size)
{
std::memcpy(dst, buffer, size);
buffer += size;
namespace GIF {
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) {
if (code_length < 2 || code_length > 12) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length);
throw std::runtime_error("Invalid LZW code length");
}
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out)
{
if (code_length < 2 || code_length > 12)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length);
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;
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;
while (input_length > 0) {
int code = 0;
for (i = 0; i < (code_length + 1); i++) {
if (input_length <= 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress");
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;
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) {
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;
while (input_length > 0)
{
int code = 0;
for (i = 0; i < (code_length + 1); i++)
{
if (input_length <= 0)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress");
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) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LZW error: code (%d) exceeds dictionary_ind (%d)", code, dictionary_ind);
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
}
if (code == clear_code)
{
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)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LZW error: code (%d) exceeds dictionary_ind (%d)", 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;
if (code < 0 || static_cast<size_t>(code) >= dictionary.size())
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code %d, dictionary size %lu", code, static_cast<unsigned long>(dictionary.size()));
throw std::runtime_error("LZW error: invalid code encountered");
}
int curCode = code;
match_len = dictionary[curCode].len;
while (curCode != -1)
{
out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
if (dictionary[curCode].prev == curCode)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected.");
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;
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code %d, dictionary size %lu", code, static_cast<unsigned long>(dictionary.size()));
throw std::runtime_error("LZW error: invalid code encountered");
}
int curCode = code;
match_len = dictionary[curCode].len;
while (curCode != -1) {
out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
if (dictionary[curCode].prev == curCode) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected.");
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;
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) {
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
std::string headerStr(reinterpret_cast<char *>(header), 6);
if (headerStr != "GIF87a" && headerStr != "GIF89a") {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Formato de archivo GIF inválido: %s", headerStr.c_str());
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;
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Procesando GIF con cabecera: %s", headerStr.c_str());
uint8_t lzw_code_size;
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
ScreenDescriptor screen_descriptor;
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
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);
w = screen_descriptor.width;
h = screen_descriptor.height;
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
return uncompressed_data;
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Resolución del GIF: %dx%d", 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;
}
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)
{
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
std::string headerStr(reinterpret_cast<char *>(header), 6);
if (headerStr != "GIF87a" && headerStr != "GIF89a")
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Formato de archivo GIF inválido: %s", headerStr.c_str());
throw std::runtime_error("Formato de archivo GIF inválido.");
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Procesando GIF con cabecera: %s", headerStr.c_str());
ScreenDescriptor screen_descriptor;
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
w = screen_descriptor.width;
h = screen_descriptor.height;
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Resolución del GIF: %dx%d", 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;
}
uint8_t block_type = *buffer++;
while (block_type != TRAILER)
{
if (block_type == EXTENSION_INTRODUCER)
{
uint8_t extension_label = *buffer++;
switch (extension_label)
{
case GRAPHIC_CONTROL:
{
uint8_t block_type = *buffer++;
while (block_type != TRAILER) {
if (block_type == EXTENSION_INTRODUCER) {
uint8_t extension_label = *buffer++;
switch (extension_label) {
case GRAPHIC_CONTROL: {
uint8_t blockSize = *buffer++;
buffer += blockSize;
uint8_t subBlockSize = *buffer++;
while (subBlockSize != 0)
{
while (subBlockSize != 0) {
buffer += subBlockSize;
subBlockSize = *buffer++;
}
@@ -251,51 +216,42 @@ namespace GIF
}
case APPLICATION_EXTENSION:
case COMMENT_EXTENSION:
case PLAINTEXT_EXTENSION:
{
case PLAINTEXT_EXTENSION: {
uint8_t blockSize = *buffer++;
buffer += blockSize;
uint8_t subBlockSize = *buffer++;
while (subBlockSize != 0)
{
while (subBlockSize != 0) {
buffer += subBlockSize;
subBlockSize = *buffer++;
}
break;
}
default:
{
default: {
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)
{
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
}
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type);
return std::vector<uint8_t>{};
}
block_type = *buffer++;
} else if (block_type == IMAGE_DESCRIPTOR) {
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type);
return std::vector<uint8_t>{};
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente.");
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);
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente.");
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

152
source/external/gif.h vendored
View File

@@ -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
{
uint16_t width;
uint16_t height;
uint8_t fields;
uint8_t background_color_index;
uint8_t pixel_aspect_ratio;
};
struct ScreenDescriptor {
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;
};
struct RGB {
uint8_t r, g, b;
};
struct ImageDescriptor
{
uint16_t image_left_position;
uint16_t image_top_position;
uint16_t image_width;
uint16_t image_height;
uint8_t fields;
};
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
{
uint8_t byte;
int prev;
int len;
};
struct DictionaryEntry {
uint8_t byte;
int prev;
int len;
};
struct Extension
{
uint8_t extension_code;
uint8_t block_size;
};
struct Extension {
uint8_t extension_code;
uint8_t block_size;
};
struct GraphicControlExtension
{
uint8_t fields;
uint16_t delay_time;
uint8_t transparent_color_index;
};
struct GraphicControlExtension {
uint8_t fields;
uint16_t delay_time;
uint8_t transparent_color_index;
};
struct ApplicationExtension
{
uint8_t application_id[8];
uint8_t version[3];
};
struct ApplicationExtension {
uint8_t application_id[8];
uint8_t version[3];
};
struct PlaintextExtension
{
uint16_t left, top, width, height;
uint8_t cell_width, cell_height;
uint8_t foreground_color, background_color;
};
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);
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 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);
// 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);
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 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);
};
// 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
} // namespace GIF

View File

@@ -1,26 +1,24 @@
#ifndef JA_USESDLMIXER
#include "jail_audio.h"
#include <SDL3/SDL.h> // Para SDL_AudioFormat, SDL_BindAudioStream, SDL_Se...
#include <stdint.h> // Para uint32_t, uint8_t
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread
#include <stdlib.h> // Para free, malloc
#include <string.h> // Para strcpy, strlen
#include <SDL3/SDL.h> // Para SDL_AudioFormat, SDL_BindAudioStream, SDL_Se...
#include <stdint.h> // Para uint32_t, uint8_t
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread
#include <stdlib.h> // Para free, malloc
#include <string.h> // Para strcpy, strlen
#include "stb_vorbis.h" // Para stb_vorbis_decode_memory
#include "stb_vorbis.h" // Para stb_vorbis_decode_memory
#define JA_MAX_SIMULTANEOUS_CHANNELS 20
#define JA_MAX_GROUPS 2
struct JA_Sound_t
{
struct JA_Sound_t {
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
Uint32 length{0};
Uint8 *buffer{NULL};
};
struct JA_Channel_t
{
struct JA_Channel_t {
JA_Sound_t *sound{nullptr};
int pos{0};
int times{0};
@@ -29,8 +27,7 @@ struct JA_Channel_t
JA_Channel_state state{JA_CHANNEL_FREE};
};
struct JA_Music_t
{
struct JA_Music_t {
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
Uint32 length{0};
Uint8 *buffer{nullptr};
@@ -58,59 +55,43 @@ int fade_start_time;
int fade_duration;
int fade_initial_volume;
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
{
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING)
{
if (fading)
{
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval) {
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) {
if (fading) {
int time = SDL_GetTicks();
if (time > (fade_start_time + fade_duration))
{
if (time > (fade_start_time + fade_duration)) {
fading = false;
JA_StopMusic();
return 30;
}
else
{
} else {
const int time_passed = time - fade_start_time;
const float percent = (float)time_passed / (float)fade_duration;
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent));
}
}
if (current_music->times != 0)
{
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2))
{
if (current_music->times != 0) {
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
}
if (current_music->times > 0)
current_music->times--;
}
else
{
} else {
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0)
JA_StopMusic();
}
}
if (JA_soundEnabled)
{
if (JA_soundEnabled) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
if (channels[i].state == JA_CHANNEL_PLAYING)
{
if (channels[i].times != 0)
{
if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2))
{
if (channels[i].state == JA_CHANNEL_PLAYING) {
if (channels[i].times != 0) {
if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) {
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
if (channels[i].times > 0)
channels[i].times--;
}
}
else
{
} else {
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0)
JA_StopChannel(i);
}
@@ -120,8 +101,7 @@ Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
return 30;
}
void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels)
{
void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) {
#ifdef DEBUG
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
@@ -140,8 +120,7 @@ void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channel
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
}
void JA_Quit()
{
void JA_Quit() {
if (JA_timerID)
SDL_RemoveTimer(JA_timerID);
@@ -150,8 +129,7 @@ void JA_Quit()
sdlAudioDevice = 0;
}
JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
{
JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length) {
JA_Music_t *music = new JA_Music_t();
int chan, samplerate;
@@ -170,8 +148,7 @@ JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
return music;
}
JA_Music_t *JA_LoadMusic(const char *filename)
{
JA_Music_t *JA_LoadMusic(const char *filename) {
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
@@ -191,8 +168,7 @@ JA_Music_t *JA_LoadMusic(const char *filename)
return music;
}
void JA_PlayMusic(JA_Music_t *music, const int loop)
{
void JA_PlayMusic(JA_Music_t *music, const int loop) {
if (!JA_musicEnabled)
return;
@@ -212,15 +188,13 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
// SDL_ResumeAudioStreamDevice(current_music->stream);
}
char *JA_GetMusicFilename(JA_Music_t *music)
{
char *JA_GetMusicFilename(JA_Music_t *music) {
if (!music)
music = current_music;
return music->filename;
}
void JA_PauseMusic()
{
void JA_PauseMusic() {
if (!JA_musicEnabled)
return;
if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -231,8 +205,7 @@ void JA_PauseMusic()
SDL_UnbindAudioStream(current_music->stream);
}
void JA_ResumeMusic()
{
void JA_ResumeMusic() {
if (!JA_musicEnabled)
return;
if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -243,8 +216,7 @@ void JA_ResumeMusic()
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
}
void JA_StopMusic()
{
void JA_StopMusic() {
if (!JA_musicEnabled)
return;
if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -259,8 +231,7 @@ void JA_StopMusic()
current_music->filename = nullptr;
}
void JA_FadeOutMusic(const int milliseconds)
{
void JA_FadeOutMusic(const int milliseconds) {
if (!JA_musicEnabled)
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
@@ -272,8 +243,7 @@ void JA_FadeOutMusic(const int milliseconds)
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState()
{
JA_Music_state JA_GetMusicState() {
if (!JA_musicEnabled)
return JA_MUSIC_DISABLED;
if (!current_music)
@@ -282,8 +252,7 @@ JA_Music_state JA_GetMusicState()
return current_music->state;
}
void JA_DeleteMusic(JA_Music_t *music)
{
void JA_DeleteMusic(JA_Music_t *music) {
if (current_music == music)
current_music = nullptr;
SDL_free(music->buffer);
@@ -292,68 +261,59 @@ void JA_DeleteMusic(JA_Music_t *music)
delete music;
}
float JA_SetMusicVolume(float volume)
{
float JA_SetMusicVolume(float volume) {
JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f);
if (current_music)
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
return JA_musicVolume;
}
void JA_SetMusicPosition(float value)
{
void JA_SetMusicPosition(float value) {
if (!current_music)
return;
current_music->pos = value * current_music->spec.freq;
}
float JA_GetMusicPosition()
{
float JA_GetMusicPosition() {
if (!current_music)
return 0;
return float(current_music->pos) / float(current_music->spec.freq);
}
void JA_EnableMusic(const bool value)
{
void JA_EnableMusic(const bool value) {
if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING))
JA_StopMusic();
JA_musicEnabled = value;
}
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
{
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length) {
JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer;
sound->length = length;
return sound;
}
JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size)
{
JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size) {
JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length);
return sound;
}
JA_Sound_t *JA_LoadSound(const char *filename)
{
JA_Sound_t *JA_LoadSound(const char *filename) {
JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
return sound;
}
int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group)
{
int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group) {
if (!JA_soundEnabled)
return -1;
int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE)
{
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) {
channel++;
}
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS)
@@ -372,8 +332,7 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group)
return channel;
}
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group)
{
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) {
if (!JA_soundEnabled)
return -1;
@@ -393,10 +352,8 @@ int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop,
return channel;
}
void JA_DeleteSound(JA_Sound_t *sound)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
void JA_DeleteSound(JA_Sound_t *sound) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].sound == sound)
JA_StopChannel(i);
}
@@ -404,25 +361,19 @@ void JA_DeleteSound(JA_Sound_t *sound)
delete sound;
}
void JA_PauseChannel(const int channel)
{
void JA_PauseChannel(const int channel) {
if (!JA_soundEnabled)
return;
if (channel == -1)
{
if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PLAYING)
{
if (channels[i].state == JA_CHANNEL_PLAYING) {
channels[i].state = JA_CHANNEL_PAUSED;
// SDL_PauseAudioStreamDevice(channels[i].stream);
SDL_UnbindAudioStream(channels[i].stream);
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
{
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PLAYING) {
channels[channel].state = JA_CHANNEL_PAUSED;
// SDL_PauseAudioStreamDevice(channels[channel].stream);
SDL_UnbindAudioStream(channels[channel].stream);
@@ -430,25 +381,19 @@ void JA_PauseChannel(const int channel)
}
}
void JA_ResumeChannel(const int channel)
{
void JA_ResumeChannel(const int channel) {
if (!JA_soundEnabled)
return;
if (channel == -1)
{
if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PAUSED)
{
if (channels[i].state == JA_CHANNEL_PAUSED) {
channels[i].state = JA_CHANNEL_PLAYING;
// SDL_ResumeAudioStreamDevice(channels[i].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
{
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PAUSED) {
channels[channel].state = JA_CHANNEL_PLAYING;
// SDL_ResumeAudioStreamDevice(channels[channel].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
@@ -456,15 +401,12 @@ void JA_ResumeChannel(const int channel)
}
}
void JA_StopChannel(const int channel)
{
void JA_StopChannel(const int channel) {
if (!JA_soundEnabled)
return;
if (channel == -1)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].state != JA_CHANNEL_FREE)
SDL_DestroyAudioStream(channels[i].stream);
channels[i].stream = nullptr;
@@ -472,9 +414,7 @@ void JA_StopChannel(const int channel)
channels[i].pos = 0;
channels[i].sound = NULL;
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state != JA_CHANNEL_FREE)
SDL_DestroyAudioStream(channels[channel].stream);
channels[channel].stream = nullptr;
@@ -484,8 +424,7 @@ void JA_StopChannel(const int channel)
}
}
JA_Channel_state JA_GetChannelState(const int channel)
{
JA_Channel_state JA_GetChannelState(const int channel) {
if (!JA_soundEnabled)
return JA_SOUND_DISABLED;
@@ -495,11 +434,9 @@ JA_Channel_state JA_GetChannelState(const int channel)
return channels[channel].state;
}
float JA_SetSoundVolume(float volume, const int group)
{
float JA_SetSoundVolume(float volume, const int group) {
const float v = SDL_clamp(volume, 0.0f, 1.0f);
for (int i = 0; i < JA_MAX_GROUPS; ++i)
{
for (int i = 0; i < JA_MAX_GROUPS; ++i) {
if (group == -1 || group == i)
JA_soundVolume[i] = v;
}
@@ -512,18 +449,15 @@ float JA_SetSoundVolume(float volume, const int group)
return v;
}
void JA_EnableSound(const bool value)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
void JA_EnableSound(const bool value) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].state == JA_CHANNEL_PLAYING)
JA_StopChannel(i);
}
JA_soundEnabled = value;
}
float JA_SetVolume(float volume)
{
float JA_SetVolume(float volume) {
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
return JA_musicVolume;

View File

@@ -1,16 +1,14 @@
#pragma once
#include <SDL3/SDL.h>
enum JA_Channel_state
{
enum JA_Channel_state {
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED
};
enum JA_Music_state
{
enum JA_Music_state {
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,

View File

@@ -1,461 +1,416 @@
#include "jail_shader.h"
#include <SDL3/SDL.h> // Para SDL_GL_GetProcAddress, SDL_LogError
#include <stdint.h> // Para uintptr_t
#include <SDL3/SDL.h> // Para SDL_GL_GetProcAddress, SDL_LogError
#include <stdint.h> // Para uintptr_t
#include <cstring> // Para strncmp
#include <stdexcept> // Para runtime_error
#include <vector> // Para vector
#ifdef __APPLE__
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#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 <SDL3/SDL_opengl.h> // Para GLuint, GLint, glTexCoord2f, glVertex2f
#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 <SDL3/SDL_opengl.h> // Para GLuint, GLint, glTexCoord2f, glVertex2f
#endif // __APPLE__
namespace shader
{
// Constantes
const GLuint INVALID_SHADER_ID = 0;
const GLuint INVALID_PROGRAM_ID = 0;
const GLuint DEFAULT_TEXTURE_ID = 1;
namespace shader {
// Constantes
const GLuint INVALID_SHADER_ID = 0;
const GLuint INVALID_PROGRAM_ID = 0;
const GLuint DEFAULT_TEXTURE_ID = 1;
// Variables globales
SDL_Window *win = nullptr;
SDL_Renderer *renderer = nullptr;
GLuint programId = 0;
SDL_Texture *backBuffer = nullptr;
SDL_Point win_size = {320 * 4, 256 * 4};
SDL_FPoint tex_size = {320, 256};
bool usingOpenGL = false;
// Variables globales
SDL_Window *win = nullptr;
SDL_Renderer *renderer = nullptr;
GLuint programId = 0;
SDL_Texture *backBuffer = nullptr;
SDL_Point win_size = {320 * 4, 256 * 4};
SDL_FPoint tex_size = {320, 256};
bool usingOpenGL = false;
#ifndef __APPLE__
// Declaración de funciones de extensión de OpenGL (evitando GLEW)
PFNGLCREATESHADERPROC glCreateShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
// Declaración de funciones de extensión de OpenGL (evitando GLEW)
PFNGLCREATESHADERPROC glCreateShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
bool initGLExtensions()
{
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
bool initGLExtensions() {
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
glUseProgram && glDeleteProgram;
}
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
glUseProgram && glDeleteProgram;
}
#endif
// Función para verificar errores de OpenGL
void 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);
}
// Función para verificar errores de OpenGL
void 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);
}
}
// Función para compilar un shader a partir de un std::string
GLuint compileShader(const std::string &source, GLuint shader_type) {
if (source.empty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío.");
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
}
// Función para compilar un shader a partir de un std::string
GLuint compileShader(const std::string &source, GLuint shader_type)
{
if (source.empty())
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío.");
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
// Crear identificador del shader
GLuint shader_id = glCreateShader(shader_type);
if (shader_id == INVALID_SHADER_ID) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader.");
checkGLError("glCreateShader");
return INVALID_SHADER_ID;
}
// Agregar una directiva según el tipo de shader
std::string directive = (shader_type == GL_VERTEX_SHADER)
? "#define VERTEX\n"
: "#define FRAGMENT\n";
const char *sources[2] = {directive.c_str(), source.c_str()};
// Especificar el código fuente del shader
glShaderSource(shader_id, 2, sources, nullptr);
checkGLError("glShaderSource");
// Compilar el shader
glCompileShader(shader_id);
checkGLError("glCompileShader");
// Verificar si la compilación fue exitosa
GLint compiled_ok = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
if (compiled_ok != GL_TRUE) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id);
GLint log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
std::vector<GLchar> log(log_length);
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
}
glDeleteShader(shader_id);
return INVALID_SHADER_ID;
}
return shader_id;
}
// Crear identificador del shader
GLuint shader_id = glCreateShader(shader_type);
if (shader_id == INVALID_SHADER_ID)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader.");
checkGLError("glCreateShader");
return INVALID_SHADER_ID;
}
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
GLuint compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source) {
GLuint program_id = glCreateProgram();
if (program_id == INVALID_PROGRAM_ID) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
checkGLError("glCreateProgram");
return INVALID_PROGRAM_ID;
}
// Agregar una directiva según el tipo de shader
std::string directive = (shader_type == GL_VERTEX_SHADER)
? "#define VERTEX\n"
: "#define FRAGMENT\n";
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_VERTEX_SHADER);
GLuint fragment_shader_id = compileShader(fragment_shader_source.empty() ? vertex_shader_source : fragment_shader_source, GL_FRAGMENT_SHADER);
const char *sources[2] = {directive.c_str(), source.c_str()};
if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID) {
// Asociar los shaders al programa
glAttachShader(program_id, vertex_shader_id);
checkGLError("glAttachShader vertex");
glAttachShader(program_id, fragment_shader_id);
checkGLError("glAttachShader fragment");
// Especificar el código fuente del shader
glShaderSource(shader_id, 2, sources, nullptr);
checkGLError("glShaderSource");
glLinkProgram(program_id);
checkGLError("glLinkProgram");
// Compilar el shader
glCompileShader(shader_id);
checkGLError("glCompileShader");
// Verificar si la compilación fue exitosa
GLint compiled_ok = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
if (compiled_ok != GL_TRUE)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id);
// Verificar el estado del enlace
GLint isLinked = GL_FALSE;
glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
GLint log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
std::vector<GLchar> log(log_length);
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de enlace del programa: %s", log.data());
}
glDeleteShader(shader_id);
return INVALID_SHADER_ID;
}
return shader_id;
}
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
GLuint compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source)
{
GLuint program_id = glCreateProgram();
if (program_id == INVALID_PROGRAM_ID)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
checkGLError("glCreateProgram");
return INVALID_PROGRAM_ID;
}
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_VERTEX_SHADER);
GLuint fragment_shader_id = compileShader(fragment_shader_source.empty() ? vertex_shader_source : fragment_shader_source, GL_FRAGMENT_SHADER);
if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID)
{
// Asociar los shaders al programa
glAttachShader(program_id, vertex_shader_id);
checkGLError("glAttachShader vertex");
glAttachShader(program_id, fragment_shader_id);
checkGLError("glAttachShader fragment");
glLinkProgram(program_id);
checkGLError("glLinkProgram");
// Verificar el estado del enlace
GLint isLinked = GL_FALSE;
glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
GLint log_length;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de enlace del programa: %s", log.data());
}
glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID;
}
else
{
glValidateProgram(program_id);
checkGLError("glValidateProgram");
// Log de información del programa (solo si hay información)
GLint log_length;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 1) // > 1 porque algunos drivers devuelven 1 para cadena vacía
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
}
}
}
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders.");
glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID;
}
} else {
glValidateProgram(program_id);
checkGLError("glValidateProgram");
// Limpiar los shaders (ya no son necesarios después del enlace)
if (vertex_shader_id != INVALID_SHADER_ID)
{
glDeleteShader(vertex_shader_id);
// Log de información del programa (solo si hay información)
GLint log_length;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 1) // > 1 porque algunos drivers devuelven 1 para cadena vacía
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
}
}
if (fragment_shader_id != INVALID_SHADER_ID)
{
glDeleteShader(fragment_shader_id);
}
return program_id;
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders.");
glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID;
}
// Función para obtener el ID de textura OpenGL desde SDL3
GLuint getTextureID(SDL_Texture *texture)
{
if (!texture)
return DEFAULT_TEXTURE_ID;
// Intentar obtener el ID de textura OpenGL desde las propiedades de SDL3
SDL_PropertiesID props = SDL_GetTextureProperties(texture);
GLuint textureId = 0;
// Intentar diferentes nombres de propiedades según la versión de SDL3
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
// Si la primera no funciona, intentar con el nombre alternativo
if (textureId == 0)
{
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
}
// Si aún no funciona, intentar obtener como número
if (textureId == 0)
{
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
}
// Si ninguna funciona, usar el método manual de bindeo de textura
if (textureId == 0)
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)", DEFAULT_TEXTURE_ID);
textureId = DEFAULT_TEXTURE_ID;
}
return textureId;
// Limpiar los shaders (ya no son necesarios después del enlace)
if (vertex_shader_id != INVALID_SHADER_ID) {
glDeleteShader(vertex_shader_id);
}
if (fragment_shader_id != INVALID_SHADER_ID) {
glDeleteShader(fragment_shader_id);
}
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader)
{
shader::win = window;
shader::renderer = SDL_GetRenderer(window);
shader::backBuffer = back_buffer_texture;
return program_id;
}
if (!shader::renderer)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana.");
return false;
}
// Función para obtener el ID de textura OpenGL desde SDL3
GLuint getTextureID(SDL_Texture *texture) {
if (!texture)
return DEFAULT_TEXTURE_ID;
SDL_GetWindowSize(window, &win_size.x, &win_size.y);
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y);
// Intentar obtener el ID de textura OpenGL desde las propiedades de SDL3
SDL_PropertiesID props = SDL_GetTextureProperties(texture);
GLuint textureId = 0;
const auto render_name = SDL_GetRendererName(renderer);
if (!render_name)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
return false;
}
// Intentar diferentes nombres de propiedades según la versión de SDL3
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
// Verificar que el renderer sea OpenGL
if (!strncmp(render_name, "opengl", 6))
{
// Si la primera no funciona, intentar con el nombre alternativo
if (textureId == 0) {
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
}
// Si aún no funciona, intentar obtener como número
if (textureId == 0) {
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
}
// Si ninguna funciona, usar el método manual de bindeo de textura
if (textureId == 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)",
DEFAULT_TEXTURE_ID);
textureId = DEFAULT_TEXTURE_ID;
}
return textureId;
}
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) {
shader::win = window;
shader::renderer = SDL_GetRenderer(window);
shader::backBuffer = back_buffer_texture;
if (!shader::renderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana.");
return false;
}
SDL_GetWindowSize(window, &win_size.x, &win_size.y);
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y);
const auto render_name = SDL_GetRendererName(renderer);
if (!render_name) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
return false;
}
// Verificar que el renderer sea OpenGL
if (!strncmp(render_name, "opengl", 6)) {
#ifndef __APPLE__
if (!initGLExtensions())
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se han podido inicializar las extensiones de OpenGL.");
usingOpenGL = false;
return false;
}
#endif
// Compilar el programa de shaders utilizando std::string
programId = compileProgram(vertex_shader, fragment_shader);
if (programId == INVALID_PROGRAM_ID)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
usingOpenGL = false;
return false;
}
}
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name);
if (!initGLExtensions()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se han podido inicializar las extensiones de OpenGL.");
usingOpenGL = false;
return false;
}
usingOpenGL = true;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully.");
return true;
#endif
// Compilar el programa de shaders utilizando std::string
programId = compileProgram(vertex_shader, fragment_shader);
if (programId == INVALID_PROGRAM_ID) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
usingOpenGL = false;
return false;
}
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name);
usingOpenGL = false;
return false;
}
void render()
{
// Establece el color de fondo
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderClear(renderer);
usingOpenGL = true;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully.");
return true;
}
if (usingOpenGL && programId != INVALID_PROGRAM_ID)
{
// Guardar estados de OpenGL
GLint oldProgramId;
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
void render() {
// Establece el color de fondo
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderClear(renderer);
GLint oldViewport[4];
glGetIntegerv(GL_VIEWPORT, oldViewport);
if (usingOpenGL && programId != INVALID_PROGRAM_ID) {
// Guardar estados de OpenGL
GLint oldProgramId;
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
GLboolean wasTextureEnabled = glIsEnabled(GL_TEXTURE_2D);
GLint oldTextureId;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);
GLint oldViewport[4];
glGetIntegerv(GL_VIEWPORT, oldViewport);
// Obtener y bindear la textura
GLuint textureId = getTextureID(backBuffer);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
checkGLError("glBindTexture");
GLboolean wasTextureEnabled = glIsEnabled(GL_TEXTURE_2D);
GLint oldTextureId;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);
// Usar nuestro programa de shaders
glUseProgram(programId);
checkGLError("glUseProgram");
// Obtener y bindear la textura
GLuint textureId = getTextureID(backBuffer);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
checkGLError("glBindTexture");
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
int logicalW, logicalH;
SDL_RendererLogicalPresentation mode;
SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
if (logicalW == 0 || logicalH == 0)
{
logicalW = win_size.x;
logicalH = win_size.y;
// Usar nuestro programa de shaders
glUseProgram(programId);
checkGLError("glUseProgram");
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
int logicalW, logicalH;
SDL_RendererLogicalPresentation mode;
SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
if (logicalW == 0 || logicalH == 0) {
logicalW = win_size.x;
logicalH = win_size.y;
}
// Cálculo del viewport
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
if (USE_INTEGER_SCALE) {
// Calcula el factor de escalado entero máximo que se puede aplicar
int scaleX = win_size.x / logicalW;
int scaleY = win_size.y / logicalH;
int scale = (scaleX < scaleY ? scaleX : scaleY);
if (scale < 1) {
scale = 1;
}
// Cálculo del viewport
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
if (USE_INTEGER_SCALE)
{
// Calcula el factor de escalado entero máximo que se puede aplicar
int scaleX = win_size.x / logicalW;
int scaleY = win_size.y / logicalH;
int scale = (scaleX < scaleY ? scaleX : scaleY);
if (scale < 1)
{
scale = 1;
}
viewportW = logicalW * scale;
viewportH = logicalH * scale;
viewportW = logicalW * scale;
viewportH = logicalH * scale;
viewportX = (win_size.x - viewportW) / 2;
viewportY = (win_size.y - viewportH) / 2;
} else {
// Letterboxing: preserva la relación de aspecto usando una escala flotante
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
float logicalAspect = static_cast<float>(logicalW) / logicalH;
if (windowAspect > logicalAspect) {
viewportW = static_cast<int>(logicalAspect * win_size.y);
viewportX = (win_size.x - viewportW) / 2;
} else {
viewportH = static_cast<int>(win_size.x / logicalAspect);
viewportY = (win_size.y - viewportH) / 2;
}
else
{
// Letterboxing: preserva la relación de aspecto usando una escala flotante
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
float logicalAspect = static_cast<float>(logicalW) / logicalH;
if (windowAspect > logicalAspect)
{
viewportW = static_cast<int>(logicalAspect * win_size.y);
viewportX = (win_size.x - viewportW) / 2;
}
else
{
viewportH = static_cast<int>(win_size.x / logicalAspect);
viewportY = (win_size.y - viewportH) / 2;
}
}
glViewport(viewportX, viewportY, viewportW, viewportH);
checkGLError("glViewport");
// Configurar la proyección ortográfica usando el espacio lógico
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Dibuja el quad con las coordenadas ajustadas.
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
glBegin(GL_TRIANGLE_STRIP);
// Vértice superior izquierdo
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
// Vértice superior derecho
glTexCoord2f(1.0f, 1.0f);
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
// Vértice inferior izquierdo
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
// Vértice inferior derecho
glTexCoord2f(1.0f, 0.0f);
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
glEnd();
checkGLError("render quad");
SDL_GL_SwapWindow(win);
// Restaurar estados de OpenGL
glUseProgram(oldProgramId);
glBindTexture(GL_TEXTURE_2D, oldTextureId);
if (!wasTextureEnabled)
{
glDisable(GL_TEXTURE_2D);
}
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
}
else
{
// Fallback a renderizado normal de SDL
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
SDL_RenderPresent(renderer);
glViewport(viewportX, viewportY, viewportW, viewportH);
checkGLError("glViewport");
// Configurar la proyección ortográfica usando el espacio lógico
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Dibuja el quad con las coordenadas ajustadas.
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
glBegin(GL_TRIANGLE_STRIP);
// Vértice superior izquierdo
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
// Vértice superior derecho
glTexCoord2f(1.0f, 1.0f);
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
// Vértice inferior izquierdo
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
// Vértice inferior derecho
glTexCoord2f(1.0f, 0.0f);
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
glEnd();
checkGLError("render quad");
SDL_GL_SwapWindow(win);
// Restaurar estados de OpenGL
glUseProgram(oldProgramId);
glBindTexture(GL_TEXTURE_2D, oldTextureId);
if (!wasTextureEnabled) {
glDisable(GL_TEXTURE_2D);
}
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
} else {
// Fallback a renderizado normal de SDL
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
SDL_RenderPresent(renderer);
}
}
void cleanup() {
if (programId != INVALID_PROGRAM_ID) {
glDeleteProgram(programId);
programId = INVALID_PROGRAM_ID;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
}
void cleanup()
{
if (programId != INVALID_PROGRAM_ID)
{
glDeleteProgram(programId);
programId = INVALID_PROGRAM_ID;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
}
// Reinicializar variables
win = nullptr;
renderer = nullptr;
backBuffer = nullptr;
usingOpenGL = false;
}
// Reinicializar variables
win = nullptr;
renderer = nullptr;
backBuffer = nullptr;
usingOpenGL = false;
}
bool isUsingOpenGL() {
return usingOpenGL;
}
bool isUsingOpenGL()
{
return usingOpenGL;
}
GLuint getProgramId()
{
return programId;
}
}
GLuint getProgramId() {
return programId;
}
} // namespace shader

View File

@@ -1,10 +1,10 @@
#pragma once
#include <SDL3/SDL.h> // Para SDL_Texture, SDL_Window
#include <string> // Para basic_string, string
#include <SDL3/SDL.h> // Para SDL_Texture, SDL_Window
namespace shader
{
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
void render();
}
#include <string> // Para basic_string, string
namespace shader {
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
void render();
} // namespace shader

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff