Implementa pre-escalado de alta calidad para eliminar artefactos de escalado dinámico de SDL y mejorar la nitidez visual de los logos. Características: - 4 texturas pre-escaladas (2 logos × 2 resoluciones: base + nativa) - Detección automática de resolución nativa del monitor - Switching dinámico entre texturas al cambiar resolución (F4) - Renderizado 1:1 sin escalado adicional (máxima calidad) - Algoritmo Mitchell en espacio sRGB (balance calidad/velocidad) - Todo en RAM, sin archivos temporales Archivos nuevos: - source/external/stb_image_resize2.h: Biblioteca de escalado stb - source/logo_scaler.h/cpp: Clase helper para pre-escalado Cambios en AppLogo: - Reemplazadas shared_ptr<Texture> por SDL_Texture* raw pointers - initialize(): Pre-escala logos a 2 resoluciones al inicio - updateScreenSize(): Cambia entre texturas según resolución - render(): Simplificado, siempre usa renderWithGeometry() - ~AppLogo(): Libera 4 texturas SDL manualmente El sistema detecta la resolución nativa al inicio y crea versiones optimizadas. Al presionar F4, cambia automáticamente a la textura nativa para calidad perfecta en fullscreen. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
145 lines
5.3 KiB
C++
145 lines
5.3 KiB
C++
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
|
#include "logo_scaler.h"
|
|
|
|
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
|
#include <SDL3/SDL_log.h> // Para SDL_Log
|
|
#include <SDL3/SDL_pixels.h> // Para SDL_PixelFormat
|
|
#include <SDL3/SDL_render.h> // Para SDL_CreateTexture
|
|
#include <SDL3/SDL_surface.h> // Para SDL_CreateSurfaceFrom
|
|
#include <SDL3/SDL_video.h> // Para SDL_GetDisplays
|
|
|
|
#include <cstdlib> // Para free()
|
|
#include <iostream> // Para std::cout
|
|
|
|
#include "external/stb_image.h" // Para stbi_load, stbi_image_free
|
|
#include "external/stb_image_resize2.h" // Para stbir_resize_uint8_srgb
|
|
|
|
// ============================================================================
|
|
// Detectar resolución nativa del monitor principal
|
|
// ============================================================================
|
|
|
|
bool LogoScaler::detectNativeResolution(int& native_width, int& native_height) {
|
|
int num_displays = 0;
|
|
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
|
|
|
if (displays == nullptr || num_displays == 0) {
|
|
SDL_Log("Error al obtener displays: %s", SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
// Obtener resolución del display principal (displays[0])
|
|
const auto* dm = SDL_GetCurrentDisplayMode(displays[0]);
|
|
if (dm == nullptr) {
|
|
SDL_Log("Error al obtener modo del display: %s", SDL_GetError());
|
|
SDL_free(displays);
|
|
return false;
|
|
}
|
|
|
|
native_width = dm->w;
|
|
native_height = dm->h;
|
|
|
|
SDL_free(displays);
|
|
|
|
std::cout << "Resolución nativa detectada: " << native_width << "x" << native_height << std::endl;
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Cargar PNG y escalar al tamaño especificado
|
|
// ============================================================================
|
|
|
|
unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
|
int target_width, int target_height,
|
|
int& out_width, int& out_height) {
|
|
// 1. Cargar imagen original con stb_image
|
|
int orig_width, orig_height, orig_channels;
|
|
unsigned char* orig_data = stbi_load(path.c_str(), &orig_width, &orig_height, &orig_channels, STBI_rgb_alpha);
|
|
|
|
if (orig_data == nullptr) {
|
|
SDL_Log("Error al cargar imagen %s: %s", path.c_str(), stbi_failure_reason());
|
|
return nullptr;
|
|
}
|
|
|
|
std::cout << "Imagen cargada: " << path << " (" << orig_width << "x" << orig_height << ")" << std::endl;
|
|
|
|
// 2. Calcular tamaño final manteniendo aspect ratio
|
|
// El alto está fijado por target_height (APPLOGO_HEIGHT_PERCENT)
|
|
// Calcular ancho proporcional al aspect ratio original
|
|
float aspect_ratio = static_cast<float>(orig_width) / static_cast<float>(orig_height);
|
|
out_width = static_cast<int>(target_height * aspect_ratio);
|
|
out_height = target_height;
|
|
|
|
std::cout << " Escalando a: " << out_width << "x" << out_height << std::endl;
|
|
|
|
// 3. Alocar buffer para imagen escalada (RGBA = 4 bytes por píxel)
|
|
unsigned char* scaled_data = static_cast<unsigned char*>(malloc(out_width * out_height * 4));
|
|
if (scaled_data == nullptr) {
|
|
SDL_Log("Error al alocar memoria para imagen escalada");
|
|
stbi_image_free(orig_data);
|
|
return nullptr;
|
|
}
|
|
|
|
// 4. Escalar con stb_image_resize2 (algoritmo Mitchell, espacio sRGB)
|
|
// La función devuelve el puntero de salida, o nullptr si falla
|
|
unsigned char* result = stbir_resize_uint8_srgb(
|
|
orig_data, orig_width, orig_height, 0, // Input
|
|
scaled_data, out_width, out_height, 0, // Output
|
|
STBIR_RGBA // Formato píxel
|
|
);
|
|
|
|
// Liberar imagen original (ya no la necesitamos)
|
|
stbi_image_free(orig_data);
|
|
|
|
if (result == nullptr) {
|
|
SDL_Log("Error al escalar imagen");
|
|
free(scaled_data);
|
|
return nullptr;
|
|
}
|
|
|
|
std::cout << " Escalado completado correctamente" << std::endl;
|
|
return scaled_data;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Crear textura SDL desde buffer RGBA
|
|
// ============================================================================
|
|
|
|
SDL_Texture* LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
|
|
unsigned char* data,
|
|
int width, int height) {
|
|
if (renderer == nullptr || data == nullptr || width <= 0 || height <= 0) {
|
|
SDL_Log("Parámetros inválidos para createTextureFromBuffer");
|
|
return nullptr;
|
|
}
|
|
|
|
// 1. Crear surface SDL desde buffer RGBA
|
|
int pitch = width * 4; // 4 bytes por píxel (RGBA)
|
|
SDL_PixelFormat pixel_format = SDL_PIXELFORMAT_RGBA32;
|
|
|
|
SDL_Surface* surface = SDL_CreateSurfaceFrom(
|
|
width, height,
|
|
pixel_format,
|
|
data,
|
|
pitch
|
|
);
|
|
|
|
if (surface == nullptr) {
|
|
SDL_Log("Error al crear surface: %s", SDL_GetError());
|
|
return nullptr;
|
|
}
|
|
|
|
// 2. Crear textura desde surface
|
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
|
|
|
if (texture == nullptr) {
|
|
SDL_Log("Error al crear textura: %s", SDL_GetError());
|
|
SDL_DestroySurface(surface);
|
|
return nullptr;
|
|
}
|
|
|
|
// 3. Liberar surface (la textura ya tiene los datos)
|
|
SDL_DestroySurface(surface);
|
|
|
|
return texture;
|
|
}
|