mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Show the middle 16:9 of a wider picture in the picture a save file keeps.
The game draws the whole picture into the 543x306 target of the save's picture, so a picture wider than 16:9 came out squeezed. The new set wide_save has one site in the viewport helper, where it loads the address of SetViewport: a viewport of exactly 0, 0, 543, 306 gets the patch page's two numbers added to its x and its width, without branches or flags. widescreen.c writes them for a picture wider than 16:9 and switches the set on only then; the scissor, set before, keeps the target's size. C generated before the set existed keeps the other widescreen sets, and the log says that the save's picture is squeezed. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
# matched against, +116 the ratio that replaces it and +120 the tolerance of the match, as floats; +144 the bit
|
||||
# patterns of the UI's full-screen orthographic projection (m00 = 2 / 3840, m11 = 2 / 2160), +160..+175 and +208..+223
|
||||
# the four screen vtables that keep it, +176 the UI's horizontal squeeze (16:9 over the picture's ratio) in four lanes, +192 the
|
||||
# movie's margin on each side as a share of the width.
|
||||
# movie's margin on each side as a share of the width, +224 what the viewport of the save's picture gets added to its x
|
||||
# and +228 to its width, as 32-bit integers.
|
||||
#
|
||||
# The matrix-update, UI and movie sites: Copyright (c) 2026 Ivan0xFF (MIT; see THIRD_PARTY_NOTICES.md). Each is
|
||||
# written without branches or flags, as the generator's patch sites need. The set names differ from the other patch
|
||||
@@ -163,6 +164,22 @@ site wide_hud main 774368 ad401041 ad401041 @page:x16 fd404a10 6e040431 6e0c2491
|
||||
# at x29 - 40: min x +8, max x +16); it moves in by the page's margin on each side, the middle 16:9 of the picture.
|
||||
site wide_movie main 3b5c758 a941a269 d100a3b0 bd400a10 bd401211 1e303a32 @page:x17 bd40c233 1e330a52 1e322a10 1e323a31 bd000a10 bd001211 a941a269 # movie layer viewport: ldp x9, x8, [x19, #0x18]
|
||||
|
||||
# The save's picture: the viewport helper (main+0x2846e0) makes whole pixels of a viewport object on its target and
|
||||
# hands x, y, width and height in w1..w4 to nvnCommandBufferSetScissor (main+0x284804) and then to
|
||||
# nvnCommandBufferSetViewport (main+0x284828), before it leaves through SetDepthRange; the two procedures' addresses
|
||||
# are the globals behind main+0x4c8da90 and main+0x4c8e7d8, which main+0x12a1738 onwards fills by name. The picture a
|
||||
# save file shows is drawn through it into a target of 543x306 (not a constant of main: the size comes with the game's
|
||||
# data, so the site knows the viewport by its numbers), and the whole picture went in: wider than 16:9, it came out
|
||||
# squeezed. Where the helper loads SetViewport's address, a viewport of exactly 0, 0, 543, 306 gets the page's +224
|
||||
# added to its x and +228 to its width (runtime/widescreen.c wide_init: wider by the picture's ratio over 16:9 and
|
||||
# centred on the target). The scissor was set before and stays the target's, so the save shows the middle 16:9 of the
|
||||
# picture, the part a 16:9 picture holds. Without branches or flags: the differences from those four numbers are or-ed
|
||||
# together, clz >> 5 of that is 1 only when there is none, and madd adds the page's two numbers times it. x9..x12 and
|
||||
# x16 are free: the call takes x0..x4, and the helper reads none of them after it. The set is on only for a picture
|
||||
# wider than 16:9.
|
||||
set wide_save NX2NAVI_PATCH_WIDE_SAVE 0
|
||||
site wide_save main 284824 f9400108 f9400108 @page:x16 295c2e0a 51087c69 5104c88c 2a0c0129 2a010129 2a020129 5ac01129 53057d29 1b0a0521 1b0b0d23 # ldr x8, [x8]; ldp w10, w11, [x16, #224]; sub w9, w3, #543; sub w12, w4, #306; orr w9, w9, w12; orr w9, w9, w1; orr w9, w9, w2; clz w9, w9; lsr w9, w9, #5; madd w1, w9, w10, w1; madd w3, w9, w11, w3
|
||||
|
||||
# The game's zstd decoder (BSD zstd, statically linked into main) through the host's libzstd (runtime/ov_zstd.c): the
|
||||
# three calls of ZSTD_decompressMultiFrame (main+0xeb380: dctx, dst, capacity, src, size, dict, dict size, ddict) go to
|
||||
# the host function on the patch page (+0xff0). main+0xe910c is the file loader's call for a file that fits one read
|
||||
|
||||
@@ -59,7 +59,7 @@ static const char *const known[] = {
|
||||
"MOTION_GUARD_DEGREES", "MOTION_POLICY_TRACE", "SELECTIVE_MOTION", "SELECTIVE_MOTION_RAW", // motion_owner.c, vk_fg_pose.inc
|
||||
"MVOBJ_ALL", "MVOBJ_BANKS", "MVOBJ_EQUAL", "MVOBJ_EXACT", "MVOBJ_EXEC", "MVOBJ_NOC4", "MVOBJ_ONLY", "MVOBJ_TIMES", "MVPREV_CHECK", "MVPREV_GROW", "MVPREV_SKIP", "MVPREV_TRUST", "MV_CHECK",
|
||||
"MV_SURVEY",
|
||||
"ONE_PER_CORE", "OPERATION_MODE", "OUTPUT_RES", "PAD_LAYOUT", "PACE_HZ", "PASS_CRUMBS", "PATCH_OUTPUT", "PATCH_RES_FIXED", "PATCH_SCENE", "PATCH_WIDE_ASPECT", "PATCH_WIDE_HUD", "PATCH_WIDE_MOVIE", "PATCH_WIDE_OUT", "PATCH_FREECAM", "PATCH_WIDE_SCENE", "PCSS", "PCSS_K", "PERF_OVERLAY", "PERF_SLOW_MS", "PIPELINE_CACHE", "PIPELINE_CACHE_MAX_MB", "PIPELINE_CACHE_PLAY", "PIPELINE_CACHE_PLAY_MB", "PIPE_BINARIES", "PIPE_BINARIES_MAX_MB", "PIPE_FEEDBACK", "PIPE_MEMO", "PIPE_PREBUILD", "PIPE_SEED", "PIPE_SKIP", "PIPE_SYNC", "PIPE_WAIT", "POWER_FULL", "TEX_SAME", "TEX_SAME_BIG", "TEX_FLAT3D", "TEX_KEEP_TAKEN", "TEX_STALE_KEPT", "PRESENT_HELD", "HELD_SYNC",
|
||||
"ONE_PER_CORE", "OPERATION_MODE", "OUTPUT_RES", "PAD_LAYOUT", "PACE_HZ", "PASS_CRUMBS", "PATCH_OUTPUT", "PATCH_RES_FIXED", "PATCH_SCENE", "PATCH_WIDE_ASPECT", "PATCH_WIDE_HUD", "PATCH_WIDE_MOVIE", "PATCH_WIDE_OUT", "PATCH_FREECAM", "PATCH_WIDE_SAVE", "PATCH_WIDE_SCENE", "PCSS", "PCSS_K", "PERF_OVERLAY", "PERF_SLOW_MS", "PIPELINE_CACHE", "PIPELINE_CACHE_MAX_MB", "PIPELINE_CACHE_PLAY", "PIPELINE_CACHE_PLAY_MB", "PIPE_BINARIES", "PIPE_BINARIES_MAX_MB", "PIPE_FEEDBACK", "PIPE_MEMO", "PIPE_PREBUILD", "PIPE_SEED", "PIPE_SKIP", "PIPE_SYNC", "PIPE_WAIT", "POWER_FULL", "TEX_SAME", "TEX_SAME_BIG", "TEX_FLAT3D", "TEX_KEEP_TAKEN", "TEX_STALE_KEPT", "PRESENT_HELD", "HELD_SYNC",
|
||||
"PREPARE_PIPELINES", "PREWARM_FULL", "PREWARM_WAIT_MS", "PREWARM_XLATE", "PROBE_MOVIE", "PROBE_MOVIE_SHOT", "PROFILE", "PROFILE_CHAINS", "PROFILE_DIR", "PROFILE_FRAMES", "PROFILE_REPLAY", "PROFILE_SLOW",
|
||||
"POOL_FAST", "POOL_GROUP", "POOL_GROUP_CHECK", "POOL_PRESNAP", "POOL_PRESNAP_RUNS",
|
||||
"SUBMIT_FINISH_GPU", "SVC_WAITS", "SNAP_WIDEN", "SUBMIT_FINISH_RESULTS", "SUBMIT_FINISH_KINDS", "FOLIAGE", "MIRROR_STAGE", "FLUSH_SKIP_CLEAN", "MIRROR_HOT", "MESH_EMULATION", "MESH_EMU_MB", "MESH_EMU_TASKS", "MESH_EMU_BATCH", "GUEST_OPT", "LOG_TEX_NEW", "DUMP_KEY", "VEC_INDEX_FIX", "PASS_TIMES",
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
// them from the patch page instead (wide_out: the picture, wide_scene: the scene), wide_aspect replaces a 16:9 ratio of
|
||||
// sead's perspective projection (every 16:9 camera of the game) with the picture's, wide_hud keeps the HUD and menus
|
||||
// in their 16:9 shape in the middle of the picture (the UI's full-screen projection squeezed horizontally; fades and
|
||||
// the menu backgrounds that redraw a capture of the whole picture stay full width), and wide_movie shows pre-rendered
|
||||
// movies in the same middle 16:9. The heights stay the game's (1440 and 1080), so only the width grows, by the shape's
|
||||
// ratio to 16:9; the present scales the picture to the window keeping its shape (gfx_present.c, NX2NAVI_ASPECT=fit).
|
||||
// the menu backgrounds that redraw a capture of the whole picture stay full width), wide_movie shows pre-rendered
|
||||
// movies in the same middle 16:9, and wide_save draws that middle 16:9 into the picture a save file keeps. The heights
|
||||
// stay the game's (1440 and 1080), so only the width grows, by the shape's ratio to 16:9; the present scales the
|
||||
// picture to the window keeping its shape (gfx_present.c, NX2NAVI_ASPECT=fit).
|
||||
//
|
||||
// Setting NX2NAVI_GAME_ASPECT, read at start: "16:9" (the game's own, every set off), "window" (the shape of the window,
|
||||
// or of the monitor in fullscreen), or a fixed shape "21:9" (2560x1080 monitors, 64:27), "32:9". A shape within 1% of
|
||||
@@ -32,6 +33,7 @@
|
||||
#define GAME_H 1440
|
||||
#define SCENE_H 1080
|
||||
#define GAME_DTA_KIB 312320.0 // the texture heap made for that picture (wide_heap_extra_kib)
|
||||
#define SAVE_W 543 // the width of the target a save's picture is drawn into (save_extra)
|
||||
|
||||
// The window's size, or the monitor's in fullscreen; 0 when unknown.
|
||||
static int screen_size(int *w, int *h) {
|
||||
@@ -164,9 +166,19 @@ uint64_t wide_heap_extra_kib(void) {
|
||||
return grow > 0 ? (uint64_t)ceil(GAME_DTA_KIB * grow / 1024) * 1024 : 0;
|
||||
}
|
||||
|
||||
// The save's picture (recomp/patches-v111.txt, set wide_save): the game draws the whole picture into a target 543
|
||||
// pixels wide, which squeezes a picture wider than 16:9. The viewport of that draw is made wider than its target by the
|
||||
// picture's ratio over 16:9, half of it on each side, so the target, which the scissor keeps to, holds the middle 16:9
|
||||
// of the picture. Returns the pixels added for a picture of ow x oh: an even number, so the picture's middle stays in
|
||||
// the target's middle; 0 for a picture that is not wider than 16:9, taller or not.
|
||||
static int32_t save_extra(unsigned ow, unsigned oh) {
|
||||
double wider = (double)ow * GAME_H / ((double)oh * GAME_W);
|
||||
return wider > 1 ? 2 * (int32_t)lround(SAVE_W * (wider - 1) / 2) : 0;
|
||||
}
|
||||
|
||||
void wide_init(void) {
|
||||
int so = rt_patch_set("wide_out"), ss = rt_patch_set("wide_scene"), sa = rt_patch_set("wide_aspect"),
|
||||
sh = rt_patch_set("wide_hud"), sm = rt_patch_set("wide_movie");
|
||||
sh = rt_patch_set("wide_hud"), sm = rt_patch_set("wide_movie"), sv = rt_patch_set("wide_save");
|
||||
// The scene's share of the picture is not a size in this set: the game's GPU-time dynamic resolution sets it each
|
||||
// frame (3/4 of the picture at most), and writing other sizes into wide_scene's constant or the 1920x1080 render
|
||||
// sizes left the light target where the controller put it. DLSS's modes fix the share through res_fixed instead
|
||||
@@ -201,14 +213,24 @@ void wide_init(void) {
|
||||
memcpy(page + 176, squeeze4, 16);
|
||||
memcpy(page + 192, &margin, 4);
|
||||
memcpy(page + 208, keep2, 16);
|
||||
// the save's picture: what its viewport gets added to its x and to its width. The set is not one wide_available
|
||||
// asks for: C generated before it existed keeps the other sets and squeezes the save's picture as before.
|
||||
int32_t extra = save_extra(ow, oh), save[2] = {-(extra / 2), extra};
|
||||
memcpy(page + 224, save, 8);
|
||||
rt_patch_switch(so, 1);
|
||||
rt_patch_switch(ss, 1);
|
||||
rt_patch_switch(sa, 1);
|
||||
rt_patch_switch(sh, 1);
|
||||
rt_patch_switch(sm, 1);
|
||||
if (extra > 0) rt_patch_switch(sv, 1);
|
||||
scale_k = oh > GAME_H ? (double)oh / GAME_H : 1.0;
|
||||
rt_log("widescreen: picture %ux%u, scene %ux%u (%.0f%% of it), camera aspect ratio %.4f (16:9 is %.4f), UI and movies "
|
||||
"in the middle %.1f%%", ow, oh, sw, sch, f * 100, ratio, game, squeeze * 100);
|
||||
if (extra > 0 && sv >= 0)
|
||||
rt_log("widescreen: a save's picture holds the middle 16:9 (its viewport %d pixels wide on the %d of its target)",
|
||||
SAVE_W + extra, SAVE_W);
|
||||
else if (extra > 0)
|
||||
rt_log("widescreen: the generated C has no set wide_save; a save's picture holds the whole picture, squeezed");
|
||||
}
|
||||
|
||||
// The picture the game draws: the widescreen one wide_init set up, else the game's own 2560x1440. DLSS's largest mode
|
||||
|
||||
Reference in New Issue
Block a user