modernitzat el sistema d'opcions
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
#include "core/rendering/text.h" // for Text, TXT_CENTER, TXT_COLOR, TXT_STROKE
|
||||
#include "core/resources/asset.h" // for Asset
|
||||
#include "core/resources/resource.h"
|
||||
#include "game/defaults.hpp" // for GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT
|
||||
#include "game/options.hpp" // for Options::video, Options::settings
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
#include "core/rendering/sdl3gpu/sdl3gpu_shader.hpp" // for Rendering::SDL3GPUShader
|
||||
@@ -59,17 +61,14 @@ namespace {
|
||||
#endif // __EMSCRIPTEN__
|
||||
|
||||
// Constructor
|
||||
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options) {
|
||||
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset) {
|
||||
// Inicializa variables
|
||||
this->window = window;
|
||||
this->renderer = renderer;
|
||||
this->options = options;
|
||||
this->asset = asset;
|
||||
|
||||
gameCanvasWidth = options->gameWidth;
|
||||
gameCanvasHeight = options->gameHeight;
|
||||
borderWidth = options->borderWidth * 2;
|
||||
borderHeight = options->borderHeight * 2;
|
||||
gameCanvasWidth = GAMECANVAS_WIDTH;
|
||||
gameCanvasHeight = GAMECANVAS_HEIGHT;
|
||||
|
||||
// Define el color del borde para el modo de pantalla completa
|
||||
borderColor = {0x00, 0x00, 0x00};
|
||||
@@ -80,7 +79,7 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
|
||||
// Mirror del pattern de jaildoctors_dilemma (que usa exactament 256×192 i
|
||||
// funciona) on `initSDLVideo` configura la presentation abans de crear cap
|
||||
// textura.
|
||||
setVideoMode(options->videoMode != 0);
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
|
||||
// Força al window manager a completar el resize/posicionat abans de passar
|
||||
// la ventana al dispositiu GPU. Sense açò en Linux/X11 hi ha un race
|
||||
@@ -92,10 +91,10 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options
|
||||
// ARGB8888 per simplificar el readback cap al pipeline SDL3 GPU.
|
||||
gameCanvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, gameCanvasWidth, gameCanvasHeight);
|
||||
if (gameCanvas != nullptr) {
|
||||
SDL_SetTextureScaleMode(gameCanvas, options->filter == FILTER_NEAREST ? SDL_SCALEMODE_NEAREST : SDL_SCALEMODE_LINEAR);
|
||||
SDL_SetTextureScaleMode(gameCanvas, Options::video.scale_mode);
|
||||
}
|
||||
if (gameCanvas == nullptr) {
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "gameCanvas could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -182,7 +181,7 @@ void Screen::blit() {
|
||||
}
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
|
||||
if (options->videoShaderEnabled) {
|
||||
if (Options::video.shader.enabled) {
|
||||
// Ruta normal: shader amb els seus params.
|
||||
shader_backend_->uploadPixels(pixel_buffer_.data(), gameCanvasWidth, gameCanvasHeight);
|
||||
shader_backend_->render();
|
||||
@@ -237,54 +236,54 @@ void Screen::setVideoMode(bool fullscreen) {
|
||||
|
||||
// Cambia entre pantalla completa y ventana
|
||||
void Screen::toggleVideoMode() {
|
||||
setVideoMode(options->videoMode == 0);
|
||||
setVideoMode(!Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Reduce el zoom de la ventana
|
||||
auto Screen::decWindowZoom() -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
const int PREV = options->windowSize;
|
||||
options->windowSize = std::max(options->windowSize - 1, WINDOW_ZOOM_MIN);
|
||||
if (options->windowSize == PREV) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
const int PREV = Options::window.zoom;
|
||||
Options::window.zoom = std::max(Options::window.zoom - 1, WINDOW_ZOOM_MIN);
|
||||
if (Options::window.zoom == PREV) { return false; }
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Aumenta el zoom de la ventana
|
||||
auto Screen::incWindowZoom() -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
const int PREV = options->windowSize;
|
||||
options->windowSize = std::min(options->windowSize + 1, WINDOW_ZOOM_MAX);
|
||||
if (options->windowSize == PREV) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
const int PREV = Options::window.zoom;
|
||||
Options::window.zoom = std::min(Options::window.zoom + 1, WINDOW_ZOOM_MAX);
|
||||
if (Options::window.zoom == PREV) { return false; }
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Establece el zoom de la ventana directamente
|
||||
auto Screen::setWindowZoom(int zoom) -> bool {
|
||||
if (options->videoMode != 0) { return false; }
|
||||
if (Options::video.fullscreen) { return false; }
|
||||
if (zoom < WINDOW_ZOOM_MIN || zoom > WINDOW_ZOOM_MAX) { return false; }
|
||||
if (zoom == options->windowSize) { return false; }
|
||||
options->windowSize = zoom;
|
||||
if (zoom == Options::window.zoom) { return false; }
|
||||
Options::window.zoom = zoom;
|
||||
setVideoMode(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Establece el escalado entero
|
||||
void Screen::setIntegerScale(bool enabled) {
|
||||
if (options->integerScale == enabled) { return; }
|
||||
options->integerScale = enabled;
|
||||
setVideoMode(options->videoMode != 0);
|
||||
if (Options::video.integer_scale == enabled) { return; }
|
||||
Options::video.integer_scale = enabled;
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Alterna el escalado entero
|
||||
void Screen::toggleIntegerScale() {
|
||||
setIntegerScale(!options->integerScale);
|
||||
setIntegerScale(!Options::video.integer_scale);
|
||||
}
|
||||
|
||||
// Establece el V-Sync
|
||||
void Screen::setVSync(bool enabled) {
|
||||
options->vSync = enabled;
|
||||
Options::video.vsync = enabled;
|
||||
SDL_SetRenderVSync(renderer, enabled ? 1 : SDL_RENDERER_VSYNC_DISABLED);
|
||||
#ifndef NO_SHADERS
|
||||
if (shader_backend_) {
|
||||
@@ -295,7 +294,7 @@ void Screen::setVSync(bool enabled) {
|
||||
|
||||
// Alterna el V-Sync
|
||||
void Screen::toggleVSync() {
|
||||
setVSync(!options->vSync);
|
||||
setVSync(!Options::video.vsync);
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
@@ -322,15 +321,9 @@ void Screen::applyFullscreen(bool fullscreen) {
|
||||
|
||||
// Calcula windowWidth/Height/dest para el modo ventana y aplica SDL_SetWindowSize
|
||||
void Screen::applyWindowedLayout() {
|
||||
if (options->borderEnabled) {
|
||||
windowWidth = gameCanvasWidth + borderWidth;
|
||||
windowHeight = gameCanvasHeight + borderHeight;
|
||||
dest = {0 + (borderWidth / 2), 0 + (borderHeight / 2), gameCanvasWidth, gameCanvasHeight};
|
||||
} else {
|
||||
windowWidth = gameCanvasWidth;
|
||||
windowHeight = gameCanvasHeight;
|
||||
dest = {0, 0, gameCanvasWidth, gameCanvasHeight};
|
||||
}
|
||||
windowWidth = gameCanvasWidth;
|
||||
windowHeight = gameCanvasHeight;
|
||||
dest = {0, 0, gameCanvasWidth, gameCanvasHeight};
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
windowWidth *= WASM_RENDER_SCALE;
|
||||
@@ -340,7 +333,7 @@ void Screen::applyWindowedLayout() {
|
||||
#endif
|
||||
|
||||
// Modifica el tamaño de la ventana
|
||||
SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize);
|
||||
SDL_SetWindowSize(window, windowWidth * Options::window.zoom, windowHeight * Options::window.zoom);
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
}
|
||||
|
||||
@@ -350,9 +343,9 @@ void Screen::applyFullscreenLayout() {
|
||||
computeFullscreenGameRect();
|
||||
}
|
||||
|
||||
// Calcula el rectángulo dest para fullscreen: integerScale / keepAspect / stretched
|
||||
// Calcula el rectángulo dest para fullscreen: integer_scale / aspect ratio
|
||||
void Screen::computeFullscreenGameRect() {
|
||||
if (options->integerScale) {
|
||||
if (Options::video.integer_scale) {
|
||||
// Calcula el tamaño de la escala máxima
|
||||
int scale = 0;
|
||||
while (((gameCanvasWidth * (scale + 1)) <= windowWidth) && ((gameCanvasHeight * (scale + 1)) <= windowHeight)) {
|
||||
@@ -363,7 +356,8 @@ void Screen::computeFullscreenGameRect() {
|
||||
dest.h = gameCanvasHeight * scale;
|
||||
dest.x = (windowWidth - dest.w) / 2;
|
||||
dest.y = (windowHeight - dest.h) / 2;
|
||||
} else if (options->keepAspect) {
|
||||
} else {
|
||||
// Manté la relació d'aspecte sense escalat enter (letterbox/pillarbox).
|
||||
float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight;
|
||||
if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight)) {
|
||||
dest.h = windowHeight;
|
||||
@@ -376,21 +370,13 @@ void Screen::computeFullscreenGameRect() {
|
||||
dest.x = (windowWidth - dest.w) / 2;
|
||||
dest.y = (windowHeight - dest.h) / 2;
|
||||
}
|
||||
} else {
|
||||
dest.w = windowWidth;
|
||||
dest.h = windowHeight;
|
||||
dest.x = dest.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Aplica la logical presentation y persiste el estado en options
|
||||
void Screen::applyLogicalPresentation(bool fullscreen) {
|
||||
SDL_SetRenderLogicalPresentation(renderer, windowWidth, windowHeight, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
// Actualiza las opciones
|
||||
options->videoMode = fullscreen ? SDL_WINDOW_FULLSCREEN : 0;
|
||||
options->screen.windowWidth = windowWidth;
|
||||
options->screen.windowHeight = windowHeight;
|
||||
Options::video.fullscreen = fullscreen;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -436,13 +422,13 @@ void Screen::handleCanvasResized() {
|
||||
// La crida a SDL_SetWindowFullscreen + SDL_SetRenderLogicalPresentation
|
||||
// que fa setVideoMode és l'única manera de resincronitzar l'estat intern
|
||||
// de SDL amb el canvas HTML real.
|
||||
setVideoMode(options->videoMode != 0);
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Screen::syncFullscreenFlagFromBrowser(bool isFullscreen) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
options->videoMode = isFullscreen ? SDL_WINDOW_FULLSCREEN : 0;
|
||||
Options::video.fullscreen = isFullscreen;
|
||||
#else
|
||||
(void)isFullscreen;
|
||||
#endif
|
||||
@@ -474,10 +460,7 @@ void Screen::applyShaderParams() {
|
||||
if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) {
|
||||
return;
|
||||
}
|
||||
const Rendering::ShaderType ACTIVE = options->videoShaderType == 1
|
||||
? Rendering::ShaderType::CRTPI
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
shader_backend_->setActiveShader(ACTIVE);
|
||||
shader_backend_->setActiveShader(Options::video.shader.current_shader);
|
||||
|
||||
// Preset per defecte (carregador YAML pendent). Valors estil "CRT" de CCAE.
|
||||
Rendering::PostFXParams POSTFX;
|
||||
@@ -497,17 +480,17 @@ void Screen::initShaders() {
|
||||
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
||||
const std::string FALLBACK_DRIVER = "none";
|
||||
shader_backend_->setPreferredDriver(
|
||||
options->videoGpuAcceleration ? options->videoGpuPreferredDriver : FALLBACK_DRIVER);
|
||||
Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : FALLBACK_DRIVER);
|
||||
}
|
||||
if (!shader_backend_->isHardwareAccelerated()) {
|
||||
const bool ok = shader_backend_->init(window, gameCanvas, "", "");
|
||||
if (options->console) {
|
||||
if (Options::settings.console) {
|
||||
std::cout << "Screen::initShaders: SDL3GPUShader::init() = " << (ok ? "OK" : "FAILED") << '\n';
|
||||
}
|
||||
}
|
||||
if (shader_backend_->isHardwareAccelerated()) {
|
||||
shader_backend_->setScaleMode(options->integerScale);
|
||||
shader_backend_->setVSync(options->vSync);
|
||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||
shader_backend_->setVSync(Options::video.vsync);
|
||||
applyShaderParams(); // aplica preset del shader actiu
|
||||
}
|
||||
#endif
|
||||
@@ -526,8 +509,8 @@ void Screen::shutdownShaders() {
|
||||
}
|
||||
|
||||
void Screen::setGpuAcceleration(bool enabled) {
|
||||
if (options->videoGpuAcceleration == enabled) { return; }
|
||||
options->videoGpuAcceleration = enabled;
|
||||
if (Options::video.gpu.acceleration == enabled) { return; }
|
||||
Options::video.gpu.acceleration = enabled;
|
||||
// Soft toggle: el backend es manté viu (vegeu shutdownShaders). El canvi
|
||||
// s'aplica al proper arrencada. S'emet una notificació perquè l'usuari
|
||||
// sap que ha tocat la tecla però el canvi no és immediat.
|
||||
@@ -538,7 +521,7 @@ void Screen::setGpuAcceleration(bool enabled) {
|
||||
}
|
||||
|
||||
void Screen::toggleGpuAcceleration() {
|
||||
setGpuAcceleration(!options->videoGpuAcceleration);
|
||||
setGpuAcceleration(!Options::video.gpu.acceleration);
|
||||
}
|
||||
|
||||
auto Screen::isGpuAccelerated() const -> bool {
|
||||
@@ -550,8 +533,8 @@ auto Screen::isGpuAccelerated() const -> bool {
|
||||
}
|
||||
|
||||
void Screen::setShaderEnabled(bool enabled) {
|
||||
if (options->videoShaderEnabled == enabled) { return; }
|
||||
options->videoShaderEnabled = enabled;
|
||||
if (Options::video.shader.enabled == enabled) { return; }
|
||||
Options::video.shader.enabled = enabled;
|
||||
#ifndef NO_SHADERS
|
||||
if (enabled) {
|
||||
applyShaderParams(); // restaura preset del shader actiu
|
||||
@@ -566,17 +549,17 @@ void Screen::setShaderEnabled(bool enabled) {
|
||||
}
|
||||
|
||||
void Screen::toggleShaderEnabled() {
|
||||
setShaderEnabled(!options->videoShaderEnabled);
|
||||
setShaderEnabled(!Options::video.shader.enabled);
|
||||
}
|
||||
|
||||
auto Screen::isShaderEnabled() const -> bool {
|
||||
return options->videoShaderEnabled;
|
||||
return Options::video.shader.enabled;
|
||||
}
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
void Screen::setActiveShader(Rendering::ShaderType type) {
|
||||
options->videoShaderType = type == Rendering::ShaderType::CRTPI ? 1 : 0;
|
||||
if (options->videoShaderEnabled) {
|
||||
Options::video.shader.current_shader = type;
|
||||
if (Options::video.shader.enabled) {
|
||||
applyShaderParams();
|
||||
}
|
||||
const color_t MAGENTA = {0xFF, 0x00, 0xFF};
|
||||
@@ -586,7 +569,7 @@ void Screen::setActiveShader(Rendering::ShaderType type) {
|
||||
}
|
||||
|
||||
auto Screen::getActiveShader() const -> Rendering::ShaderType {
|
||||
return options->videoShaderType == 1 ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
return Options::video.shader.current_shader;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -597,6 +580,8 @@ void Screen::toggleActiveShader() {
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
setActiveShader(NEXT);
|
||||
#else
|
||||
options->videoShaderType = options->videoShaderType == 1 ? 0 : 1;
|
||||
Options::video.shader.current_shader = Options::video.shader.current_shader == Rendering::ShaderType::POSTFX
|
||||
? Rendering::ShaderType::CRTPI
|
||||
: Rendering::ShaderType::POSTFX;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@ namespace Rendering {
|
||||
class Asset;
|
||||
class Text;
|
||||
|
||||
// Tipos de filtro
|
||||
constexpr int FILTER_NEAREST = 0;
|
||||
constexpr int FILTER_LINEAL = 1;
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
// Constantes
|
||||
@@ -35,7 +31,7 @@ class Screen {
|
||||
#endif
|
||||
|
||||
// Constructor y destructor
|
||||
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options);
|
||||
Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset);
|
||||
~Screen();
|
||||
|
||||
// Render loop
|
||||
@@ -104,15 +100,12 @@ class Screen {
|
||||
SDL_Renderer *renderer; // El renderizador de la ventana
|
||||
Asset *asset; // Objeto con el listado de recursos
|
||||
SDL_Texture *gameCanvas; // Textura para completar la ventana de juego hasta la pantalla completa
|
||||
options_t *options; // Variable con todas las opciones del programa
|
||||
|
||||
// Variables
|
||||
int windowWidth; // Ancho de la pantalla o ventana
|
||||
int windowHeight; // Alto de la pantalla o ventana
|
||||
int gameCanvasWidth; // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego
|
||||
int gameCanvasHeight; // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego
|
||||
int borderWidth; // Anchura del borde
|
||||
int borderHeight; // Altura del borde
|
||||
SDL_Rect dest; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
|
||||
color_t borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla
|
||||
|
||||
|
||||
Reference in New Issue
Block a user