presentation: bool integer_scale -> enum PresentationMode (integer_scale|letterbox|stretched|overscan) amb migracio de configs antics
This commit is contained in:
@@ -326,16 +326,27 @@ void Screen::detectMaxZoom() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Establece el escalado entero
|
||||
void Screen::setIntegerScale(bool enabled) {
|
||||
if (Options::video.integer_scale == enabled) { return; }
|
||||
Options::video.integer_scale = enabled;
|
||||
// Estableix el mode de presentacio del canvas i reaplica el layout
|
||||
void Screen::setPresentationMode(Options::PresentationMode mode) {
|
||||
if (Options::video.presentation_mode == mode) { return; }
|
||||
Options::video.presentation_mode = mode;
|
||||
#ifndef NO_SHADERS
|
||||
if (shader_backend_) {
|
||||
shader_backend_->setPresentationMode(static_cast<Rendering::ShaderBackend::PresentationMode>(mode));
|
||||
}
|
||||
#endif
|
||||
setVideoMode(Options::video.fullscreen);
|
||||
}
|
||||
|
||||
// Alterna el escalado entero
|
||||
void Screen::toggleIntegerScale() {
|
||||
setIntegerScale(!Options::video.integer_scale);
|
||||
// Cicla integer_scale -> letterbox -> stretched -> overscan -> integer_scale
|
||||
void Screen::nextPresentationMode() {
|
||||
setPresentationMode(Options::nextPresentationMode(Options::video.presentation_mode));
|
||||
}
|
||||
|
||||
// Nom curt del mode actual (per a notificacions). Static perque no necessita
|
||||
// estat d'instancia: nomes consulta Options::video.
|
||||
auto Screen::getPresentationModeName() -> const char * {
|
||||
return Options::presentationModeToString(Options::video.presentation_mode);
|
||||
}
|
||||
|
||||
// Establece el V-Sync
|
||||
@@ -407,39 +418,75 @@ void Screen::applyFullscreenLayout() {
|
||||
computeFullscreenGameRect();
|
||||
}
|
||||
|
||||
// Calcula el rectángulo dest para fullscreen: integer_scale / aspect ratio
|
||||
// Calcula el rectangle dest segons el PresentationMode actiu.
|
||||
// INTEGER_SCALE: x sencera maxima (1x, 2x, 3x...) centrada amb barres.
|
||||
// LETTERBOX: mante aspect ratio, ajusta al menor dels eixos, barres.
|
||||
// STRETCHED: omple tota la finestra deformant la relacio d'aspecte.
|
||||
// OVERSCAN: mante aspect ratio omplint la finestra (retalla el sobrant).
|
||||
void Screen::computeFullscreenGameRect() {
|
||||
if (Options::video.integer_scale) {
|
||||
// Calcula el tamaño de la escala máxima
|
||||
int scale = 0;
|
||||
while (((game_canvas_width_ * (scale + 1)) <= window_width_) && ((game_canvas_height_ * (scale + 1)) <= window_height_)) {
|
||||
scale++;
|
||||
}
|
||||
const float CANVAS_RATIO = static_cast<float>(game_canvas_width_) / static_cast<float>(game_canvas_height_);
|
||||
const float WINDOW_RATIO = static_cast<float>(window_width_) / static_cast<float>(window_height_);
|
||||
|
||||
dest_.w = game_canvas_width_ * scale;
|
||||
dest_.h = game_canvas_height_ * scale;
|
||||
dest_.x = (window_width_ - dest_.w) / 2;
|
||||
dest_.y = (window_height_ - dest_.h) / 2;
|
||||
} else {
|
||||
// Manté la relació d'aspecte sense escalat enter (letterbox/pillarbox).
|
||||
float ratio = (float)game_canvas_width_ / (float)game_canvas_height_;
|
||||
if ((window_width_ - game_canvas_width_) >= (window_height_ - game_canvas_height_)) {
|
||||
dest_.h = window_height_;
|
||||
dest_.w = static_cast<int>(std::lround(window_height_ * ratio));
|
||||
dest_.x = (window_width_ - dest_.w) / 2;
|
||||
dest_.y = (window_height_ - dest_.h) / 2;
|
||||
} else {
|
||||
switch (Options::video.presentation_mode) {
|
||||
case Options::PresentationMode::INTEGER_SCALE: {
|
||||
int scale = 0;
|
||||
while (((game_canvas_width_ * (scale + 1)) <= window_width_) && ((game_canvas_height_ * (scale + 1)) <= window_height_)) {
|
||||
scale++;
|
||||
}
|
||||
dest_.w = game_canvas_width_ * scale;
|
||||
dest_.h = game_canvas_height_ * scale;
|
||||
break;
|
||||
}
|
||||
case Options::PresentationMode::LETTERBOX: {
|
||||
if (WINDOW_RATIO >= CANVAS_RATIO) {
|
||||
dest_.h = window_height_;
|
||||
dest_.w = static_cast<int>(std::lround(window_height_ * CANVAS_RATIO));
|
||||
} else {
|
||||
dest_.w = window_width_;
|
||||
dest_.h = static_cast<int>(std::lround(window_width_ / CANVAS_RATIO));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Options::PresentationMode::STRETCHED: {
|
||||
dest_.w = window_width_;
|
||||
dest_.h = static_cast<int>(std::lround(window_width_ / ratio));
|
||||
dest_.x = (window_width_ - dest_.w) / 2;
|
||||
dest_.y = (window_height_ - dest_.h) / 2;
|
||||
dest_.h = window_height_;
|
||||
break;
|
||||
}
|
||||
case Options::PresentationMode::OVERSCAN: {
|
||||
// Mante aspect: dimensiona al major dels eixos (l'altre desborda).
|
||||
if (WINDOW_RATIO >= CANVAS_RATIO) {
|
||||
dest_.w = window_width_;
|
||||
dest_.h = static_cast<int>(std::lround(window_width_ / CANVAS_RATIO));
|
||||
} else {
|
||||
dest_.h = window_height_;
|
||||
dest_.w = static_cast<int>(std::lround(window_height_ * CANVAS_RATIO));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
dest_.x = (window_width_ - dest_.w) / 2;
|
||||
dest_.y = (window_height_ - dest_.h) / 2;
|
||||
}
|
||||
|
||||
// Aplica la logical presentation y persiste el estado en options
|
||||
// Aplica la logical presentation segons el PresentationMode actiu (ruta SDL_Renderer fallback).
|
||||
// La ruta GPU calcula el viewport ella mateixa via computeViewport().
|
||||
void Screen::applyLogicalPresentation(bool fullscreen) {
|
||||
SDL_SetRenderLogicalPresentation(renderer_, window_width_, window_height_, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
SDL_RendererLogicalPresentation lp = SDL_LOGICAL_PRESENTATION_LETTERBOX;
|
||||
switch (Options::video.presentation_mode) {
|
||||
case Options::PresentationMode::INTEGER_SCALE:
|
||||
lp = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
|
||||
break;
|
||||
case Options::PresentationMode::LETTERBOX:
|
||||
lp = SDL_LOGICAL_PRESENTATION_LETTERBOX;
|
||||
break;
|
||||
case Options::PresentationMode::STRETCHED:
|
||||
lp = SDL_LOGICAL_PRESENTATION_STRETCH;
|
||||
break;
|
||||
case Options::PresentationMode::OVERSCAN:
|
||||
lp = SDL_LOGICAL_PRESENTATION_OVERSCAN;
|
||||
break;
|
||||
}
|
||||
SDL_SetRenderLogicalPresentation(renderer_, window_width_, window_height_, lp);
|
||||
Options::video.fullscreen = fullscreen;
|
||||
}
|
||||
|
||||
@@ -545,7 +592,7 @@ void Screen::initShaders() {
|
||||
}
|
||||
}
|
||||
if (shader_backend_->isHardwareAccelerated()) {
|
||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||
shader_backend_->setPresentationMode(static_cast<Rendering::ShaderBackend::PresentationMode>(Options::video.presentation_mode));
|
||||
shader_backend_->setVSync(Options::video.vsync);
|
||||
|
||||
// Resol els índexs de preset a partir del nom emmagatzemat al config.
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include <string> // for string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "utils/utils.h" // for Color
|
||||
#include "game/options.hpp" // for Options::PresentationMode
|
||||
#include "utils/utils.h" // for Color
|
||||
|
||||
#ifndef NO_SHADERS
|
||||
#include "core/rendering/shader_backend.hpp" // for Rendering::ShaderType
|
||||
@@ -51,17 +52,18 @@ class Screen {
|
||||
void blit(); // Vuelca el contenido del renderizador en pantalla
|
||||
|
||||
// Video y ventana
|
||||
void setVideoMode(bool fullscreen); // Establece el modo de video
|
||||
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
||||
void handleCanvasResized(); // En Emscripten, reaplica setVideoMode tras un cambio del navegador (salida de fullscreen con Esc, rotación). No-op fuera de Emscripten
|
||||
static void syncFullscreenFlagFromBrowser(bool is_fullscreen); // Sincroniza el flag interno de fullscreen con el estado real del navegador. Debe llamarse antes de diferir handleCanvasResized. No-op fuera de Emscripten
|
||||
void toggleIntegerScale(); // Alterna el escalado entero
|
||||
void setIntegerScale(bool enabled); // Establece el escalado entero
|
||||
void toggleVSync(); // Alterna el V-Sync
|
||||
void setVSync(bool enabled); // Establece el V-Sync
|
||||
auto decWindowZoom() -> bool; // Reduce el zoom de la ventana (devuelve true si cambió)
|
||||
auto incWindowZoom() -> bool; // Aumenta el zoom de la ventana (devuelve true si cambió)
|
||||
auto setWindowZoom(int zoom) -> bool; // Establece el zoom de la ventana (devuelve true si cambió)
|
||||
void setVideoMode(bool fullscreen); // Establece el modo de video
|
||||
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
||||
void handleCanvasResized(); // En Emscripten, reaplica setVideoMode tras un cambio del navegador (salida de fullscreen con Esc, rotación). No-op fuera de Emscripten
|
||||
static void syncFullscreenFlagFromBrowser(bool is_fullscreen); // Sincroniza el flag interno de fullscreen con el estado real del navegador. Debe llamarse antes de diferir handleCanvasResized. No-op fuera de Emscripten
|
||||
void nextPresentationMode(); // Cicla integer_scale -> letterbox -> stretched -> overscan
|
||||
void setPresentationMode(Options::PresentationMode mode); // Estableix el mode de presentacio del canvas
|
||||
[[nodiscard]] static auto getPresentationModeName() -> const char *; // Nom curt del mode actual (per a notificacions)
|
||||
void toggleVSync(); // Alterna el V-Sync
|
||||
void setVSync(bool enabled); // Establece el V-Sync
|
||||
auto decWindowZoom() -> bool; // Reduce el zoom de la ventana (devuelve true si cambió)
|
||||
auto incWindowZoom() -> bool; // Aumenta el zoom de la ventana (devuelve true si cambió)
|
||||
auto setWindowZoom(int zoom) -> bool; // Establece el zoom de la ventana (devuelve true si cambió)
|
||||
|
||||
// Borde
|
||||
void setBorderColor(Color color); // Cambia el color del borde
|
||||
|
||||
@@ -292,21 +292,48 @@ namespace Rendering {
|
||||
// computeViewport — dimensions lògiques del canvas dins del swapchain (letterbox)
|
||||
// ---------------------------------------------------------------------------
|
||||
auto SDL3GPUShader::computeViewport(Uint32 sw, Uint32 sh) const -> Viewport {
|
||||
const auto SWF = static_cast<float>(sw);
|
||||
const auto SHF = static_cast<float>(sh);
|
||||
const float CANVAS_RATIO = static_cast<float>(game_width_) / static_cast<float>(game_height_);
|
||||
const float WINDOW_RATIO = SWF / SHF;
|
||||
|
||||
float vw = 0.0F;
|
||||
float vh = 0.0F;
|
||||
if (integer_scale_) {
|
||||
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / game_width_, static_cast<int>(sh) / game_height_));
|
||||
vw = static_cast<float>(game_width_ * SCALE);
|
||||
vh = static_cast<float>(game_height_ * SCALE);
|
||||
} else {
|
||||
const float SCALE = std::min(
|
||||
static_cast<float>(sw) / static_cast<float>(game_width_),
|
||||
static_cast<float>(sh) / static_cast<float>(game_height_));
|
||||
vw = static_cast<float>(game_width_) * SCALE;
|
||||
vh = static_cast<float>(game_height_) * SCALE;
|
||||
switch (presentation_mode_) {
|
||||
case PresentationMode::INTEGER_SCALE: {
|
||||
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / game_width_, static_cast<int>(sh) / game_height_));
|
||||
vw = static_cast<float>(game_width_ * SCALE);
|
||||
vh = static_cast<float>(game_height_ * SCALE);
|
||||
break;
|
||||
}
|
||||
case PresentationMode::LETTERBOX: {
|
||||
if (WINDOW_RATIO >= CANVAS_RATIO) {
|
||||
vh = SHF;
|
||||
vw = SHF * CANVAS_RATIO;
|
||||
} else {
|
||||
vw = SWF;
|
||||
vh = SWF / CANVAS_RATIO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PresentationMode::STRETCHED: {
|
||||
vw = SWF;
|
||||
vh = SHF;
|
||||
break;
|
||||
}
|
||||
case PresentationMode::OVERSCAN: {
|
||||
if (WINDOW_RATIO >= CANVAS_RATIO) {
|
||||
vw = SWF;
|
||||
vh = SWF / CANVAS_RATIO;
|
||||
} else {
|
||||
vh = SHF;
|
||||
vw = SHF * CANVAS_RATIO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const float VX = std::floor((static_cast<float>(sw) - vw) * 0.5F);
|
||||
const float VY = std::floor((static_cast<float>(sh) - vh) * 0.5F);
|
||||
const float VX = std::floor((SWF - vw) * 0.5F);
|
||||
const float VY = std::floor((SHF - vh) * 0.5F);
|
||||
return {.x = VX, .y = VY, .w = vw, .h = vh};
|
||||
}
|
||||
|
||||
@@ -569,8 +596,8 @@ namespace Rendering {
|
||||
}
|
||||
}
|
||||
|
||||
void SDL3GPUShader::setScaleMode(bool integer_scale) {
|
||||
integer_scale_ = integer_scale;
|
||||
void SDL3GPUShader::setPresentationMode(PresentationMode mode) {
|
||||
presentation_mode_ = mode;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -97,8 +97,8 @@ namespace Rendering {
|
||||
// Activa/desactiva VSync en el swapchain
|
||||
void setVSync(bool vsync) override;
|
||||
|
||||
// Activa/desactiva escalado entero (integer scale)
|
||||
void setScaleMode(bool integer_scale) override;
|
||||
// Estableix el mode de presentacio del canvas
|
||||
void setPresentationMode(PresentationMode mode) override;
|
||||
|
||||
// Selecciona el shader de post-procesado activo (POSTFX o CRTPI)
|
||||
void setActiveShader(ShaderType type) override;
|
||||
@@ -195,7 +195,7 @@ namespace Rendering {
|
||||
std::string preferred_driver_; // Driver preferido; vacío = auto (SDL elige)
|
||||
bool is_initialized_ = false;
|
||||
bool vsync_ = true;
|
||||
bool integer_scale_ = false;
|
||||
PresentationMode presentation_mode_ = PresentationMode::INTEGER_SCALE;
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -112,9 +112,16 @@ namespace Rendering {
|
||||
virtual void setVSync(bool /*vsync*/) {}
|
||||
|
||||
/**
|
||||
* @brief Activa o desactiva el escalado entero (integer scale)
|
||||
* @brief Estableix el mode de presentacio del canvas dins del swapchain.
|
||||
* El backend calcula el viewport en consequencia.
|
||||
*/
|
||||
virtual void setScaleMode(bool /*integer_scale*/) {}
|
||||
enum class PresentationMode : std::uint8_t {
|
||||
INTEGER_SCALE,
|
||||
LETTERBOX,
|
||||
STRETCHED,
|
||||
OVERSCAN
|
||||
};
|
||||
virtual void setPresentationMode(PresentationMode /*mode*/) {}
|
||||
|
||||
/**
|
||||
* @brief Verifica si el backend está usando aceleración por hardware
|
||||
|
||||
Reference in New Issue
Block a user