presentation: bool integer_scale -> enum PresentationMode (integer_scale|letterbox|stretched|overscan) amb migracio de configs antics

This commit is contained in:
2026-05-19 20:29:22 +02:00
parent ac997c185d
commit 20325ddd5a
8 changed files with 214 additions and 69 deletions
+80 -33
View File
@@ -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.