GlobalInputs F1-F12 + Escape, Screen sense destruir finestra, escalat al GPU, presets i fons canvas (v0.11.0)
This commit is contained in:
1 parent
837eb73398
commit
297dc85e47
23 files changed
+653
-34
No files matched your search
@@ -156,6 +156,64 @@ void Screen::applyCrtPiParams(const Rendering::CrtPiParams& params) {
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::setWindowZoom(int zoom) {
|
||||
config_.zoom = zoom;
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
void Screen::setFullscreen(bool fullscreen) {
|
||||
config_.fullscreen = fullscreen;
|
||||
SDL_SetWindowFullscreen(window_, fullscreen);
|
||||
SDL_SyncWindow(window_);
|
||||
adjustWindowSize();
|
||||
}
|
||||
|
||||
void Screen::setVSync(bool vsync) {
|
||||
config_.vsync = vsync;
|
||||
if (shader_backend_ != nullptr) {
|
||||
shader_backend_->setVSync(vsync);
|
||||
} else if (renderer_ != nullptr) {
|
||||
SDL_SetRenderVSync(renderer_, vsync ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::setScalingMode(Defaults::ScalingMode mode) {
|
||||
config_.scaling_mode = mode;
|
||||
if (shader_backend_ != nullptr) {
|
||||
shader_backend_->setScalingMode(mode);
|
||||
} else if (renderer_ != nullptr) {
|
||||
SDL_SetRenderLogicalPresentation(renderer_, GameCanvas::WIDTH, GameCanvas::HEIGHT, toSdlPresentation(mode));
|
||||
}
|
||||
}
|
||||
|
||||
// Fullscreen manté la resolució del desktop; en mode finestra recalculem i
|
||||
// reposicionem. A Wayland el compositor ignora SDL_SetWindowPosition, així
|
||||
// que allí el reset queda en mans del WM.
|
||||
void Screen::adjustWindowSize() {
|
||||
if (config_.fullscreen) { return; }
|
||||
|
||||
int old_w = 0;
|
||||
int old_h = 0;
|
||||
SDL_GetWindowSize(window_, &old_w, &old_h);
|
||||
int old_x = 0;
|
||||
int old_y = 0;
|
||||
SDL_GetWindowPosition(window_, &old_x, &old_y);
|
||||
|
||||
const int NEW_W = GameCanvas::WIDTH * config_.zoom;
|
||||
const int NEW_H = GameCanvas::HEIGHT * config_.zoom;
|
||||
const int NEW_X = old_x + ((old_w - NEW_W) / 2);
|
||||
const int NEW_Y = old_y + ((old_h - NEW_H) / 2);
|
||||
|
||||
SDL_SetWindowSize(window_, NEW_W, NEW_H);
|
||||
SDL_SyncWindow(window_);
|
||||
|
||||
const char* driver = SDL_GetCurrentVideoDriver();
|
||||
const bool IS_WAYLAND = (driver != nullptr && SDL_strcmp(driver, "wayland") == 0);
|
||||
if (!IS_WAYLAND) {
|
||||
SDL_SetWindowPosition(window_, std::max(NEW_X, 0), std::max(NEW_Y, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::clear(std::uint8_t r, std::uint8_t g, std::uint8_t b) {
|
||||
const std::uint32_t COLOR = (0xFFU << 24) | (static_cast<std::uint32_t>(r) << 16) | (static_cast<std::uint32_t>(g) << 8) | static_cast<std::uint32_t>(b);
|
||||
std::ranges::fill(canvas_, COLOR);
|
||||
|
||||
@@ -54,6 +54,16 @@ class Screen {
|
||||
// Reenvia paràmetres CrtPi al backend GPU. No-op al path fallback.
|
||||
void applyCrtPiParams(const Rendering::CrtPiParams& params);
|
||||
|
||||
// Canvis lleugers que NO destrueixen la finestra. Zoom i fullscreen
|
||||
// redimensionen SDL_Window i mantenen la finestra centrada respecte a
|
||||
// l'anterior posició; VSync s'envia directament al backend GPU.
|
||||
void setWindowZoom(int zoom);
|
||||
void setFullscreen(bool fullscreen);
|
||||
void setVSync(bool vsync);
|
||||
// Mode d'escalat del path GPU (letterbox/integer/stretch/...). Al
|
||||
// fallback SDL_Renderer es propaga via SDL_SetRenderLogicalPresentation.
|
||||
void setScalingMode(Defaults::ScalingMode mode);
|
||||
|
||||
void clear(std::uint8_t r = 0, std::uint8_t g = 0, std::uint8_t b = 0);
|
||||
// Pinta un rectangle opac al canvas ARGB del joc. Pensat per a HUDs
|
||||
// simples (caixes de notificacions, barres d'estat); no gasta paleta.
|
||||
@@ -75,6 +85,9 @@ class Screen {
|
||||
|
||||
void destroySdl();
|
||||
void createSdl();
|
||||
// Redimensiona la finestra existent i la recenta sense tancar-la; al
|
||||
// fallback SDL_Renderer també ajusta la presentació lògica.
|
||||
void adjustWindowSize();
|
||||
|
||||
// Comptador intern de frames per segon. S'incrementa a cada present() i
|
||||
// es recalcula quan ha passat un segon complet (SDL_GetTicks en ms).
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include "core/rendering/sdl3gpu/spv/crtpi_frag_spv.h"
|
||||
#include "core/rendering/sdl3gpu/spv/postfx_vert_spv.h"
|
||||
@@ -280,7 +282,10 @@ namespace Rendering {
|
||||
SDL_GPUTexture* scene,
|
||||
SDL_GPUSampler* sampler,
|
||||
int game_width,
|
||||
int game_height) {
|
||||
int game_height,
|
||||
Defaults::ScalingMode scaling_mode,
|
||||
std::uint32_t swapchain_w,
|
||||
std::uint32_t swapchain_h) {
|
||||
if (pipeline_ == nullptr) { return; }
|
||||
|
||||
SDL_GPUColorTargetInfo color_target{};
|
||||
@@ -292,6 +297,11 @@ namespace Rendering {
|
||||
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &color_target, 1, nullptr);
|
||||
if (pass == nullptr) { return; }
|
||||
|
||||
// Viewport per aplicar letterbox/integer/... sense modificar el
|
||||
// triangle fullscreen; la resta del swapchain queda a clear_color.
|
||||
const SDL_GPUViewport VP = computeViewport(scaling_mode, swapchain_w, swapchain_h, game_width, game_height);
|
||||
SDL_SetGPUViewport(pass, &VP);
|
||||
|
||||
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||
|
||||
SDL_GPUTextureSamplerBinding binding{};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "core/rendering/shader_backend.hpp"
|
||||
|
||||
// Uniforms del shader CRT-Pi. 4 × vec4 (64 bytes) per a alineament Metal/Vulkan.
|
||||
@@ -56,7 +58,10 @@ namespace Rendering {
|
||||
SDL_GPUTexture* scene,
|
||||
SDL_GPUSampler* sampler,
|
||||
int game_width,
|
||||
int game_height);
|
||||
int game_height,
|
||||
Defaults::ScalingMode scaling_mode,
|
||||
std::uint32_t swapchain_w,
|
||||
std::uint32_t swapchain_h);
|
||||
|
||||
private:
|
||||
SDL_GPUDevice* device_{nullptr};
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include "core/rendering/sdl3gpu/spv/postfx_frag_spv.h"
|
||||
#include "core/rendering/sdl3gpu/spv/postfx_vert_spv.h"
|
||||
@@ -370,7 +372,7 @@ namespace Rendering {
|
||||
|
||||
// Camí CrtPi: delega tot el render pass al pipeline dedicat.
|
||||
if (active_shader_ == ShaderType::CRTPI && crtpi_pipeline_ != nullptr) {
|
||||
crtpi_pipeline_->render(cmd, swapchain, scene_texture_, sampler_, game_width_, game_height_);
|
||||
crtpi_pipeline_->render(cmd, swapchain, scene_texture_, sampler_, game_width_, game_height_, scaling_mode_, sw, sh);
|
||||
SDL_SubmitGPUCommandBuffer(cmd);
|
||||
return;
|
||||
}
|
||||
@@ -385,6 +387,9 @@ namespace Rendering {
|
||||
|
||||
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &color_target, 1, nullptr);
|
||||
if (pass != nullptr) {
|
||||
const SDL_GPUViewport VP = computeViewport(scaling_mode_, sw, sh, game_width_, game_height_);
|
||||
SDL_SetGPUViewport(pass, &VP);
|
||||
|
||||
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||
|
||||
SDL_GPUTextureSamplerBinding binding{};
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Rendering {
|
||||
void setActiveShader(ShaderType type) override { active_shader_ = type; }
|
||||
void setCrtPiParams(const CrtPiParams& params) override;
|
||||
void setVSync(bool vsync) override;
|
||||
void setScalingMode(Defaults::ScalingMode mode) override { scaling_mode_ = mode; }
|
||||
void setPreferredDriver(const std::string& driver) override { preferred_driver_ = driver; }
|
||||
void cleanup() override;
|
||||
|
||||
@@ -99,6 +100,7 @@ namespace Rendering {
|
||||
|
||||
int game_width_{0};
|
||||
int game_height_{0};
|
||||
Defaults::ScalingMode scaling_mode_{Defaults::Video::SCALING_MODE};
|
||||
std::string preferred_driver_;
|
||||
std::string driver_name_;
|
||||
bool vsync_{true};
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "core/rendering/sdl3gpu/viewport.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
auto computeViewport(Defaults::ScalingMode mode,
|
||||
std::uint32_t swapchain_w,
|
||||
std::uint32_t swapchain_h,
|
||||
int logical_w,
|
||||
int logical_h) -> SDL_GPUViewport {
|
||||
const auto SW = static_cast<float>(swapchain_w);
|
||||
const auto SH = static_cast<float>(swapchain_h);
|
||||
const auto LW = static_cast<float>(logical_w);
|
||||
const auto LH = static_cast<float>(logical_h);
|
||||
|
||||
float vw = 0.0F;
|
||||
float vh = 0.0F;
|
||||
switch (mode) {
|
||||
case Defaults::ScalingMode::DISABLED:
|
||||
vw = LW;
|
||||
vh = LH;
|
||||
break;
|
||||
case Defaults::ScalingMode::STRETCH:
|
||||
vw = SW;
|
||||
vh = SH;
|
||||
break;
|
||||
case Defaults::ScalingMode::LETTERBOX: {
|
||||
const float SCALE = std::min(SW / LW, SH / LH);
|
||||
vw = LW * SCALE;
|
||||
vh = LH * SCALE;
|
||||
break;
|
||||
}
|
||||
case Defaults::ScalingMode::OVERSCAN: {
|
||||
const float SCALE = std::max(SW / LW, SH / LH);
|
||||
vw = LW * SCALE;
|
||||
vh = LH * SCALE;
|
||||
break;
|
||||
}
|
||||
case Defaults::ScalingMode::INTEGER: {
|
||||
const int SCALE = std::max(1,
|
||||
std::min(static_cast<int>(SW) / logical_w, static_cast<int>(SH) / logical_h));
|
||||
vw = LW * static_cast<float>(SCALE);
|
||||
vh = LH * static_cast<float>(SCALE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const float VX = std::floor((SW - vw) * 0.5F);
|
||||
const float VY = std::floor((SH - vh) * 0.5F);
|
||||
return {.x = VX, .y = VY, .w = vw, .h = vh, .min_depth = 0.0F, .max_depth = 1.0F};
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "utils/defaults.hpp"
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Calcula el rectangle on s'ha de pintar el triangle fullscreen dins del
|
||||
// swapchain segons el mode d'escalat configurat. La zona fora del
|
||||
// viewport queda amb la clear_color del render pass (negre o el color
|
||||
// que decidisca el caller).
|
||||
auto computeViewport(Defaults::ScalingMode mode,
|
||||
std::uint32_t swapchain_w,
|
||||
std::uint32_t swapchain_h,
|
||||
int logical_w,
|
||||
int logical_h) -> SDL_GPUViewport;
|
||||
|
||||
} // namespace Rendering
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "utils/defaults.hpp"
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Shader de post-procés actiu. El backend escull el pipeline corresponent.
|
||||
@@ -78,6 +80,10 @@ namespace Rendering {
|
||||
// Canvia el mode de presentació (VSYNC/IMMEDIATE/MAILBOX) en calent.
|
||||
virtual void setVSync(bool vsync) = 0;
|
||||
|
||||
// Mode d'escalat del triangle fullscreen al swapchain (letterbox,
|
||||
// integer, overscan, ...). Implementat via SDL_SetGPUViewport.
|
||||
virtual void setScalingMode(Defaults::ScalingMode mode) = 0;
|
||||
|
||||
// Fixa el driver preferit (buit = automàtic). S'ha de cridar abans d'init().
|
||||
virtual void setPreferredDriver(const std::string& driver) = 0;
|
||||
|
||||
|
||||
Reference in new issue
Block a user