dab71d41b6
- Identificado que SDL_RenderGeometry requiere campo alpha en SDL_Vertex - Restaurada implementación original con alpha=1.0f en todos los vértices - Eliminado código debug temporal y workaround con SDL_RenderFillRect - El degradado de fondo ahora funciona correctamente como en la versión original 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
302 lines
8.5 KiB
C++
302 lines
8.5 KiB
C++
#include "window_manager.h"
|
|
|
|
#include <SDL3/SDL_init.h> // for SDL_Init
|
|
#include <SDL3/SDL_error.h> // for SDL_GetError
|
|
#include <SDL3/SDL_video.h> // for SDL_CreateWindow, SDL_GetDisplayBounds
|
|
#include <iostream> // for cout
|
|
|
|
// Incluir backends específicos
|
|
// TODO: Reactivar cuando se implemente compilación Objective-C++
|
|
// #ifdef __APPLE__
|
|
// #include "backends/metal_renderer.h"
|
|
// #endif
|
|
|
|
#if defined(_WIN32) || defined(__linux__)
|
|
#include "backends/vulkan_renderer.h"
|
|
#endif
|
|
|
|
// Fallback SDL siempre disponible
|
|
#include "backends/sdl_renderer.h"
|
|
|
|
namespace vibe4 {
|
|
|
|
WindowManager::WindowManager() = default;
|
|
|
|
WindowManager::~WindowManager() {
|
|
shutdown();
|
|
}
|
|
|
|
bool WindowManager::initialize(const char* title, int width, int height, int zoom) {
|
|
logical_width_ = width;
|
|
logical_height_ = height;
|
|
current_zoom_ = zoom;
|
|
|
|
// Inicializar SDL
|
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
|
std::cout << "¡SDL no se pudo inicializar! Error: " << SDL_GetError() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Crear ventana SDL (sin multiplicar por zoom - trabajamos nativo)
|
|
if (!createSDLWindow(title, width, height)) {
|
|
return false;
|
|
}
|
|
|
|
// Detectar y crear el mejor backend disponible
|
|
BackendType backend_type = detectBestBackend();
|
|
renderer_ = createRenderer(backend_type);
|
|
|
|
if (!renderer_) {
|
|
std::cout << "¡No se pudo crear ningún backend de renderizado!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Inicializar el renderer
|
|
if (!renderer_->initialize(window_, width, height)) {
|
|
std::cout << "¡No se pudo inicializar el backend " << renderer_->getBackendName() << "!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Crear textura de renderizado para postprocesado
|
|
auto* sdl_renderer = getSDLRenderer();
|
|
if (sdl_renderer) {
|
|
render_texture_ = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGBA8888,
|
|
SDL_TEXTUREACCESS_TARGET, width, height);
|
|
if (!render_texture_) {
|
|
std::cout << "¡No se pudo crear la textura de renderizado! Error: " << SDL_GetError() << std::endl;
|
|
return false;
|
|
}
|
|
std::cout << "Textura de renderizado creada: " << width << "x" << height << std::endl;
|
|
}
|
|
|
|
std::cout << "Backend de renderizado inicializado: " << renderer_->getBackendName() << std::endl;
|
|
return true;
|
|
}
|
|
|
|
void WindowManager::shutdown() {
|
|
if (render_texture_) {
|
|
SDL_DestroyTexture(render_texture_);
|
|
render_texture_ = nullptr;
|
|
}
|
|
|
|
if (renderer_) {
|
|
renderer_->shutdown();
|
|
renderer_.reset();
|
|
}
|
|
|
|
if (window_) {
|
|
SDL_DestroyWindow(window_);
|
|
window_ = nullptr;
|
|
}
|
|
|
|
SDL_Quit();
|
|
}
|
|
|
|
bool WindowManager::createSDLWindow(const char* title, int width, int height) {
|
|
Uint32 window_flags = SDL_WINDOW_OPENGL; // Empezamos con OpenGL como base
|
|
|
|
// Agregar flags específicos dependiendo del backend que vayamos a usar
|
|
BackendType backend_type = detectBestBackend();
|
|
switch (backend_type) {
|
|
case BackendType::METAL:
|
|
window_flags = SDL_WINDOW_METAL;
|
|
break;
|
|
case BackendType::VULKAN:
|
|
window_flags = SDL_WINDOW_VULKAN;
|
|
break;
|
|
case BackendType::SDL:
|
|
default:
|
|
window_flags = SDL_WINDOW_OPENGL;
|
|
break;
|
|
}
|
|
|
|
window_ = SDL_CreateWindow(title, width, height, window_flags);
|
|
if (!window_) {
|
|
std::cout << "¡No se pudo crear la ventana! Error: " << SDL_GetError() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BackendType WindowManager::detectBestBackend() const {
|
|
// TODO: Reactivar Metal cuando se implemente compilación Objective-C++
|
|
#ifdef __APPLE__
|
|
return BackendType::SDL; // Temporalmente usar SDL en macOS
|
|
#elif defined(_WIN32) || defined(__linux__)
|
|
return BackendType::VULKAN; // Windows/Linux usan Vulkan
|
|
#else
|
|
return BackendType::SDL; // Fallback para otras plataformas
|
|
#endif
|
|
}
|
|
|
|
std::unique_ptr<RendererInterface> WindowManager::createRenderer(BackendType type) {
|
|
switch (type) {
|
|
// TODO: Reactivar cuando se implemente compilación Objective-C++
|
|
// #ifdef __APPLE__
|
|
// case BackendType::METAL:
|
|
// return std::make_unique<MetalRenderer>();
|
|
// #endif
|
|
|
|
#if defined(_WIN32) || defined(__linux__)
|
|
case BackendType::VULKAN:
|
|
return std::make_unique<VulkanRenderer>();
|
|
#endif
|
|
|
|
case BackendType::SDL:
|
|
default:
|
|
return std::make_unique<SDLRenderer>();
|
|
}
|
|
}
|
|
|
|
void WindowManager::setTitle(const char* title) {
|
|
if (window_) {
|
|
SDL_SetWindowTitle(window_, title);
|
|
}
|
|
}
|
|
|
|
bool WindowManager::setFullscreen(bool enable) {
|
|
if (!window_) return false;
|
|
|
|
bool result = SDL_SetWindowFullscreen(window_, enable);
|
|
if (result) {
|
|
fullscreen_enabled_ = enable;
|
|
if (enable) {
|
|
real_fullscreen_enabled_ = false; // Solo uno puede estar activo
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool WindowManager::setRealFullscreen(bool enable) {
|
|
if (!window_) return false;
|
|
|
|
bool result = SDL_SetWindowFullscreen(window_, enable);
|
|
if (result) {
|
|
real_fullscreen_enabled_ = enable;
|
|
if (enable) {
|
|
fullscreen_enabled_ = false; // Solo uno puede estar activo
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void WindowManager::setZoom(int zoom) {
|
|
if (zoom < MIN_ZOOM || zoom > MAX_ZOOM) return;
|
|
|
|
current_zoom_ = zoom;
|
|
updateWindowSize();
|
|
}
|
|
|
|
void WindowManager::updateWindowSize() {
|
|
if (!window_ || fullscreen_enabled_ || real_fullscreen_enabled_) return;
|
|
|
|
int new_width = logical_width_ * current_zoom_;
|
|
int new_height = logical_height_ * current_zoom_;
|
|
|
|
SDL_SetWindowSize(window_, new_width, new_height);
|
|
|
|
if (renderer_) {
|
|
renderer_->resize(logical_width_, logical_height_);
|
|
}
|
|
}
|
|
|
|
int WindowManager::calculateMaxZoom() const {
|
|
SDL_Rect display_bounds;
|
|
if (!SDL_GetDisplayBounds(SDL_GetDisplayForWindow(window_), &display_bounds)) {
|
|
return MIN_ZOOM;
|
|
}
|
|
|
|
int max_width = display_bounds.w - DESKTOP_MARGIN * 2;
|
|
int max_height = display_bounds.h - DESKTOP_MARGIN * 2 - DECORATION_HEIGHT;
|
|
|
|
int max_zoom_x = max_width / logical_width_;
|
|
int max_zoom_y = max_height / logical_height_;
|
|
|
|
int calculated_max = std::min(max_zoom_x, max_zoom_y);
|
|
return std::min(calculated_max, MAX_ZOOM);
|
|
}
|
|
|
|
void WindowManager::zoomIn() {
|
|
int max_zoom = calculateMaxZoom();
|
|
if (current_zoom_ < max_zoom) {
|
|
setZoom(current_zoom_ + 1);
|
|
}
|
|
}
|
|
|
|
void WindowManager::zoomOut() {
|
|
if (current_zoom_ > MIN_ZOOM) {
|
|
setZoom(current_zoom_ - 1);
|
|
}
|
|
}
|
|
|
|
void WindowManager::getSize(int& width, int& height) const {
|
|
if (window_) {
|
|
SDL_GetWindowSize(window_, &width, &height);
|
|
} else {
|
|
width = height = 0;
|
|
}
|
|
}
|
|
|
|
void WindowManager::getLogicalSize(int& width, int& height) const {
|
|
width = logical_width_;
|
|
height = logical_height_;
|
|
}
|
|
|
|
BackendType WindowManager::getBackendType() const {
|
|
return renderer_ ? renderer_->getBackendType() : BackendType::SDL;
|
|
}
|
|
|
|
const char* WindowManager::getBackendName() const {
|
|
return renderer_ ? renderer_->getBackendName() : "None";
|
|
}
|
|
|
|
SDL_Renderer* WindowManager::getSDLRenderer() const {
|
|
// Solo funciona si el backend activo es SDL
|
|
if (renderer_ && renderer_->getBackendType() == BackendType::SDL) {
|
|
auto* sdl_renderer = static_cast<SDLRenderer*>(renderer_.get());
|
|
return sdl_renderer->getSDLRenderer();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool WindowManager::setRenderTarget() {
|
|
auto* sdl_renderer = getSDLRenderer();
|
|
if (!sdl_renderer || !render_texture_) {
|
|
return false;
|
|
}
|
|
|
|
// Cambiar el render target a nuestra textura
|
|
if (!SDL_SetRenderTarget(sdl_renderer, render_texture_)) {
|
|
std::cout << "¡No se pudo establecer render target! Error: " << SDL_GetError() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Limpiar la textura de renderizado
|
|
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
|
|
SDL_RenderClear(sdl_renderer);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WindowManager::presentFrame() {
|
|
auto* sdl_renderer = getSDLRenderer();
|
|
if (!sdl_renderer || !render_texture_) {
|
|
return;
|
|
}
|
|
|
|
// Volver al render target por defecto (la ventana)
|
|
SDL_SetRenderTarget(sdl_renderer, nullptr);
|
|
|
|
// Limpiar la pantalla
|
|
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
|
|
SDL_RenderClear(sdl_renderer);
|
|
|
|
// Copiar la textura de renderizado a la pantalla 1:1 (sin zoom)
|
|
SDL_RenderTexture(sdl_renderer, render_texture_, nullptr, nullptr);
|
|
|
|
// Presentar el frame final
|
|
SDL_RenderPresent(sdl_renderer);
|
|
}
|
|
|
|
} // namespace vibe4
|