clang format

This commit is contained in:
2026-03-28 12:50:00 +01:00
parent 065f66d40e
commit b459e2106f
18 changed files with 18502 additions and 1962 deletions

View File

@@ -181,11 +181,11 @@ void Audio::initSDLAudio() {
// enable() ya aplica los volúmenes, pero no toca music_enabled_/sound_enabled_. // enable() ya aplica los volúmenes, pero no toca music_enabled_/sound_enabled_.
// Si alguno está desactivado, hay que forzar el volumen a 0 en el backend. // Si alguno está desactivado, hay que forzar el volumen a 0 en el backend.
if (!Options::audio.music.enabled) { if (!Options::audio.music.enabled) {
setMusicVolume(0.0F); // music_enabled_=true aún → llega a JA setMusicVolume(0.0F); // music_enabled_=true aún → llega a JA
enableMusic(false); enableMusic(false);
} }
if (!Options::audio.sound.enabled) { if (!Options::audio.sound.enabled) {
setSoundVolume(0.0F); // sound_enabled_=true aún → llega a JA setSoundVolume(0.0F); // sound_enabled_=true aún → llega a JA
enableSound(false); enableSound(false);
} }

View File

@@ -5,15 +5,15 @@
#include <string> // Para allocator, operator+, char_traits, string #include <string> // Para allocator, operator+, char_traits, string
#include <vector> // Para vector #include <vector> // Para vector
#include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT #include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/render_info.hpp" // Para RenderInfo #include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "game/options.hpp" // Para Options, options, OptionsVideo, Section #include "game/options.hpp" // Para Options, options, OptionsVideo, Section
#include "game/scene_manager.hpp" // Para SceneManager #include "game/scene_manager.hpp" // Para SceneManager
#include "game/ui/console.hpp" // Para Console #include "game/ui/console.hpp" // Para Console
#include "game/ui/notifier.hpp" // Para Notifier, NotificationText #include "game/ui/notifier.hpp" // Para Notifier, NotificationText
#include "utils/utils.hpp" // Para stringInVector #include "utils/utils.hpp" // Para stringInVector
namespace GlobalInputs { namespace GlobalInputs {

View File

@@ -79,11 +79,11 @@ void RenderInfo::render() const {
std::transform(line.begin(), line.end(), line.begin(), [](unsigned char c) { return std::tolower(c); }); std::transform(line.begin(), line.end(), line.begin(), [](unsigned char c) { return std::tolower(c); });
// Constantes visuales (igual que Console) // Constantes visuales (igual que Console)
static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK
static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN
static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN
static constexpr int TEXT_SIZE = 6; static constexpr int TEXT_SIZE = 6;
static constexpr int PADDING_V = TEXT_SIZE / 2; static constexpr int PADDING_V = TEXT_SIZE / 2;
// Fuente: preferir la de la consola si está disponible // Fuente: preferir la de la consola si está disponible
auto text_obj = (Console::get() != nullptr) ? Console::get()->getText() : Screen::get()->getText(); auto text_obj = (Console::get() != nullptr) ? Console::get()->getText() : Screen::get()->getText();
@@ -96,15 +96,17 @@ void RenderInfo::render() const {
.x = 0.0F, .x = 0.0F,
.y = static_cast<float>(Y), .y = static_cast<float>(Y),
.w = Options::game.width, .w = Options::game.width,
.h = static_cast<float>(TEXT_SIZE + (PADDING_V * 2)) .h = static_cast<float>(TEXT_SIZE + (PADDING_V * 2))};
};
auto game_surface = Screen::get()->getGameSurface(); auto game_surface = Screen::get()->getGameSurface();
game_surface->fillRect(&RECT, BG_COLOR); game_surface->fillRect(&RECT, BG_COLOR);
game_surface->drawRectBorder(&RECT, BORDER_COLOR); game_surface->drawRectBorder(&RECT, BORDER_COLOR);
text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, text_obj->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG,
static_cast<int>(Options::game.width / 2), static_cast<int>(Options::game.width / 2),
Y + PADDING_V, line, 1, MSG_COLOR); Y + PADDING_V,
line,
1,
MSG_COLOR);
} }
// Activa o desactiva el overlay y notifica a Notifier del cambio de offset // Activa o desactiva el overlay y notifica a Notifier del cambio de offset

View File

@@ -12,6 +12,7 @@
#include <string> // Para char_traits, string, operator+, operator== #include <string> // Para char_traits, string, operator+, operator==
#include "core/input/mouse.hpp" // Para updateCursorVisibility #include "core/input/mouse.hpp" // Para updateCursorVisibility
#include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader #include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // Para SDL3GPUShader
#include "core/rendering/surface.hpp" // Para Surface, readPalFile #include "core/rendering/surface.hpp" // Para Surface, readPalFile
#include "core/rendering/text.hpp" // Para Text #include "core/rendering/text.hpp" // Para Text
@@ -19,7 +20,6 @@
#include "core/resources/resource_helper.hpp" // Para ResourceHelper #include "core/resources/resource_helper.hpp" // Para ResourceHelper
#include "core/resources/resource_list.hpp" // Para Asset, AssetType #include "core/resources/resource_list.hpp" // Para Asset, AssetType
#include "game/options.hpp" // Para Options, options, OptionsVideo, Border #include "game/options.hpp" // Para Options, options, OptionsVideo, Border
#include "core/rendering/render_info.hpp" // Para RenderInfo
#include "game/ui/console.hpp" // Para Console #include "game/ui/console.hpp" // Para Console
#include "game/ui/notifier.hpp" // Para Notifier #include "game/ui/notifier.hpp" // Para Notifier
@@ -312,7 +312,7 @@ void Screen::updateZoomFactor() {
int pw{0}, ph{0}; int pw{0}, ph{0};
SDL_GetRenderOutputSize(renderer_, &pw, &ph); SDL_GetRenderOutputSize(renderer_, &pw, &ph);
const float SCALE = std::min(static_cast<float>(pw) / static_cast<float>(window_width_), const float SCALE = std::min(static_cast<float>(pw) / static_cast<float>(window_width_),
static_cast<float>(ph) / static_cast<float>(window_height_)); static_cast<float>(ph) / static_cast<float>(window_height_));
zoom_factor_ = Options::video.integer_scale ? std::floor(SCALE) : SCALE; zoom_factor_ = Options::video.integer_scale ? std::floor(SCALE) : SCALE;
} }
@@ -402,12 +402,14 @@ void Screen::textureToRenderer() {
// Franjas superior e inferior (ancho completo) // Franjas superior e inferior (ancho completo)
std::fill_n(border_pixel_buffer_.data(), OFF_Y * BORDER_W, border_argb_color_); std::fill_n(border_pixel_buffer_.data(), OFF_Y * BORDER_W, border_argb_color_);
std::fill_n(&border_pixel_buffer_[(OFF_Y + GAME_H) * BORDER_W], std::fill_n(&border_pixel_buffer_[(OFF_Y + GAME_H) * BORDER_W],
(BORDER_H - OFF_Y - GAME_H) * BORDER_W, border_argb_color_); (BORDER_H - OFF_Y - GAME_H) * BORDER_W,
border_argb_color_);
// Columnas laterales en las filas del área de juego // Columnas laterales en las filas del área de juego
for (int y = OFF_Y; y < OFF_Y + GAME_H; ++y) { for (int y = OFF_Y; y < OFF_Y + GAME_H; ++y) {
std::fill_n(&border_pixel_buffer_[y * BORDER_W], OFF_X, border_argb_color_); std::fill_n(&border_pixel_buffer_[y * BORDER_W], OFF_X, border_argb_color_);
std::fill_n(&border_pixel_buffer_[y * BORDER_W + OFF_X + GAME_W], std::fill_n(&border_pixel_buffer_[y * BORDER_W + OFF_X + GAME_W],
BORDER_W - OFF_X - GAME_W, border_argb_color_); BORDER_W - OFF_X - GAME_W,
border_argb_color_);
} }
} else { } else {
// Path B: borde dinámico (escena de carga — bandas de colores animadas) // Path B: borde dinámico (escena de carga — bandas de colores animadas)

View File

@@ -53,12 +53,12 @@ class Screen {
void toggleBorder(); // Cambia entre borde visible y no visible void toggleBorder(); // Cambia entre borde visible y no visible
// Paletas y PostFX // Paletas y PostFX
void nextPalette(); // Cambia a la siguiente paleta void nextPalette(); // Cambia a la siguiente paleta
void previousPalette(); // Cambia a la paleta anterior void previousPalette(); // Cambia a la paleta anterior
void setPalete(); // Establece la paleta actual void setPalete(); // Establece la paleta actual
void togglePostFX(); // Cambia el estado del PostFX void togglePostFX(); // Cambia el estado del PostFX
void toggleSupersampling(); // Activa/desactiva el supersampling global void toggleSupersampling(); // Activa/desactiva el supersampling global
void reloadPostFX(); // Recarga el shader del preset actual sin toggle void reloadPostFX(); // Recarga el shader del preset actual sin toggle
void setLinearUpscale(bool linear); // Upscale NEAREST (false) o LINEAR (true) en el paso SS void setLinearUpscale(bool linear); // Upscale NEAREST (false) o LINEAR (true) en el paso SS
void setDownscaleAlgo(int algo); // 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3 void setDownscaleAlgo(int algo); // 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -682,11 +682,7 @@ namespace Rendering {
: 1.0F; : 1.0F;
// ---- Determinar si usar el path Lanczos (SS activo + algo seleccionado) ---- // ---- Determinar si usar el path Lanczos (SS activo + algo seleccionado) ----
const bool USE_LANCZOS = (oversample_ > 1 && downscale_algo_ > 0 const bool USE_LANCZOS = (oversample_ > 1 && downscale_algo_ > 0 && scaled_texture_ != nullptr && postfx_texture_ != nullptr && postfx_offscreen_pipeline_ != nullptr && downscale_pipeline_ != nullptr);
&& scaled_texture_ != nullptr
&& postfx_texture_ != nullptr
&& postfx_offscreen_pipeline_ != nullptr
&& downscale_pipeline_ != nullptr);
if (USE_LANCZOS) { if (USE_LANCZOS) {
// ---- Pass A: PostFX → postfx_texture_ (full scaled size, sin viewport) ---- // ---- Pass A: PostFX → postfx_texture_ (full scaled size, sin viewport) ----
@@ -1029,14 +1025,20 @@ namespace Rendering {
scaled_texture_ = SDL_CreateGPUTexture(device_, &info); scaled_texture_ = SDL_CreateGPUTexture(device_, &info);
if (scaled_texture_ == nullptr) { if (scaled_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create scaled texture %dx%d (factor %d): %s", SDL_Log("SDL3GPUShader: failed to create scaled texture %dx%d (factor %d): %s",
W, H, factor, SDL_GetError()); W,
H,
factor,
SDL_GetError());
return false; return false;
} }
postfx_texture_ = SDL_CreateGPUTexture(device_, &info); postfx_texture_ = SDL_CreateGPUTexture(device_, &info);
if (postfx_texture_ == nullptr) { if (postfx_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create postfx texture %dx%d (factor %d): %s", SDL_Log("SDL3GPUShader: failed to create postfx texture %dx%d (factor %d): %s",
W, H, factor, SDL_GetError()); W,
H,
factor,
SDL_GetError());
SDL_ReleaseGPUTexture(device_, scaled_texture_); SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr; scaled_texture_ = nullptr;
return false; return false;

View File

@@ -106,22 +106,22 @@ namespace Rendering {
SDL_Window* window_ = nullptr; SDL_Window* window_ = nullptr;
SDL_GPUDevice* device_ = nullptr; SDL_GPUDevice* device_ = nullptr;
SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass (→ swapchain o → postfx_texture_) SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass (→ swapchain o → postfx_texture_)
SDL_GPUGraphicsPipeline* postfx_offscreen_pipeline_ = nullptr; // PostFX → postfx_texture_ (B8G8R8A8, solo con Lanczos) SDL_GPUGraphicsPipeline* postfx_offscreen_pipeline_ = nullptr; // PostFX → postfx_texture_ (B8G8R8A8, solo con Lanczos)
SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale pass (solo con SS) SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale pass (solo con SS)
SDL_GPUGraphicsPipeline* downscale_pipeline_ = nullptr; // Lanczos downscale (solo con SS + algo > 0) SDL_GPUGraphicsPipeline* downscale_pipeline_ = nullptr; // Lanczos downscale (solo con SS + algo > 0)
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_) SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
SDL_GPUTexture* scaled_texture_ = nullptr; // Upscale target (game×factor), solo con SS SDL_GPUTexture* scaled_texture_ = nullptr; // Upscale target (game×factor), solo con SS
SDL_GPUTexture* postfx_texture_ = nullptr; // PostFX output a resolución escalada, solo con Lanczos SDL_GPUTexture* postfx_texture_ = nullptr; // PostFX output a resolución escalada, solo con Lanczos
SDL_GPUTransferBuffer* upload_buffer_ = nullptr; SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
SDL_GPUSampler* sampler_ = nullptr; // NEAREST SDL_GPUSampler* sampler_ = nullptr; // NEAREST
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F}; PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F};
int game_width_ = 0; // Dimensiones originales del canvas int game_width_ = 0; // Dimensiones originales del canvas
int game_height_ = 0; int game_height_ = 0;
int ss_factor_ = 0; // Factor SS activo (3, 6, 9...) o 0 si SS desactivado int ss_factor_ = 0; // Factor SS activo (3, 6, 9...) o 0 si SS desactivado
int oversample_ = 1; // SS on/off (1 = off, >1 = on) int oversample_ = 1; // SS on/off (1 = off, >1 = on)
int downscale_algo_ = 1; // 0 = bilinear legacy, 1 = Lanczos2, 2 = Lanczos3 int downscale_algo_ = 1; // 0 = bilinear legacy, 1 = Lanczos2, 2 = Lanczos3
std::string driver_name_; std::string driver_name_;
std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige) std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige)

View File

@@ -1,59 +1,633 @@
#pragma once #pragma once
#include <cstdint>
#include <cstddef> #include <cstddef>
#include <cstdint>
static const uint8_t kupscale_frag_spv[] = { static const uint8_t kupscale_frag_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x03,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x02,
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23,
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x07,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01,
0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x0b,
0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00,
0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x0d,
0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x00,
0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x14,
0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x00,
0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x00,
0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x5f, 0x00,
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x75, 0x76, 0x11,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x02,
0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x06,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x47,
0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x53,
0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c,
0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73,
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x74,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2e,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34,
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x35,
0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x30,
0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x00,
0x38, 0x00, 0x01, 0x00 0x0e,
}; 0x00,
0x03,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x07,
0x00,
0x04,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x10,
0x00,
0x03,
0x00,
0x04,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x03,
0x00,
0x03,
0x00,
0x02,
0x00,
0x00,
0x00,
0xc2,
0x01,
0x00,
0x00,
0x04,
0x00,
0x0a,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x63,
0x70,
0x70,
0x5f,
0x73,
0x74,
0x79,
0x6c,
0x65,
0x5f,
0x6c,
0x69,
0x6e,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x00,
0x04,
0x00,
0x08,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x69,
0x6e,
0x63,
0x6c,
0x75,
0x64,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x05,
0x00,
0x04,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x05,
0x00,
0x05,
0x00,
0x09,
0x00,
0x00,
0x00,
0x6f,
0x75,
0x74,
0x5f,
0x63,
0x6f,
0x6c,
0x6f,
0x72,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x73,
0x63,
0x65,
0x6e,
0x65,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x76,
0x5f,
0x75,
0x76,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x09,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x21,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x22,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x13,
0x00,
0x02,
0x00,
0x02,
0x00,
0x00,
0x00,
0x21,
0x00,
0x03,
0x00,
0x03,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x16,
0x00,
0x03,
0x00,
0x06,
0x00,
0x00,
0x00,
0x20,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x07,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x19,
0x00,
0x09,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x1b,
0x00,
0x03,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x36,
0x00,
0x05,
0x00,
0x02,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0xf8,
0x00,
0x02,
0x00,
0x05,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x57,
0x00,
0x05,
0x00,
0x07,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x3e,
0x00,
0x03,
0x00,
0x09,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0xfd,
0x00,
0x01,
0x00,
0x38,
0x00,
0x01,
0x00};
static const size_t kupscale_frag_spv_size = 628; static const size_t kupscale_frag_spv_size = 628;

View File

@@ -530,18 +530,18 @@ void Surface::toARGBBuffer(Uint32* buffer) const {
const int WIDTH = static_cast<int>(surface_data_->width); const int WIDTH = static_cast<int>(surface_data_->width);
const int HEIGHT = static_cast<int>(surface_data_->height); const int HEIGHT = static_cast<int>(surface_data_->height);
const Uint8* src = surface_data_->data.get(); const Uint8* src = surface_data_->data.get();
// Obtenemos el tamaño de la paleta para evitar accesos fuera de rango // Obtenemos el tamaño de la paleta para evitar accesos fuera de rango
const size_t PAL_SIZE = palette_.size(); const size_t PAL_SIZE = palette_.size();
for (int i = 0; i < WIDTH * HEIGHT; ++i) { for (int i = 0; i < WIDTH * HEIGHT; ++i) {
Uint8 color_index = src[i]; Uint8 color_index = src[i];
// Verificación de seguridad: ¿El índice existe en la paleta? // Verificación de seguridad: ¿El índice existe en la paleta?
if (color_index < PAL_SIZE) { if (color_index < PAL_SIZE) {
buffer[i] = palette_[color_index]; buffer[i] = palette_[color_index];
} else { } else {
buffer[i] = 0xFF000000; // Negro opaco si el índice es erróneo buffer[i] = 0xFF000000; // Negro opaco si el índice es erróneo
} }
} }
} }

View File

@@ -533,7 +533,9 @@ namespace Options {
const auto& a = yaml["audio"]; const auto& a = yaml["audio"];
if (a.contains("enabled")) { if (a.contains("enabled")) {
try { audio.enabled = a["enabled"].get_value<bool>(); } catch (...) {} try {
audio.enabled = a["enabled"].get_value<bool>();
} catch (...) {}
} }
if (a.contains("volume")) { if (a.contains("volume")) {
try { try {
@@ -543,7 +545,9 @@ namespace Options {
if (a.contains("music")) { if (a.contains("music")) {
const auto& m = a["music"]; const auto& m = a["music"];
if (m.contains("enabled")) { if (m.contains("enabled")) {
try { audio.music.enabled = m["enabled"].get_value<bool>(); } catch (...) {} try {
audio.music.enabled = m["enabled"].get_value<bool>();
} catch (...) {}
} }
if (m.contains("volume")) { if (m.contains("volume")) {
try { try {
@@ -554,7 +558,9 @@ namespace Options {
if (a.contains("sound")) { if (a.contains("sound")) {
const auto& s = a["sound"]; const auto& s = a["sound"];
if (s.contains("enabled")) { if (s.contains("enabled")) {
try { audio.sound.enabled = s["enabled"].get_value<bool>(); } catch (...) {} try {
audio.sound.enabled = s["enabled"].get_value<bool>();
} catch (...) {}
} }
if (s.contains("volume")) { if (s.contains("volume")) {
try { try {

View File

@@ -77,15 +77,15 @@ namespace Options {
// Estructura para las opciones de video // Estructura para las opciones de video
struct Video { struct Video {
bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no
bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo
bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false) bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false)
int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3 int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3
Border border{}; // Borde de la pantalla Border border{}; // Borde de la pantalla
std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego
std::string info; // Información sobre el modo de vídeo std::string info; // Información sobre el modo de vídeo

View File

@@ -11,17 +11,17 @@ namespace SceneManager {
// --- Escenas del programa --- // --- Escenas del programa ---
enum class Scene { enum class Scene {
LOGO, // Pantalla del logo LOGO, // Pantalla del logo
LOADING_SCREEN, // Pantalla de carga LOADING_SCREEN, // Pantalla de carga
TITLE, // Pantalla de título/menú principal TITLE, // Pantalla de título/menú principal
CREDITS, // Créditos del juego CREDITS, // Créditos del juego
GAME, // Juego principal GAME, // Juego principal
DEMO, // Modo demostración DEMO, // Modo demostración
GAME_OVER, // Pantalla de game over GAME_OVER, // Pantalla de game over
ENDING, // Final del juego (ending 1) ENDING, // Final del juego (ending 1)
ENDING2, // Final del juego (ending 2) ENDING2, // Final del juego (ending 2)
RESTART_CURRENT, // Especial: reinicia la escena que estaba corriendo RESTART_CURRENT, // Especial: reinicia la escena que estaba corriendo
QUIT // Salir del programa QUIT // Salir del programa
}; };
// --- Opciones para transiciones entre escenas --- // --- Opciones para transiciones entre escenas ---

View File

@@ -7,16 +7,16 @@
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/render_info.hpp" // Para RenderInfo
#include "core/rendering/sprite/sprite.hpp" // Para Sprite #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/sprite/sprite.hpp" // Para Sprite
#include "core/rendering/text.hpp" // Para Text #include "core/rendering/surface.hpp" // Para Surface
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/rendering/text.hpp" // Para Text
#include "game/options.hpp" // Para Options #include "core/resources/resource_cache.hpp" // Para Resource
#include "core/rendering/render_info.hpp" // Para RenderInfo #include "game/options.hpp" // Para Options
#include "game/scene_manager.hpp" // Para SceneManager #include "game/scene_manager.hpp" // Para SceneManager
#include "game/ui/notifier.hpp" // Para Notifier #include "game/ui/notifier.hpp" // Para Notifier
// ── Sistema de comandos ──────────────────────────────────────────────────────── // ── Sistema de comandos ────────────────────────────────────────────────────────
@@ -46,21 +46,23 @@ static auto parseTokens(const std::string& input) -> std::vector<std::string> {
} }
// Macro para comando de toggle booleano (evita repetición en ON/OFF) // Macro para comando de toggle booleano (evita repetición en ON/OFF)
#define BOOL_TOGGLE_CMD(label, getter, toggle_fn) \ #define BOOL_TOGGLE_CMD(label, getter, toggle_fn) \
[](const std::vector<std::string>& args) -> std::string { \ [](const std::vector<std::string>& args) -> std::string { \
if (args.empty()) { \ if (args.empty()) { \
(toggle_fn); \ (toggle_fn); \
return label " " + std::string((getter) ? "ON" : "OFF"); \ return label " " + std::string((getter) ? "ON" : "OFF"); \
} \ } \
if (args[0] == "ON") { \ if (args[0] == "ON") { \
if (getter) { return label " already ON"; } \ if (getter) { return label " already ON"; } \
(toggle_fn); return label " ON"; \ (toggle_fn); \
} \ return label " ON"; \
if (args[0] == "OFF") { \ } \
if (!(getter)) { return label " already OFF"; } \ if (args[0] == "OFF") { \
(toggle_fn); return label " OFF"; \ if (!(getter)) { return label " already OFF"; } \
} \ (toggle_fn); \
return "Usage: " label " [ON|OFF]"; \ return label " OFF"; \
} \
return "Usage: " label " [ON|OFF]"; \
} }
// Texto de ayuda común para HELP y ? // Texto de ayuda común para HELP y ?
@@ -92,408 +94,410 @@ static void printHelp() {
// Tabla de comandos disponibles // Tabla de comandos disponibles
static const std::vector<ConsoleCommand> COMMANDS = { static const std::vector<ConsoleCommand> COMMANDS = {
// SS [ON|OFF] — Supersampling (Ctrl+F4) // SS [ON|OFF] — Supersampling (Ctrl+F4)
{.keyword = "SS", .execute = BOOL_TOGGLE_CMD("Supersampling", {.keyword = "SS", .execute = BOOL_TOGGLE_CMD("Supersampling", Options::video.supersampling, Screen::get()->toggleSupersampling())},
Options::video.supersampling,
Screen::get()->toggleSupersampling())},
// POSTFX [ON|OFF|NEXT] — PostFX y presets (F4 / Shift+F4) // POSTFX [ON|OFF|NEXT] — PostFX y presets (F4 / Shift+F4)
{.keyword = "POSTFX", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "POSTFX", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { if (args.empty()) {
Screen::get()->togglePostFX(); Screen::get()->togglePostFX();
return std::string("PostFX ") + (Options::video.postfx ? "ON" : "OFF"); return std::string("PostFX ") + (Options::video.postfx ? "ON" : "OFF");
} }
if (args[0] == "ON") { if (args[0] == "ON") {
if (Options::video.postfx) { return "PostFX already ON"; } if (Options::video.postfx) { return "PostFX already ON"; }
Screen::get()->togglePostFX(); return "PostFX ON"; Screen::get()->togglePostFX();
} return "PostFX ON";
if (args[0] == "OFF") { }
if (!Options::video.postfx) { return "PostFX already OFF"; } if (args[0] == "OFF") {
Screen::get()->togglePostFX(); return "PostFX OFF"; if (!Options::video.postfx) { return "PostFX already OFF"; }
} Screen::get()->togglePostFX();
if (args[0] == "NEXT") { return "PostFX OFF";
if (Options::postfx_presets.empty()) { return "No presets available"; } }
Options::current_postfx_preset = if (args[0] == "NEXT") {
(Options::current_postfx_preset + 1) % if (Options::postfx_presets.empty()) { return "No presets available"; }
static_cast<int>(Options::postfx_presets.size()); Options::current_postfx_preset =
Screen::get()->reloadPostFX(); (Options::current_postfx_preset + 1) %
return "PostFX preset: " + static_cast<int>(Options::postfx_presets.size());
Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name; Screen::get()->reloadPostFX();
} return "PostFX preset: " +
return "Usage: POSTFX [ON|OFF|NEXT]"; Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name;
}}, }
return "Usage: POSTFX [ON|OFF|NEXT]";
}},
// BORDER [ON|OFF] — Borde decorativo (B) // BORDER [ON|OFF] — Borde decorativo (B)
{.keyword = "BORDER", .execute = BOOL_TOGGLE_CMD("Border", {.keyword = "BORDER", .execute = BOOL_TOGGLE_CMD("Border", Options::video.border.enabled, Screen::get()->toggleBorder())},
Options::video.border.enabled,
Screen::get()->toggleBorder())},
// FULLSCREEN [ON|OFF [PLEASE]] — Pantalla completa (F3); OFF bloqueado en kiosk sin PLEASE // FULLSCREEN [ON|OFF [PLEASE]] — Pantalla completa (F3); OFF bloqueado en kiosk sin PLEASE
{.keyword = "FULLSCREEN", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "FULLSCREEN", .execute = [](const std::vector<std::string>& args) -> std::string {
const bool EXPLICIT_ON = !args.empty() && args[0] == "ON"; const bool EXPLICIT_ON = !args.empty() && args[0] == "ON";
const bool EXPLICIT_OFF = !args.empty() && args[0] == "OFF"; const bool EXPLICIT_OFF = !args.empty() && args[0] == "OFF";
const bool WITH_PLEASE = !args.empty() && args.back() == "PLEASE"; const bool WITH_PLEASE = !args.empty() && args.back() == "PLEASE";
const bool IS_TOGGLE = args.empty(); const bool IS_TOGGLE = args.empty();
const bool TURNING_OFF = EXPLICIT_OFF || (IS_TOGGLE && Options::video.fullscreen); const bool TURNING_OFF = EXPLICIT_OFF || (IS_TOGGLE && Options::video.fullscreen);
if (TURNING_OFF && Options::kiosk.enabled && !WITH_PLEASE) { if (TURNING_OFF && Options::kiosk.enabled && !WITH_PLEASE) {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
if (EXPLICIT_ON) { if (EXPLICIT_ON) {
if (Options::video.fullscreen) { return "Fullscreen already ON"; } if (Options::video.fullscreen) { return "Fullscreen already ON"; }
Screen::get()->toggleVideoMode(); return "Fullscreen ON"; Screen::get()->toggleVideoMode();
} return "Fullscreen ON";
if (EXPLICIT_OFF) { }
if (!Options::video.fullscreen) { return "Fullscreen already OFF"; } if (EXPLICIT_OFF) {
Screen::get()->toggleVideoMode(); return "Fullscreen OFF"; if (!Options::video.fullscreen) { return "Fullscreen already OFF"; }
} Screen::get()->toggleVideoMode();
if (IS_TOGGLE) { return "Fullscreen OFF";
Screen::get()->toggleVideoMode(); }
return std::string("Fullscreen ") + (Options::video.fullscreen ? "ON" : "OFF"); if (IS_TOGGLE) {
} Screen::get()->toggleVideoMode();
return "Usage: FULLSCREEN [ON|OFF]"; return std::string("Fullscreen ") + (Options::video.fullscreen ? "ON" : "OFF");
}}, }
return "Usage: FULLSCREEN [ON|OFF]";
}},
// ZOOM UP/DOWN — Zoom de ventana (F1/F2) // ZOOM UP/DOWN — Zoom de ventana (F1/F2)
{.keyword = "ZOOM", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "ZOOM", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { return "Usage: ZOOM [UP|DOWN]"; } if (args.empty()) { return "Usage: ZOOM [UP|DOWN]"; }
if (args[0] == "UP") { if (args[0] == "UP") {
if (!Screen::get()->incWindowZoom()) { return "Max zoom reached"; } if (!Screen::get()->incWindowZoom()) { return "Max zoom reached"; }
return "Zoom " + std::to_string(Options::window.zoom); return "Zoom " + std::to_string(Options::window.zoom);
} }
if (args[0] == "DOWN") { if (args[0] == "DOWN") {
if (!Screen::get()->decWindowZoom()) { return "Min zoom reached"; } if (!Screen::get()->decWindowZoom()) { return "Min zoom reached"; }
return "Zoom " + std::to_string(Options::window.zoom); return "Zoom " + std::to_string(Options::window.zoom);
} }
return "Usage: ZOOM [UP|DOWN]"; return "Usage: ZOOM [UP|DOWN]";
}}, }},
// INTSCALE [ON|OFF] — Escalado entero (F7) // INTSCALE [ON|OFF] — Escalado entero (F7)
{.keyword = "INTSCALE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "INTSCALE", .execute = [](const std::vector<std::string>& args) -> std::string {
const bool ON = args.empty() ? !Options::video.integer_scale const bool ON = args.empty() ? !Options::video.integer_scale
: (args[0] == "ON"); : (args[0] == "ON");
if (!args.empty() && args[0] != "ON" && args[0] != "OFF") { if (!args.empty() && args[0] != "ON" && args[0] != "OFF") {
return "Usage: INTSCALE [ON|OFF]"; return "Usage: INTSCALE [ON|OFF]";
} }
if (ON == Options::video.integer_scale) { if (ON == Options::video.integer_scale) {
return std::string("IntScale already ") + (ON ? "ON" : "OFF"); return std::string("IntScale already ") + (ON ? "ON" : "OFF");
} }
Screen::get()->toggleIntegerScale(); Screen::get()->toggleIntegerScale();
Screen::get()->setVideoMode(Options::video.fullscreen); Screen::get()->setVideoMode(Options::video.fullscreen);
return std::string("IntScale ") + (Options::video.integer_scale ? "ON" : "OFF"); return std::string("IntScale ") + (Options::video.integer_scale ? "ON" : "OFF");
}}, }},
// UPSCALE [NEAREST|LINEAR] — Filtro de upscale en supersampling // UPSCALE [NEAREST|LINEAR] — Filtro de upscale en supersampling
{.keyword = "UPSCALE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "UPSCALE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { if (args.empty()) {
Screen::get()->setLinearUpscale(!Options::video.linear_upscale); Screen::get()->setLinearUpscale(!Options::video.linear_upscale);
return std::string("Upscale: ") + (Options::video.linear_upscale ? "Linear" : "Nearest"); return std::string("Upscale: ") + (Options::video.linear_upscale ? "Linear" : "Nearest");
} }
if (args[0] == "NEAREST") { if (args[0] == "NEAREST") {
if (!Options::video.linear_upscale) { return "Upscale already Nearest"; } if (!Options::video.linear_upscale) { return "Upscale already Nearest"; }
Screen::get()->setLinearUpscale(false); return "Upscale: Nearest"; Screen::get()->setLinearUpscale(false);
} return "Upscale: Nearest";
if (args[0] == "LINEAR") { }
if (Options::video.linear_upscale) { return "Upscale already Linear"; } if (args[0] == "LINEAR") {
Screen::get()->setLinearUpscale(true); return "Upscale: Linear"; if (Options::video.linear_upscale) { return "Upscale already Linear"; }
} Screen::get()->setLinearUpscale(true);
return "Usage: UPSCALE [NEAREST|LINEAR]"; return "Upscale: Linear";
}}, }
return "Usage: UPSCALE [NEAREST|LINEAR]";
}},
// DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3] — Algoritmo de downscale en supersampling // DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3] — Algoritmo de downscale en supersampling
{.keyword = "DOWNSCALE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "DOWNSCALE", .execute = [](const std::vector<std::string>& args) -> std::string {
static const std::array<std::string_view, 3> NAMES = {"Bilinear", "Lanczos2", "Lanczos3"}; static const std::array<std::string_view, 3> NAMES = {"Bilinear", "Lanczos2", "Lanczos3"};
if (args.empty()) { if (args.empty()) {
return std::string("Downscale: ") + std::string(NAMES[static_cast<size_t>(Options::video.downscale_algo)]); return std::string("Downscale: ") + std::string(NAMES[static_cast<size_t>(Options::video.downscale_algo)]);
} }
int algo = -1; int algo = -1;
if (args[0] == "BILINEAR") { algo = 0; } if (args[0] == "BILINEAR") { algo = 0; }
if (args[0] == "LANCZOS2") { algo = 1; } if (args[0] == "LANCZOS2") { algo = 1; }
if (args[0] == "LANCZOS3") { algo = 2; } if (args[0] == "LANCZOS3") { algo = 2; }
if (algo == -1) { return "Usage: DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]"; } if (algo == -1) { return "Usage: DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]"; }
if (Options::video.downscale_algo == algo) { if (Options::video.downscale_algo == algo) {
return std::string("Downscale already ") + std::string(NAMES[static_cast<size_t>(algo)]); return std::string("Downscale already ") + std::string(NAMES[static_cast<size_t>(algo)]);
} }
Screen::get()->setDownscaleAlgo(algo); Screen::get()->setDownscaleAlgo(algo);
return std::string("Downscale: ") + std::string(NAMES[static_cast<size_t>(algo)]); return std::string("Downscale: ") + std::string(NAMES[static_cast<size_t>(algo)]);
}}, }},
// VSYNC [ON|OFF] — Sincronización vertical // VSYNC [ON|OFF] — Sincronización vertical
{.keyword = "VSYNC", .execute = BOOL_TOGGLE_CMD("VSync", {.keyword = "VSYNC", .execute = BOOL_TOGGLE_CMD("VSync", Options::video.vertical_sync, Screen::get()->toggleVSync())},
Options::video.vertical_sync,
Screen::get()->toggleVSync())},
// DRIVER [LIST|AUTO|<nombre>] — Driver GPU (aplica en el próximo arranque) // DRIVER [LIST|AUTO|<nombre>] — Driver GPU (aplica en el próximo arranque)
{.keyword = "DRIVER", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "DRIVER", .execute = [](const std::vector<std::string>& args) -> std::string {
// Sin argumentos: muestra el driver activo (permitido en kiosk) // Sin argumentos: muestra el driver activo (permitido en kiosk)
if (args.empty()) { if (args.empty()) {
const auto& driver = Screen::get()->getGPUDriver(); const auto& driver = Screen::get()->getGPUDriver();
return "GPU: " + (driver.empty() ? std::string("sdl") : driver); return "GPU: " + (driver.empty() ? std::string("sdl") : driver);
} }
// LIST: lista drivers disponibles marcando el activo con * (permitido en kiosk) // LIST: lista drivers disponibles marcando el activo con * (permitido en kiosk)
if (args[0] == "LIST") { if (args[0] == "LIST") {
const int COUNT = SDL_GetNumGPUDrivers(); const int COUNT = SDL_GetNumGPUDrivers();
if (COUNT <= 0) { return "No GPU drivers found"; } if (COUNT <= 0) { return "No GPU drivers found"; }
const std::string& active = Screen::get()->getGPUDriver(); const std::string& active = Screen::get()->getGPUDriver();
std::string result = "Drivers:"; std::string result = "Drivers:";
for (int i = 0; i < COUNT; ++i) { for (int i = 0; i < COUNT; ++i) {
const char* name = SDL_GetGPUDriver(i); const char* name = SDL_GetGPUDriver(i);
if (name != nullptr) { if (name != nullptr) {
result += ' '; result += ' ';
result += name; result += name;
if (active == name) { result += '*'; } if (active == name) { result += '*'; }
} }
} }
SDL_Log("SDL GPU drivers: %s", result.c_str()); SDL_Log("SDL GPU drivers: %s", result.c_str());
return result; return result;
} }
// Cambiar driver: bloqueado en kiosk salvo PLEASE // Cambiar driver: bloqueado en kiosk salvo PLEASE
const bool HAS_PLEASE = std::ranges::find(args, std::string("PLEASE")) != args.end(); const bool HAS_PLEASE = std::ranges::find(args, std::string("PLEASE")) != args.end();
if (Options::kiosk.enabled && !HAS_PLEASE) { if (Options::kiosk.enabled && !HAS_PLEASE) {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
if (args[0] == "AUTO") { if (args[0] == "AUTO") {
Options::video.gpu_preferred_driver.clear(); Options::video.gpu_preferred_driver.clear();
Options::saveToFile(); Options::saveToFile();
return "Driver: auto (restart)"; return "Driver: auto (restart)";
} }
if (args[0] == "NONE") { if (args[0] == "NONE") {
Options::video.gpu_preferred_driver = "none"; Options::video.gpu_preferred_driver = "none";
Options::saveToFile(); Options::saveToFile();
return "Driver: none (SDL fallback, restart)"; return "Driver: none (SDL fallback, restart)";
} }
std::string driver_lower = args[0]; std::string driver_lower = args[0];
std::ranges::transform(driver_lower, driver_lower.begin(), ::tolower); std::ranges::transform(driver_lower, driver_lower.begin(), ::tolower);
// Validar que el nombre existe en la lista de drivers SDL // Validar que el nombre existe en la lista de drivers SDL
const int COUNT = SDL_GetNumGPUDrivers(); const int COUNT = SDL_GetNumGPUDrivers();
bool found = false; bool found = false;
for (int i = 0; i < COUNT && !found; ++i) { for (int i = 0; i < COUNT && !found; ++i) {
const char* name = SDL_GetGPUDriver(i); const char* name = SDL_GetGPUDriver(i);
if (name != nullptr && driver_lower == name) { found = true; } if (name != nullptr && driver_lower == name) { found = true; }
} }
if (!found) { if (!found) {
return "Unknown driver: " + driver_lower + ". Use DRIVER LIST or NONE"; return "Unknown driver: " + driver_lower + ". Use DRIVER LIST or NONE";
} }
Options::video.gpu_preferred_driver = driver_lower; Options::video.gpu_preferred_driver = driver_lower;
Options::saveToFile(); Options::saveToFile();
return "Driver: " + driver_lower + " (restart)"; return "Driver: " + driver_lower + " (restart)";
}}, }},
// PALETTE NEXT/PREV — Paleta de colores (F5/F6) // PALETTE NEXT/PREV — Paleta de colores (F5/F6)
{.keyword = "PALETTE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "PALETTE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { return "Usage: PALETTE [NEXT|PREV]"; } if (args.empty()) { return "Usage: PALETTE [NEXT|PREV]"; }
if (args[0] == "NEXT") { if (args[0] == "NEXT") {
Screen::get()->nextPalette(); Screen::get()->nextPalette();
return "Palette: " + Options::video.palette; return "Palette: " + Options::video.palette;
} }
if (args[0] == "PREV") { if (args[0] == "PREV") {
Screen::get()->previousPalette(); Screen::get()->previousPalette();
return "Palette: " + Options::video.palette; return "Palette: " + Options::video.palette;
} }
return "Usage: PALETTE [NEXT|PREV]"; return "Usage: PALETTE [NEXT|PREV]";
}}, }},
#ifdef _DEBUG #ifdef _DEBUG
// DEBUG [ON|OFF] — Overlay de debug (F12, solo en builds debug) // DEBUG [ON|OFF] — Overlay de debug (F12, solo en builds debug)
{.keyword = "DEBUG", .execute = BOOL_TOGGLE_CMD("Debug overlay", {.keyword = "DEBUG", .execute = BOOL_TOGGLE_CMD("Debug overlay", RenderInfo::get()->isActive(), RenderInfo::get()->toggle())},
RenderInfo::get()->isActive(),
RenderInfo::get()->toggle())},
// SHOW FPS / HIDE FPS — Aliases de DEBUG ON / DEBUG OFF // SHOW FPS / HIDE FPS — Aliases de DEBUG ON / DEBUG OFF
{.keyword = "SHOW", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "SHOW", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty() || args[0] != "FPS") { return "Usage: SHOW FPS"; } if (args.empty() || args[0] != "FPS") { return "Usage: SHOW FPS"; }
if (RenderInfo::get()->isActive()) { return "Debug overlay already ON"; } if (RenderInfo::get()->isActive()) { return "Debug overlay already ON"; }
RenderInfo::get()->toggle(); return "Debug overlay ON"; RenderInfo::get()->toggle();
}}, return "Debug overlay ON";
}},
{.keyword = "HIDE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "HIDE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty() || args[0] != "FPS") { return "Usage: HIDE FPS"; } if (args.empty() || args[0] != "FPS") { return "Usage: HIDE FPS"; }
if (!RenderInfo::get()->isActive()) { return "Debug overlay already OFF"; } if (!RenderInfo::get()->isActive()) { return "Debug overlay already OFF"; }
RenderInfo::get()->toggle(); return "Debug overlay OFF"; RenderInfo::get()->toggle();
}}, return "Debug overlay OFF";
}},
#endif #endif
// SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART] — Cambiar o reiniciar escena // SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART] — Cambiar o reiniciar escena
{.keyword = "SCENE", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "SCENE", .execute = [](const std::vector<std::string>& args) -> std::string {
if (Options::kiosk.enabled) { return "Not allowed in kiosk mode"; } if (Options::kiosk.enabled) { return "Not allowed in kiosk mode"; }
if (args.empty()) { return "Usage: SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART]"; } if (args.empty()) { return "Usage: SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART]"; }
// RESTART: reinicia la escena actual (funciona desde cualquier escena) // RESTART: reinicia la escena actual (funciona desde cualquier escena)
if (args[0] == "RESTART") { if (args[0] == "RESTART") {
SceneManager::scene_before_restart = SceneManager::current; SceneManager::scene_before_restart = SceneManager::current;
SceneManager::current = SceneManager::Scene::RESTART_CURRENT; SceneManager::current = SceneManager::Scene::RESTART_CURRENT;
return "Restarting..."; return "Restarting...";
} }
// Para el resto: si pedimos la escena que ya está activa → también reiniciar // Para el resto: si pedimos la escena que ya está activa → también reiniciar
const auto GO_TO = [](SceneManager::Scene target, const std::string& label) -> std::string { const auto GO_TO = [](SceneManager::Scene target, const std::string& label) -> std::string {
if (SceneManager::current == target) { if (SceneManager::current == target) {
SceneManager::scene_before_restart = target; SceneManager::scene_before_restart = target;
SceneManager::current = SceneManager::Scene::RESTART_CURRENT; SceneManager::current = SceneManager::Scene::RESTART_CURRENT;
} else { } else {
SceneManager::current = target; SceneManager::current = target;
} }
return "Scene: " + label; return "Scene: " + label;
}; };
if (args[0] == "LOGO") { return GO_TO(SceneManager::Scene::LOGO, "Logo"); } if (args[0] == "LOGO") { return GO_TO(SceneManager::Scene::LOGO, "Logo"); }
if (args[0] == "LOADING") { return GO_TO(SceneManager::Scene::LOADING_SCREEN, "Loading"); } if (args[0] == "LOADING") { return GO_TO(SceneManager::Scene::LOADING_SCREEN, "Loading"); }
if (args[0] == "TITLE") { return GO_TO(SceneManager::Scene::TITLE, "Title"); } if (args[0] == "TITLE") { return GO_TO(SceneManager::Scene::TITLE, "Title"); }
if (args[0] == "CREDITS") { return GO_TO(SceneManager::Scene::CREDITS, "Credits"); } if (args[0] == "CREDITS") { return GO_TO(SceneManager::Scene::CREDITS, "Credits"); }
if (args[0] == "GAME") { return GO_TO(SceneManager::Scene::GAME, "Game"); } if (args[0] == "GAME") { return GO_TO(SceneManager::Scene::GAME, "Game"); }
if (args[0] == "ENDING") { return GO_TO(SceneManager::Scene::ENDING, "Ending"); } if (args[0] == "ENDING") { return GO_TO(SceneManager::Scene::ENDING, "Ending"); }
if (args[0] == "ENDING2") { return GO_TO(SceneManager::Scene::ENDING2, "Ending 2"); } if (args[0] == "ENDING2") { return GO_TO(SceneManager::Scene::ENDING2, "Ending 2"); }
return "Unknown scene: " + args[0]; return "Unknown scene: " + args[0];
}}, }},
// RESTART — Reiniciar desde el principio (equivale a SCENE LOGO) // RESTART — Reiniciar desde el principio (equivale a SCENE LOGO)
{.keyword = "RESTART", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "RESTART", .execute = [](const std::vector<std::string>&) -> std::string {
SceneManager::current = SceneManager::Scene::LOGO; SceneManager::current = SceneManager::Scene::LOGO;
return "Restarting..."; return "Restarting...";
}}, }},
// KIOSK [ON|OFF PLEASE|PLEASE] — Modo kiosko // KIOSK [ON|OFF PLEASE|PLEASE] — Modo kiosko
{.keyword = "KIOSK", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "KIOSK", .execute = [](const std::vector<std::string>& args) -> std::string {
const bool DISABLE = (!args.empty() && args[0] == "PLEASE") || const bool DISABLE = (!args.empty() && args[0] == "PLEASE") ||
(args.size() >= 2 && args[0] == "OFF" && args[1] == "PLEASE"); (args.size() >= 2 && args[0] == "OFF" && args[1] == "PLEASE");
if (DISABLE) { if (DISABLE) {
Options::kiosk.enabled = false; Options::kiosk.enabled = false;
return "Kiosk mode OFF"; return "Kiosk mode OFF";
} }
if (!args.empty() && args[0] == "OFF") { if (!args.empty() && args[0] == "OFF") {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
if (args.empty() || args[0] == "ON") { if (args.empty() || args[0] == "ON") {
if (Options::kiosk.enabled) { return "Kiosk mode already ON"; } if (Options::kiosk.enabled) { return "Kiosk mode already ON"; }
Options::kiosk.enabled = true; Options::kiosk.enabled = true;
if (!Options::video.fullscreen) { Screen::get()->toggleVideoMode(); } if (!Options::video.fullscreen) { Screen::get()->toggleVideoMode(); }
return "Kiosk mode ON"; return "Kiosk mode ON";
} }
return "Usage: KIOSK [ON]"; return "Usage: KIOSK [ON]";
}}, }},
// AUDIO [ON|OFF|VOL <0-100>] — Audio maestro (estado + volumen) // AUDIO [ON|OFF|VOL <0-100>] — Audio maestro (estado + volumen)
{.keyword = "AUDIO", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "AUDIO", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { if (args.empty()) {
const int VOL = static_cast<int>(Options::audio.volume * 100.0F); const int VOL = static_cast<int>(Options::audio.volume * 100.0F);
return std::string("Audio ") + (Options::audio.enabled ? "ON" : "OFF") + return std::string("Audio ") + (Options::audio.enabled ? "ON" : "OFF") +
" vol:" + std::to_string(VOL); " vol:" + std::to_string(VOL);
} }
if (args[0] == "ON") { if (args[0] == "ON") {
if (Options::audio.enabled) { return "Audio already ON"; } if (Options::audio.enabled) { return "Audio already ON"; }
Options::audio.enabled = true; Options::audio.enabled = true;
Audio::get()->enable(true); Audio::get()->enable(true);
return "Audio ON"; return "Audio ON";
} }
if (args[0] == "OFF") { if (args[0] == "OFF") {
if (!Options::audio.enabled) { return "Audio already OFF"; } if (!Options::audio.enabled) { return "Audio already OFF"; }
Options::audio.enabled = false; Options::audio.enabled = false;
Audio::get()->enable(false); Audio::get()->enable(false);
return "Audio OFF"; return "Audio OFF";
} }
if (args[0] == "VOL" && args.size() >= 2) { if (args[0] == "VOL" && args.size() >= 2) {
try { try {
const int VAL = std::stoi(args[1]); const int VAL = std::stoi(args[1]);
if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; } if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; }
Options::audio.volume = static_cast<float>(VAL) / 100.0F; Options::audio.volume = static_cast<float>(VAL) / 100.0F;
Audio::get()->enable(Options::audio.enabled); Audio::get()->enable(Options::audio.enabled);
return "Audio vol:" + std::to_string(VAL); return "Audio vol:" + std::to_string(VAL);
} catch (...) { return "Usage: AUDIO VOL <0-100>"; } } catch (...) { return "Usage: AUDIO VOL <0-100>"; }
} }
return "Usage: AUDIO [ON|OFF|VOL N]"; return "Usage: AUDIO [ON|OFF|VOL N]";
}}, }},
// MUSIC [ON|OFF|VOL <0-100>] — Volumen e interruptor de música // MUSIC [ON|OFF|VOL <0-100>] — Volumen e interruptor de música
{.keyword = "MUSIC", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "MUSIC", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { if (args.empty()) {
const int VOL = static_cast<int>(Options::audio.music.volume * 100.0F); const int VOL = static_cast<int>(Options::audio.music.volume * 100.0F);
return std::string("Music ") + (Options::audio.music.enabled ? "ON" : "OFF") + return std::string("Music ") + (Options::audio.music.enabled ? "ON" : "OFF") +
" vol:" + std::to_string(VOL); " vol:" + std::to_string(VOL);
} }
if (args[0] == "ON") { if (args[0] == "ON") {
if (Options::audio.music.enabled) { return "Music already ON"; } if (Options::audio.music.enabled) { return "Music already ON"; }
Options::audio.music.enabled = true; Options::audio.music.enabled = true;
Audio::get()->enableMusic(true); Audio::get()->enableMusic(true);
Audio::get()->setMusicVolume(Options::audio.music.volume); Audio::get()->setMusicVolume(Options::audio.music.volume);
return "Music ON"; return "Music ON";
} }
if (args[0] == "OFF") { if (args[0] == "OFF") {
if (!Options::audio.music.enabled) { return "Music already OFF"; } if (!Options::audio.music.enabled) { return "Music already OFF"; }
Audio::get()->setMusicVolume(0.0F); Audio::get()->setMusicVolume(0.0F);
Audio::get()->enableMusic(false); Audio::get()->enableMusic(false);
Options::audio.music.enabled = false; Options::audio.music.enabled = false;
return "Music OFF"; return "Music OFF";
} }
if (args[0] == "VOL" && args.size() >= 2) { if (args[0] == "VOL" && args.size() >= 2) {
try { try {
const int VAL = std::stoi(args[1]); const int VAL = std::stoi(args[1]);
if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; } if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; }
Options::audio.music.volume = static_cast<float>(VAL) / 100.0F; Options::audio.music.volume = static_cast<float>(VAL) / 100.0F;
if (Options::audio.music.enabled) { if (Options::audio.music.enabled) {
Audio::get()->setMusicVolume(Options::audio.music.volume); Audio::get()->setMusicVolume(Options::audio.music.volume);
} }
return "Music vol:" + std::to_string(VAL); return "Music vol:" + std::to_string(VAL);
} catch (...) { return "Usage: MUSIC VOL <0-100>"; } } catch (...) { return "Usage: MUSIC VOL <0-100>"; }
} }
return "Usage: MUSIC [ON|OFF|VOL N]"; return "Usage: MUSIC [ON|OFF|VOL N]";
}}, }},
// SOUND [ON|OFF|VOL <0-100>] — Volumen e interruptor de efectos de sonido // SOUND [ON|OFF|VOL <0-100>] — Volumen e interruptor de efectos de sonido
{.keyword = "SOUND", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "SOUND", .execute = [](const std::vector<std::string>& args) -> std::string {
if (args.empty()) { if (args.empty()) {
const int VOL = static_cast<int>(Options::audio.sound.volume * 100.0F); const int VOL = static_cast<int>(Options::audio.sound.volume * 100.0F);
return std::string("Sound ") + (Options::audio.sound.enabled ? "ON" : "OFF") + return std::string("Sound ") + (Options::audio.sound.enabled ? "ON" : "OFF") +
" vol:" + std::to_string(VOL); " vol:" + std::to_string(VOL);
} }
if (args[0] == "ON") { if (args[0] == "ON") {
if (Options::audio.sound.enabled) { return "Sound already ON"; } if (Options::audio.sound.enabled) { return "Sound already ON"; }
Options::audio.sound.enabled = true; Options::audio.sound.enabled = true;
Audio::get()->enableSound(true); Audio::get()->enableSound(true);
Audio::get()->setSoundVolume(Options::audio.sound.volume); Audio::get()->setSoundVolume(Options::audio.sound.volume);
return "Sound ON"; return "Sound ON";
} }
if (args[0] == "OFF") { if (args[0] == "OFF") {
if (!Options::audio.sound.enabled) { return "Sound already OFF"; } if (!Options::audio.sound.enabled) { return "Sound already OFF"; }
Audio::get()->setSoundVolume(0.0F); Audio::get()->setSoundVolume(0.0F);
Audio::get()->enableSound(false); Audio::get()->enableSound(false);
Options::audio.sound.enabled = false; Options::audio.sound.enabled = false;
return "Sound OFF"; return "Sound OFF";
} }
if (args[0] == "VOL" && args.size() >= 2) { if (args[0] == "VOL" && args.size() >= 2) {
try { try {
const int VAL = std::stoi(args[1]); const int VAL = std::stoi(args[1]);
if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; } if (VAL < 0 || VAL > 100) { return "Vol must be 0-100"; }
Options::audio.sound.volume = static_cast<float>(VAL) / 100.0F; Options::audio.sound.volume = static_cast<float>(VAL) / 100.0F;
if (Options::audio.sound.enabled) { if (Options::audio.sound.enabled) {
Audio::get()->setSoundVolume(Options::audio.sound.volume); Audio::get()->setSoundVolume(Options::audio.sound.volume);
} }
return "Sound vol:" + std::to_string(VAL); return "Sound vol:" + std::to_string(VAL);
} catch (...) { return "Usage: SOUND VOL <0-100>"; } } catch (...) { return "Usage: SOUND VOL <0-100>"; }
} }
return "Usage: SOUND [ON|OFF|VOL N]"; return "Usage: SOUND [ON|OFF|VOL N]";
}}, }},
// EXIT / QUIT — Cerrar la aplicacion (bloqueado en kiosk) // EXIT / QUIT — Cerrar la aplicacion (bloqueado en kiosk)
{.keyword = "EXIT", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "EXIT", .execute = [](const std::vector<std::string>& args) -> std::string {
if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) { if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
SceneManager::current = SceneManager::Scene::QUIT; SceneManager::current = SceneManager::Scene::QUIT;
return "Quitting..."; return "Quitting...";
}}, }},
{.keyword = "QUIT", .execute = [](const std::vector<std::string>& args) -> std::string { {.keyword = "QUIT", .execute = [](const std::vector<std::string>& args) -> std::string {
if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) { if (Options::kiosk.enabled && (args.empty() || args[0] != "PLEASE")) {
return "Not allowed in kiosk mode"; return "Not allowed in kiosk mode";
} }
SceneManager::current = SceneManager::Scene::QUIT; SceneManager::current = SceneManager::Scene::QUIT;
return "Quitting..."; return "Quitting...";
}}, }},
// HELP / ? — Muestra ayuda en la terminal del sistema // HELP / ? — Muestra ayuda en la terminal del sistema
{.keyword = "HELP", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "HELP", .execute = [](const std::vector<std::string>&) -> std::string {
printHelp(); return "Help printed to terminal"; printHelp();
}}, return "Help printed to terminal";
}},
{.keyword = "?", .execute = [](const std::vector<std::string>&) -> std::string { {.keyword = "?", .execute = [](const std::vector<std::string>&) -> std::string {
printHelp(); return "Help printed to terminal"; printHelp();
}}, return "Help printed to terminal";
}},
}; };
// ── Singleton ───────────────────────────────────────────────────────────────── // ── Singleton ─────────────────────────────────────────────────────────────────
@@ -581,7 +585,7 @@ void Console::update(float delta_time) {
cursor_timer_ += delta_time; cursor_timer_ += delta_time;
const float THRESHOLD = cursor_visible_ ? CURSOR_ON_TIME : CURSOR_OFF_TIME; const float THRESHOLD = cursor_visible_ ? CURSOR_ON_TIME : CURSOR_OFF_TIME;
if (cursor_timer_ >= THRESHOLD) { if (cursor_timer_ >= THRESHOLD) {
cursor_timer_ = 0.0F; cursor_timer_ = 0.0F;
cursor_visible_ = !cursor_visible_; cursor_visible_ = !cursor_visible_;
} }
} }
@@ -626,16 +630,16 @@ void Console::render() {
void Console::toggle() { void Console::toggle() {
switch (status_) { switch (status_) {
case Status::HIDDEN: case Status::HIDDEN:
status_ = Status::RISING; status_ = Status::RISING;
input_line_.clear(); input_line_.clear();
cursor_timer_ = 0.0F; cursor_timer_ = 0.0F;
cursor_visible_ = true; cursor_visible_ = true;
SDL_StartTextInput(SDL_GetKeyboardFocus()); SDL_StartTextInput(SDL_GetKeyboardFocus());
if (Notifier::get() != nullptr) { Notifier::get()->addYOffset(static_cast<int>(height_)); } if (Notifier::get() != nullptr) { Notifier::get()->addYOffset(static_cast<int>(height_)); }
break; break;
case Status::ACTIVE: case Status::ACTIVE:
status_ = Status::VANISHING; status_ = Status::VANISHING;
msg_line_ = std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION); msg_line_ = std::string(CONSOLE_NAME) + " " + std::string(CONSOLE_VERSION);
history_index_ = -1; history_index_ = -1;
saved_input_.clear(); saved_input_.clear();
SDL_StopTextInput(SDL_GetKeyboardFocus()); SDL_StopTextInput(SDL_GetKeyboardFocus());
@@ -724,7 +728,7 @@ void Console::processCommand() {
input_line_.clear(); input_line_.clear();
history_index_ = -1; history_index_ = -1;
saved_input_.clear(); saved_input_.clear();
cursor_timer_ = 0.0F; cursor_timer_ = 0.0F;
cursor_visible_ = true; cursor_visible_ = true;
} }

View File

@@ -24,8 +24,8 @@ class Console {
void handleEvent(const SDL_Event& event); void handleEvent(const SDL_Event& event);
// Consultas // Consultas
auto isActive() -> bool; // true si RISING, ACTIVE o VANISHING auto isActive() -> bool; // true si RISING, ACTIVE o VANISHING
auto getVisibleHeight() -> int; // Píxeles visibles actuales (0 = oculta, height_ = totalmente visible) auto getVisibleHeight() -> int; // Píxeles visibles actuales (0 = oculta, height_ = totalmente visible)
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; } [[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }
private: private:
@@ -43,12 +43,12 @@ class Console {
static constexpr float SLIDE_SPEED = 120.0F; static constexpr float SLIDE_SPEED = 120.0F;
// Constantes de consola // Constantes de consola
static constexpr std::string_view CONSOLE_NAME = "JDD Console"; static constexpr std::string_view CONSOLE_NAME = "JDD Console";
static constexpr std::string_view CONSOLE_VERSION = "v1.0"; static constexpr std::string_view CONSOLE_VERSION = "v1.0";
static constexpr int MAX_LINE_CHARS = 28; static constexpr int MAX_LINE_CHARS = 28;
static constexpr int MAX_HISTORY_SIZE = 20; static constexpr int MAX_HISTORY_SIZE = 20;
static constexpr float CURSOR_ON_TIME = 0.5F; static constexpr float CURSOR_ON_TIME = 0.5F;
static constexpr float CURSOR_OFF_TIME = 0.3F; static constexpr float CURSOR_OFF_TIME = 0.3F;
// [SINGLETON] // [SINGLETON]
static Console* console; static Console* console;
@@ -58,9 +58,9 @@ class Console {
~Console() = default; ~Console() = default;
// Métodos privados // Métodos privados
void buildSurface(); // Crea la Surface con el aspecto visual void buildSurface(); // Crea la Surface con el aspecto visual
void redrawText(); // Redibuja el texto dinámico (msg + input + cursor) void redrawText(); // Redibuja el texto dinámico (msg + input + cursor)
void processCommand(); // Procesa el comando introducido por el usuario void processCommand(); // Procesa el comando introducido por el usuario
// Objetos de renderizado // Objetos de renderizado
std::shared_ptr<Text> text_; std::shared_ptr<Text> text_;
@@ -75,11 +75,11 @@ class Console {
// Estado de la entrada de texto // Estado de la entrada de texto
std::string msg_line_; // inicializado en constructor con CONSOLE_NAME + CONSOLE_VERSION std::string msg_line_; // inicializado en constructor con CONSOLE_NAME + CONSOLE_VERSION
std::string input_line_; std::string input_line_;
float cursor_timer_{0.0F}; float cursor_timer_{0.0F};
bool cursor_visible_{true}; bool cursor_visible_{true};
// Historial de comandos (navegable con flechas arriba/abajo) // Historial de comandos (navegable con flechas arriba/abajo)
std::deque<std::string> history_; std::deque<std::string> history_;
int history_index_{-1}; // -1 = en la entrada actual (presente) int history_index_{-1}; // -1 = en la entrada actual (presente)
std::string saved_input_; // guarda input_line_ al empezar a navegar std::string saved_input_; // guarda input_line_ al empezar a navegar
}; };

View File

@@ -279,7 +279,7 @@ void Notifier::clearNotifications() {
} }
// Ajusta el offset vertical base // Ajusta el offset vertical base
void Notifier::addYOffset(int px) { y_offset_ += px; } void Notifier::addYOffset(int px) { y_offset_ += px; }
void Notifier::removeYOffset(int px) { y_offset_ -= px; } void Notifier::removeYOffset(int px) { y_offset_ -= px; }
// Obtiene los códigos de las notificaciones // Obtiene los códigos de las notificaciones