Files
vibe4_shaders/source/backends/sdl_renderer.cpp
Sergio Valor 6a84234265 Implementar arquitectura multi-backend para vibe4_shaders
- Actualizar proyecto de vibe3_physics a vibe4_shaders
- Crear sistema modular de renderizado con RendererInterface
- Añadir WindowManager para gestión de ventana y backends
- Implementar backends: SDL (fallback), Vulkan, Metal
- Añadir soporte para efectos CRT en software
- Migrar sistema de renderizado a batch processing
- Actualizar README con nueva arquitectura

NOTA: Funcionalidad básica necesita restauración (texto y texturas)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 23:07:48 +02:00

250 lines
7.3 KiB
C++

#include "sdl_renderer.h"
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_error.h>
#include <iostream>
#include <cmath>
namespace vibe4 {
SDLRenderer::SDLRenderer() = default;
SDLRenderer::~SDLRenderer() {
shutdown();
}
bool SDLRenderer::initialize(SDL_Window* window, int width, int height) {
window_ = window;
screen_width_ = width;
screen_height_ = height;
// Crear renderer SDL con aceleración por hardware
renderer_ = SDL_CreateRenderer(window, nullptr);
if (!renderer_) {
std::cout << "¡No se pudo crear el renderer SDL! Error: " << SDL_GetError() << std::endl;
return false;
}
// Configurar el renderer
SDL_SetRenderLogicalPresentation(renderer_, width, height,
SDL_LOGICAL_PRESENTATION_LETTERBOX);
// Reservar espacio para el batch rendering
batch_vertices_.reserve(50000 * 4); // 4 vértices por sprite
batch_indices_.reserve(50000 * 6); // 6 índices por sprite
std::cout << "SDLRenderer inicializado exitosamente" << std::endl;
return true;
}
void SDLRenderer::shutdown() {
if (sprite_texture_) {
SDL_DestroyTexture(sprite_texture_);
sprite_texture_ = nullptr;
}
if (renderer_) {
SDL_DestroyRenderer(renderer_);
renderer_ = nullptr;
}
}
bool SDLRenderer::beginFrame() {
if (!renderer_) return false;
// Limpiar el frame
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 255);
SDL_RenderClear(renderer_);
// Limpiar batch de la frame anterior
clearBatch();
return true;
}
void SDLRenderer::endFrame() {
// Renderizar todo el batch acumulado
renderBatch();
}
void SDLRenderer::present() {
if (renderer_) {
SDL_RenderPresent(renderer_);
}
}
void SDLRenderer::renderGradientBackground(
float top_r, float top_g, float top_b,
float bottom_r, float bottom_g, float bottom_b) {
if (!renderer_) return;
// Crear gradiente usando múltiples rectángulos
const int gradient_steps = 32;
float step_height = static_cast<float>(screen_height_) / gradient_steps;
for (int i = 0; i < gradient_steps; ++i) {
float t = static_cast<float>(i) / (gradient_steps - 1);
// Interpolar colores
float r = top_r + (bottom_r - top_r) * t;
float g = top_g + (bottom_g - top_g) * t;
float b = top_b + (bottom_b - top_b) * t;
// Aplicar efectos CRT básicos si están habilitados
if (crt_enabled_) {
applyCRTEffectsToColor(r, g, b, 0, i * step_height);
}
SDL_SetRenderDrawColor(renderer_,
static_cast<Uint8>(r * 255),
static_cast<Uint8>(g * 255),
static_cast<Uint8>(b * 255), 255);
SDL_FRect rect = {
0, i * step_height,
static_cast<float>(screen_width_), step_height + 1
};
SDL_RenderFillRect(renderer_, &rect);
}
}
void SDLRenderer::renderSpriteBatch(
const std::vector<SpriteData>& sprites,
void* texture_data) {
// Agregar todos los sprites al batch
for (const auto& sprite : sprites) {
addSpriteToBatch(sprite.x, sprite.y, sprite.w, sprite.h,
sprite.r, sprite.g, sprite.b);
}
}
void SDLRenderer::addSpriteToBatch(float x, float y, float w, float h,
float r, float g, float b) {
// Aplicar efectos CRT a los colores si están habilitados
float final_r = r, final_g = g, final_b = b;
if (crt_enabled_) {
applyCRTEffectsToColor(final_r, final_g, final_b, x, y);
}
// Normalizar colores (0-255 -> 0-1)
final_r /= 255.0f;
final_g /= 255.0f;
final_b /= 255.0f;
// Crear índice base para este sprite
int base_index = static_cast<int>(batch_vertices_.size());
// Añadir 4 vértices (quad) - SDL_Vertex usa RGB sin alpha
SDL_Vertex v1, v2, v3, v4;
v1.position = {x, y};
v1.tex_coord = {0, 0};
v1.color = {final_r, final_g, final_b};
v2.position = {x + w, y};
v2.tex_coord = {1, 0};
v2.color = {final_r, final_g, final_b};
v3.position = {x + w, y + h};
v3.tex_coord = {1, 1};
v3.color = {final_r, final_g, final_b};
v4.position = {x, y + h};
v4.tex_coord = {0, 1};
v4.color = {final_r, final_g, final_b};
batch_vertices_.push_back(v1);
batch_vertices_.push_back(v2);
batch_vertices_.push_back(v3);
batch_vertices_.push_back(v4);
// Añadir 6 índices (2 triángulos)
batch_indices_.insert(batch_indices_.end(), {
base_index, base_index + 1, base_index + 2, // Primer triángulo
base_index, base_index + 2, base_index + 3 // Segundo triángulo
});
}
void SDLRenderer::clearBatch() {
batch_vertices_.clear();
batch_indices_.clear();
}
void SDLRenderer::renderBatch() {
if (batch_vertices_.empty() || !renderer_) return;
// Renderizar todo el batch en una sola llamada
SDL_RenderGeometry(renderer_, nullptr,
batch_vertices_.data(), static_cast<int>(batch_vertices_.size()),
batch_indices_.data(), static_cast<int>(batch_indices_.size()));
}
void SDLRenderer::applyCRTEffectsToColor(float& r, float& g, float& b, float x, float y) {
// Simulación básica de efectos CRT sin shaders reales
// Scanlines básicos
if (crt_params_.enable_scanlines) {
float scanline = std::sin(y * 3.14159f * 2.0f / 2.0f); // 2 píxeles por scanline
float scanline_factor = crt_params_.scanline_intensity +
(1.0f - crt_params_.scanline_intensity) * (scanline * 0.5f + 0.5f);
r *= scanline_factor;
g *= scanline_factor;
b *= scanline_factor;
}
// Efecto de máscara básico (simulando píxeles RGB)
if (crt_params_.mask_brightness < 1.0f) {
int pixel_x = static_cast<int>(x) % 3;
float mask_factor = crt_params_.mask_brightness;
switch (pixel_x) {
case 0: g *= mask_factor; b *= mask_factor; break; // Pixel rojo
case 1: r *= mask_factor; b *= mask_factor; break; // Pixel verde
case 2: r *= mask_factor; g *= mask_factor; break; // Pixel azul
}
}
// Bloom básico (intensificar colores brillantes)
if (crt_params_.enable_bloom && crt_params_.bloom_factor > 1.0f) {
float brightness = (r + g + b) / 3.0f;
if (brightness > 0.7f) {
float bloom_strength = (brightness - 0.7f) * (crt_params_.bloom_factor - 1.0f);
r += bloom_strength;
g += bloom_strength;
b += bloom_strength;
}
}
// Clamp valores
r = std::min(255.0f, std::max(0.0f, r));
g = std::min(255.0f, std::max(0.0f, g));
b = std::min(255.0f, std::max(0.0f, b));
}
void SDLRenderer::setCRTParams(const CRTParams& params) {
crt_params_ = params;
}
void SDLRenderer::enableCRT(bool enable) {
crt_enabled_ = enable;
}
void SDLRenderer::setVSync(bool enable) {
vsync_enabled_ = enable;
if (renderer_) {
SDL_SetRenderVSync(renderer_, enable ? 1 : 0);
}
}
void SDLRenderer::resize(int width, int height) {
screen_width_ = width;
screen_height_ = height;
if (renderer_) {
SDL_SetRenderLogicalPresentation(renderer_, width, height,
SDL_LOGICAL_PRESENTATION_LETTERBOX);
}
}
} // namespace vibe4