treballant en internal resolution

This commit is contained in:
2026-04-16 20:53:13 +02:00
parent 5cda8fc3f9
commit 16a3f5b470
10 changed files with 227 additions and 7 deletions

View File

@@ -37,6 +37,13 @@ Screen::Screen() {
if (zoom_ < 1) zoom_ = 1;
if (zoom_ > max_zoom_) zoom_ = max_zoom_;
// Clamp de la resolució interna a [1, max_zoom_]. Llegir del YAML i
// ajustar aquí és l'únic moment en què es fa — el menú re-clampa cada
// canvi. Si la pantalla és més petita que el valor desat (p.ex. canvi
// de monitor), baixem al màxim suportat.
if (Options::video.internal_resolution < 1) Options::video.internal_resolution = 1;
if (Options::video.internal_resolution > max_zoom_) Options::video.internal_resolution = max_zoom_;
int w = GAME_WIDTH * zoom_;
int h = Options::video.aspect_ratio_4_3 ? static_cast<int>(GAME_HEIGHT * 1.2F) * zoom_ : GAME_HEIGHT * zoom_;
@@ -66,6 +73,7 @@ Screen::~Screen() {
shader_backend_.reset();
}
if (internal_texture_sdl_) SDL_DestroyTexture(internal_texture_sdl_);
if (texture_) SDL_DestroyTexture(texture_);
if (renderer_) SDL_DestroyRenderer(renderer_);
if (window_) SDL_DestroyWindow(window_);
@@ -108,6 +116,8 @@ void Screen::initShaders() {
shader_backend_->setOversample(3);
}
shader_backend_->setInternalResolution(Options::video.internal_resolution);
// Resol el shader actiu des del config
if (Options::video.current_shader == "crtpi") {
shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI);
@@ -164,6 +174,33 @@ void Screen::present(Uint32* pixel_data) {
} else {
// Fallback SDL_Renderer
SDL_UpdateTexture(texture_, nullptr, pixel_data, GAME_WIDTH * sizeof(Uint32));
const int mult = Options::video.internal_resolution;
if (mult > 1) {
// Resolució interna: còpia NN de texture_ → internal_texture_sdl_
// (la fa SDL/GPU, no CPU). Tota la presentació downstream llegirà
// d'aquesta textura més gran — el filtre LINEAR final parteix d'una
// font més fina i l'estirament a finestra queda menys difús.
ensureFallbackInternalTexture();
if (internal_texture_sdl_ != nullptr) {
SDL_SetTextureScaleMode(texture_, SDL_SCALEMODE_NEAREST);
SDL_SetRenderTarget(renderer_, internal_texture_sdl_);
SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, texture_, nullptr, nullptr);
SDL_SetRenderTarget(renderer_, nullptr);
// El filtre global (LINEAR/NEAREST) s'aplica a l'estirament final
// cap a la finestra; per això l'aplicam a la textura intermèdia.
SDL_ScaleMode final_scale = (Options::video.texture_filter == Options::TextureFilter::LINEAR)
? SDL_SCALEMODE_LINEAR
: SDL_SCALEMODE_NEAREST;
SDL_SetTextureScaleMode(internal_texture_sdl_, final_scale);
SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, internal_texture_sdl_, nullptr, nullptr);
SDL_RenderPresent(renderer_);
return;
}
// Si la creació de la textura ha fallat, caiem al path normal.
}
SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, texture_, nullptr, nullptr);
SDL_RenderPresent(renderer_);
@@ -261,6 +298,22 @@ void Screen::cycleTextureFilter(int dir) {
}
}
void Screen::changeInternalResolution(int dir) {
int next = Options::video.internal_resolution + (dir >= 0 ? 1 : -1);
if (next < 1) next = 1;
if (next > max_zoom_) next = max_zoom_;
if (next == Options::video.internal_resolution) return;
Options::video.internal_resolution = next;
// Propaga al backend actiu. Al fallback path, la textura es recrea al
// pròxim present via ensureFallbackInternalTexture.
if (shader_backend_) {
shader_backend_->setInternalResolution(next);
} else {
applyFallbackPresentation();
}
}
auto Screen::nextShaderType() -> bool {
if (!shader_backend_ || !shader_backend_->isHardwareAccelerated()) return false;
if (!Options::video.shader_enabled) return false;
@@ -442,7 +495,41 @@ void Screen::applyFallbackPresentation() {
case Options::ScalingMode::INTEGER: mode = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; break;
}
}
SDL_SetRenderLogicalPresentation(renderer_, GAME_WIDTH, GAME_HEIGHT, mode);
// Amb resolució interna N > 1, la mida lògica creix proporcionalment
// perquè SDL scale des de 320·N × 200·N a la finestra — menys aggressive linear.
const int mult = Options::video.internal_resolution < 1 ? 1 : Options::video.internal_resolution;
SDL_SetRenderLogicalPresentation(renderer_, GAME_WIDTH * mult, GAME_HEIGHT * mult, mode);
}
void Screen::ensureFallbackInternalTexture() {
const int mult = Options::video.internal_resolution;
if (mult <= 1 || renderer_ == nullptr) {
// No cal textura intermèdia. Si la teníem, la reciclem.
if (internal_texture_sdl_ != nullptr) {
SDL_DestroyTexture(internal_texture_sdl_);
internal_texture_sdl_ = nullptr;
internal_texture_mult_ = 0;
}
return;
}
if (internal_texture_sdl_ != nullptr && internal_texture_mult_ == mult) return;
if (internal_texture_sdl_ != nullptr) {
SDL_DestroyTexture(internal_texture_sdl_);
internal_texture_sdl_ = nullptr;
}
internal_texture_sdl_ = SDL_CreateTexture(renderer_,
SDL_PIXELFORMAT_ABGR8888,
SDL_TEXTUREACCESS_TARGET,
GAME_WIDTH * mult,
GAME_HEIGHT * mult);
if (internal_texture_sdl_ == nullptr) {
std::cerr << "Screen: failed to create fallback internal texture (×" << mult << "): "
<< SDL_GetError() << '\n';
internal_texture_mult_ = 0;
return;
}
internal_texture_mult_ = mult;
}
void Screen::adjustWindowSize() {