mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-28 02:56:36 -04:00
widescreen: [video] aspect_ratio — GTE X-squash + stretched present
Adds the DuckStation-style widescreen hack as a config option, implemented in the runtime (no regen needed): - gte.cpp: gte_set_display_aspect(num, den). RTPS/RTPT scale the IR1*h/sz screen-X term by (4*den)/(3*num) around the game's own OFX projection centre (identity at 4:3). Games cull against the SXY values they read back from us, so post-projection screen- bounds culls stay aligned with the visible frame. - present: GL letterbox_rect generalised to the configured aspect (gl_renderer_set_display_aspect); SDL_Renderer path gets an aspect-derived logical size + dst rect. Window opens at the configured aspect (clamp_window_4x3 -> clamp_window_aspect). - config: [video] aspect_ratio = W:H (4:3 default, 16:9, up to 32:9) in game.toml, settings.toml (load+save), launcher seed. World geometry keeps correct proportions on the stretched present; screen-space 2D (HUD, FMV, sprite quad widths) stretches — the known limitation of the squash tier. EXPERIMENTAL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+28
-1
@@ -105,6 +105,31 @@ static void depth_cue_from_ir(GTEState* gte) {
|
||||
gte->IR3 = gte->saturate_ir(gte->MAC3, 3, true);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Widescreen X-squash (verified-enhancement, default off = identity).
|
||||
//
|
||||
// For a display aspect wider than the native 4:3, screen-space X is scaled by
|
||||
// (4*den)/(3*num) around the projection centre OFX — e.g. 3/4 for 16:9 — and
|
||||
// the present path stretches the 4:3 frame to the wide aspect, netting a wider
|
||||
// horizontal field of view (the DuckStation/Beetle "widescreen hack", but
|
||||
// applied in our GTE library so every RTPS/RTPT caller — generated code,
|
||||
// interpreter, overlay DLLs — sees it). Only the IR1*h/sz term is scaled, NOT
|
||||
// OFX, so the squash is centred on the game's own projection centre and
|
||||
// games' post-projection screen-bounds culls (which read SXY back from us)
|
||||
// stay aligned with the visible frame.
|
||||
// ---------------------------------------------------------------------------
|
||||
static int32_t s_ws_xnum = 1, s_ws_xden = 1;
|
||||
|
||||
extern "C" void gte_set_display_aspect(int num, int den) {
|
||||
if (num <= 0 || den <= 0) { s_ws_xnum = s_ws_xden = 1; return; }
|
||||
// squash = (4/3) / (num/den) = (4*den) / (3*num); identity for 4:3.
|
||||
int32_t n = 4 * den, d = 3 * num;
|
||||
int32_t a = n, b = d;
|
||||
while (b) { int32_t t = a % b; a = b; b = t; } // gcd
|
||||
s_ws_xnum = n / a;
|
||||
s_ws_xden = d / a;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// RTPS — Perspective Transformation (internal, operates on given vertex V)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -141,7 +166,9 @@ void gte_rtps_internal(GTEState* gte, int16_t* V, bool setMac0) {
|
||||
int32_t h_div_sz = gte_divide(gte->H, gte->SZ[3], gte->FLAG);
|
||||
|
||||
// Step 4: Project to screen coordinates
|
||||
int64_t sx = (gte->OFX + (int64_t)gte->IR1 * h_div_sz) >> 16;
|
||||
int64_t xterm = (int64_t)gte->IR1 * h_div_sz;
|
||||
if (s_ws_xnum != s_ws_xden) xterm = xterm * s_ws_xnum / s_ws_xden;
|
||||
int64_t sx = (gte->OFX + xterm) >> 16;
|
||||
int64_t sy = (gte->OFY + (int64_t)gte->IR2 * h_div_sz) >> 16;
|
||||
gte->push_sxy(sx, sy);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user