mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Draw Ocarina in the window's shape: a wider picture and camera, with the HUD, menus and movies kept 16:9 in the middle.
The patch sets of recomp/patches-v111.txt read the game's 2560x1440 picture and 1920x1080 scene sizes from the patch page, give every 16:9 camera the picture's ratio, squeeze the UI's full-screen projection into the middle 16:9 (fades and the menu backgrounds that redraw a capture stay full width) and pillarbox movies. runtime/widescreen.c sets them up from the new Screen tab row Widescreen (NX2NAVI_GAME_ASPECT: 16:9, window, 21:9 or 32:9, at the next start). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ Code copied or adapted from another project is listed here with its source, the
|
||||
| MacNativeGames NX2navi aspect ratio: the camera and viewport sites that hand the perspective projection its aspect ratio, and the UI layout edits for a canvas wider than 16:9 | https://github.com/ly05010419/MacNativeGames @ `933b6a0d1438de160208a0a13eb5e8d7a2cb8094` (`games/<game>/runtime/aspect_patch.h`, `aspect_math.h`, `game_patches_v143.c`, `games/<game>/scripts/ultrawide_layout.py`), Copyright (c) 2026 MacNativeGames contributors | MIT | `recomp/patches-v143.txt` (set aspect), `tools/ultrawide_layout.py`, `tools/make_romfs_patches.py` (--aspect) |
|
||||
| MacNativeGames NX2navi button icons: the Xbox controller's shoulder buttons, triggers, Menu, View and d-pad drawn with letters from the game's own text fonts, the .bfotf key, the button guide's images and their block-linear layout, the resource size table raised for the archives that grew | https://github.com/ly05010419/MacNativeGames @ `933b6a0d1438de160208a0a13eb5e8d7a2cb8094` (`games/<game>/scripts/make_button_icons.py`), Copyright (c) 2026 MacNativeGames contributors | MIT | `tools/button_icons.py`, `tools/make_romfs_patches.py` (--prompts) |
|
||||
| RenoDX NX2navi mod (game mod by souperman9, tonemapper by Musa, RenoDX framework by ShortFuse, RenoVK fork by Ritsu): the approach of the HDR tonemap (the game's 1 - e^-x curve kept below a pivot and continued along its tangent above it, the saturation grade applied to the colour scaled into 0..1) and the observation that the passes after the tonemap keep values above 1. No code copied; the shader is our own | https://github.com/clshortfuse/renodx @ `b6f87272ad1bfdc0e6444910a93606815944a085` (`src/games/<game>/tonemap.slang`, `addon.cpp`), Copyright (c) 2025 Carlos Lopez Jr. | MIT | `runtime/shaders/hdr_tonemap.frag`, `runtime/vk_hdr.c` |
|
||||
| oot-mod (Ocarina of Time Switch 2 ultrawide mod): the matrix-update sites of sead's perspective projection and the 0.01 tolerance around 16:9, the 2D canvas site with the full-screen layout projection test and the screen vtables of the capture backgrounds, the movie layer viewport site, their instruction words and what each hook does there (rewritten without branches for the generator's patch sites) | https://github.com/craftycorvid/oot-mod @ `c5ccd1cd57e8219aea3be1e758221795fa5b7ec8` (`build.py` hooks), Copyright (c) 2026 Ivan0xFF | MIT | `recomp/patches-v111.txt` (sets wide_aspect, wide_hud, wide_movie), `runtime/widescreen.c` |
|
||||
| an ultrawide mod, the community mod for emulators: the list of UI panes the ultrawide layout edits and the distances they move (data only, no code copied; the edit code is our own, and MacNativeGames' `ultrawide_layout.py` in the row above already carries the same values). The mod's repository URL and licence version are not recorded in this repository | an ultrawide mod (community mod; URL not recorded here) | GPL (version not recorded here) | `tools/ultrawide_layout.py` (`KEEP_ROOT`, `edits`, `anim_edits`) |
|
||||
| MacNativeGames NX2navi virtual-core preemption: asynchronous preemption of an owner in top-level game code, priority inheritance through guest mutexes, the SDK's preemption-disable protocol (TLR+0x100/+0x102, SVC 0x36), the core-wait diagnostics | https://github.com/ly05010419/MacNativeGames @ `33e8fa83052ea1ae09a3583137008e9797e12950` (`games/<game>/runtime/threads.c`, commits 8bf0893 and 19730cd), Copyright (c) 2026 MacNativeGames contributors | MIT | `runtime/kernel.c` (SuspendThread and a register-saving stub replace SIGUSR2), `runtime/hostfn.c`, `runtime/svc.c` (host depth) |
|
||||
| MacNativeGames RomFS index builder (`NX2NRFS1` layout) | https://github.com/ly05010419/MacNativeGames @ `b75be8cfa704df3701e86130c8ced268e79d6b11` (`games/<game>/scripts/prepare_romfs_backend.py`), Copyright (c) 2026 MacNativeGames contributors | MIT | `tools/romfs_index.py` |
|
||||
|
||||
67
recomp/patches-v111.txt
Normal file
67
recomp/patches-v111.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
# Code patches for Ocarina of Time (Switch 2) 1.1.1 main (recomp/patches.py). The sites were found in this build's
|
||||
# main; their original words are checked by the generator. runtime/widescreen.c writes the patch page and switches the
|
||||
# sets: +96 the game image size and +104 the scene size as {w, h} in one 64-bit word, +112 the 16:9 ratio a camera is
|
||||
# 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.
|
||||
#
|
||||
# The matrix-update, UI and movie sites and what each does there come from oot-mod by Ivan0xFF
|
||||
# (https://github.com/craftycorvid/oot-mod @ c5ccd1cd57e8219aea3be1e758221795fa5b7ec8, build.py hooks; MIT,
|
||||
# Copyright (c) 2026 Ivan0xFF). Its hooks branch to code caves; here each is rewritten without branches or flags, as
|
||||
# the generator's patch sites need. The set names differ from NX2navi's (output, scene, aspect), whose page layout
|
||||
# runtime/resolution.c owns.
|
||||
|
||||
set wide_out NX2NAVI_PATCH_WIDE_OUT 0
|
||||
set wide_scene NX2NAVI_PATCH_WIDE_SCENE 0
|
||||
set wide_aspect NX2NAVI_PATCH_WIDE_ASPECT 0
|
||||
set wide_hud NX2NAVI_PATCH_WIDE_HUD 0
|
||||
set wide_movie NX2NAVI_PATCH_WIDE_MOVIE 0
|
||||
|
||||
# Game image: the graphics setup (main+0x1202ce0) fills the renderer's configuration with the size of the picture the
|
||||
# game presents, 2560x1440 at every console mode (config +0x14, copied to renderer +0x9c, which main+0x346be50 reads
|
||||
# for the main render target set, main+0xf49040), and the display settings object (main+0x31f3890) stores the same size
|
||||
# at +0xb68.
|
||||
site wide_out main 1202ee0 d2814008 @page:x8 # mov x8, #0xa00 -> adrp x8, page
|
||||
site wide_out main 1202ee4 f2c0b408 f9403108 # movk x8, #0x5a0, lsl #32 -> ldr x8, [x8, #96]
|
||||
site wide_out main 31f39f4 d2814008 @page:x8 # mov x8, #0xa00 -> adrp x8, page
|
||||
site wide_out main 31f39f8 f2c0b408 f9403108 # movk x8, #0x5a0, lsl #32 -> ldr x8, [x8, #96]
|
||||
|
||||
# Scene: the display settings object's scene size (+0xb70), 1920x1080, the picture the game's upscaler takes in.
|
||||
site wide_scene main 31f3a00 d280f008 @page:x8 # mov x8, #0x780 -> adrp x8, page
|
||||
site wide_scene main 31f3a04 f2c08708 f9403508 # movk x8, #0x438, lsl #32 -> ldr x8, [x8, #104]
|
||||
|
||||
# Camera aspect ratio: the camera update (main+0x4c48c0, the same code as NX2navi's camera update site in
|
||||
# recomp/patches-v143.txt) copies the camera's near, far, vertical angle and ratio (camera +0x134..+0x140) into the
|
||||
# sead perspective projection the renderer reads (+0x98..+0xb0; the projection's own matrix update, main+0x3485cc0, does
|
||||
# not run in play: the renderer builds its matrices from these fields). The replacement loads the ratio as before and
|
||||
# puts the page's ratio in its place when it is within the page's tolerance of 16:9 (the camera's value is not the bit
|
||||
# pattern of the 16/9 constant, and the tolerance is oot-mod's 0.01); other ratios stay the camera's. fabd + fcmge + bit
|
||||
# write no flags, so the alternatives agree. s1..s4 and x9 are free there: nothing reads them before the call at
|
||||
# main+0x4c534c.
|
||||
site wide_aspect main 4c5334 bd414260 bd414260 @page:x9 2d4e0921 bd407923 7ea1d404 7e24e464 2ea41c40 # ldr s0, [x19, #0x140]; ldp s1, s2, [x9, #112]; ldr s3, [x9, #120]; fabd s4, s0, s1; fcmge s4, s3, s4; bit v0, v2, v4
|
||||
|
||||
# The same replacement where sead's perspective projection builds its matrix (doUpdateMatrix, main+0x3485cc0) and in
|
||||
# the three inlined copies of it the game mostly uses; the ratio goes back to the projection (+0xb0), so culling sees
|
||||
# the wider view. Ratios that are not 16:9 (cube maps, square views) are kept. Scratch: x9 and three s registers that
|
||||
# the next instructions overwrite before they read them.
|
||||
site wide_aspect main 3485cc0 2d558400 2d558400 @page:x9 2d4e0d22 bd407924 7ea2d422 7e22e482 2ea21c61 bd00b001 # doUpdateMatrix: ldp s0, s1, [x0, #0xac]
|
||||
site wide_aspect main 4f1e8 2d558ea0 2d558ea0 @page:x9 2d4e1524 bd407922 7ea4d464 7e24e444 2ea41ca3 bd00b2a3 # inlined matrix update: ldp s0, s3, [x21, #0xac]
|
||||
site wide_aspect main 23b9a8 2d558c00 2d558c00 @page:x9 2d4e1524 bd407922 7ea4d464 7e24e444 2ea41ca3 bd00b003 # inlined matrix update: ldp s0, s3, [x0, #0xac]
|
||||
site wide_aspect main 33b82c 2d558440 2d558440 @page:x9 2d4e1123 bd407922 7ea3d423 7e23e443 2ea31c81 bd00b041 # inlined matrix update: ldp s0, s1, [x2, #0xac]
|
||||
|
||||
# HUD and menus: the 2D canvas setup (main+0x774330) multiplies a layout's projection by its view. When the projection
|
||||
# is the full-screen orthographic one of the 3840x2160 layout grid, its first row is scaled by 16:9 over the picture's
|
||||
# ratio, so the UI keeps its shape in the middle 16:9 of the picture, its edge elements at that area's edges, and the
|
||||
# markers that follow the 3D world stay on their targets. Screens whose canvas (+0x1b8 into the screen object) belongs
|
||||
# to the item-wheel background (vtable main+0x4bed098) or the pause and system menu backgrounds (main+0x4be4fb0) keep
|
||||
# it, as in oot-mod: they redraw a capture of the whole picture. So do the event and loading fades (UIEventFadeScreen
|
||||
# main+0x4be61c8, UILoadingFadeScreen main+0x4be7b30; the vtables that hold those names at +0x378): a fade is one colour,
|
||||
# and in the middle 16:9 alone it would leave the picture showing at the sides. Without branches: the two projection
|
||||
# words are compared in vector lanes, the screen's vtable is read from the canvas' screen only when they match (else from
|
||||
# the canvas itself, a readable address) and compared with the four on the page, and bit selects the scaled row. x16, x17 and v16..v19 are free (a leaf; v16..v19 are written next).
|
||||
site wide_hud main 774368 ad401041 ad401041 @page:x16 fd404a10 6e040431 6e0c2491 0ea0fa31 2eb08e31 2eb1ae31 0e040631 9e660231 d106e010 8a110210 8a310011 aa110210 fd400210 @page:x17 3dc02a32 3dc03633 4e080610 6ef28e12 6ef38e13 4eb31e52 6e124253 0eb31e52 0e721e31 4e040631 3dc02e33 6e33dc33 6eb11e61 # 2D canvas: ldp q1, q4, [x2]
|
||||
|
||||
# Pre-rendered movies: the movie layer's draw (main+0x3b5c71c) builds a viewport over the whole picture (sead viewport
|
||||
# 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]
|
||||
@@ -359,6 +359,7 @@ void rt_boot(void) {
|
||||
mods_exefs_switch(); // after the patch sets' settings: an enabled mod's ExeFS patches on
|
||||
frame_step_init();
|
||||
res_init();
|
||||
wide_init(); // Ocarina's widescreen sets (recomp/patches-v111.txt)
|
||||
cheats_init(); // after the patch sets: a cheat's set follows its setting
|
||||
cb_addr[0] = hostfn_register("<rtld loader_ready>", cb_loader_ready);
|
||||
cb_addr[1] = hostfn_register("<rtld module_inits>", cb_module_inits);
|
||||
|
||||
@@ -42,13 +42,13 @@ static const char *const known[] = {
|
||||
"DESC_TEMPLATE", "DEVICE_PROFILE", "DISCORD_APP_ID", "DISCORD_IMAGE", "DISCORD_RPC", "DLAA", "DLAA_JITTER", "DLAA_MV", "DLAA_MASKDEBUG", "DLAA_MVDEBUG", "DLAA_OBJMV", "DLAA_SURVEY", "DLAA_TIMES", "DLSS", "DLSS_CHAR_MASK", "DLSS_PRESET", "DLSS_REACTIVE", "DUMP", "DUMP_BUF", "DUMP_DIR",
|
||||
"DUMP_LOG", "LOG_CS_BINDS", "LOG_TEX_FLAGS", "LOG_MESH", "MESH", "POOL", "NATIVE_TENSOR", "LOG_RCOND", "LOG_RT_SIZES", "DUMP_WHITE", "DUMP_AFTER", "SUBMIT_FINISH", "ACQUIRE_WAIT", "CS_FALLBACK", "EXEFS", "FEEDBACK", "FIX_C0", "FIX_ZERO", "FLIGHT", "FLIGHT_AT", "FLIGHT_DIR", "FLIGHT_FRAMES",
|
||||
"FLIGHT_SPIKE_MS", "FLIGHT_THUMBS", "FLUSH_SPAN", "FOV", "FOV_PATCH", "FPS60", "FPS_LIMIT", "FREEZE_IDLE", "FREE_CORES",
|
||||
"FULLSCREEN", "FXAA", "GPL", "GPL_DRAW_BUILD", "GPU", "GPU_INDEX", "GPU_NAME", "HDR", "HDR_GAME_NITS", "HDR_HUE",
|
||||
"FULLSCREEN", "FXAA", "GAME_ASPECT", "GPL", "GPL_DRAW_BUILD", "GPU", "GPU_INDEX", "GPU_NAME", "HDR", "HDR_GAME_NITS", "HDR_HUE",
|
||||
"HDR_PEAK_NITS", "HDR_UI_NITS", "HIGHFPS_FIX", "INPUT", "INPUT_RECORD", "INPUT_SCRIPT", "LANG", "LIB_PREBUILD",
|
||||
"LIB_PREBUILD_KEEP", "LIB_PREBUILD_THREADS", "LOCALE", "LOD_GUARD", "LSTICK_DEADZONE", "MEMORY", "MENU_LANG", "MENU_TEST",
|
||||
"MENU_CURSOR", "MENU_CURSOR_LOG", "MENU_TEST_DIR", "MENU_TEST_SET", "MINIMAL_LAYOUT", "MIRROR_GAP", "MODS_DIR", "MODS_DISABLED", "MODS_ORDER", "MODS_REBUILD", "MOTION", "MOUSE_MODE", "MOUSE_DIRECT_PATCH", "MOUSE_SENS", "MOVIE_HOST", "MOVIE_PACE",
|
||||
"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_SCENE", "PCSS", "PCSS_K", "PERF_OVERLAY", "PERF_SLOW_MS", "PIPELINE_CACHE", "PIPE_MEMO", "PIPE_PREBUILD", "PIPE_SKIP", "PIPE_SYNC", "PIPE_WAIT",
|
||||
"ONE_PER_CORE", "OPERATION_MODE", "OUTPUT_RES", "PAD_LAYOUT", "PACE_HZ", "PASS_CRUMBS", "PATCH_OUTPUT", "PATCH_SCENE", "PATCH_WIDE_ASPECT", "PATCH_WIDE_HUD", "PATCH_WIDE_MOVIE", "PATCH_WIDE_OUT", "PATCH_WIDE_SCENE", "PCSS", "PCSS_K", "PERF_OVERLAY", "PERF_SLOW_MS", "PIPELINE_CACHE", "PIPE_MEMO", "PIPE_PREBUILD", "PIPE_SKIP", "PIPE_SYNC", "PIPE_WAIT",
|
||||
"PREWARM_WAIT_MS", "PREWARM_XLATE", "PROBE_MOVIE", "PROBE_MOVIE_SHOT", "PROFILE", "PROFILE_CHAINS", "PROFILE_DIR", "PROFILE_FRAMES",
|
||||
"PROFILE_MAIN", "PROFILE_RENDER", "PROMPTS", "PUSH_SKIP", "PUSH_STAGE", "RDOC", "RDOC_DIR", "RDOC_DLL", "REALTIME", "REC_END", "REEXEC",
|
||||
"RENDER_SCALE", "REPLAY_ASYNC",
|
||||
@@ -68,7 +68,7 @@ static const struct { const char *key, *section; } sections[] = {
|
||||
{"FPS_LIMIT", "frame rate"}, {"FPS60", "frame rate"},
|
||||
{"REALTIME", "frame rate"}, {"CLOTH_REALTIME", "frame rate"}, {"HIGHFPS_FIX", "frame rate"},
|
||||
{"FULLSCREEN", "display"}, {"WINDOW_SIZE", "display"}, {"PERF_OVERLAY", "display"}, {"VK_PRESENT", "display"},
|
||||
{"GPU_INDEX", "display"}, {"OUTPUT_RES", "display"}, {"RENDER_SCALE", "display"}, {"UPSCALER", "display"},
|
||||
{"GPU_INDEX", "display"}, {"OUTPUT_RES", "display"}, {"GAME_ASPECT", "display"}, {"RENDER_SCALE", "display"}, {"UPSCALER", "display"},
|
||||
{"SHARPNESS", "display"}, {"ASPECT", "display"}, {"FOV", "display"}, {"ANISO", "display"},
|
||||
{"COLOR_PRESET", "display"},
|
||||
{"COLOR_BRIGHTNESS", "display"}, {"COLOR_CONTRAST", "display"}, {"COLOR_SATURATION", "display"},
|
||||
@@ -120,6 +120,7 @@ static const CfgMeta metas[] = {
|
||||
{"DLAA", "0", "0|1", RESTART}, {"DLSS", "dlaa", "dlaa|quality|balanced|performance|ultra_performance", LIVE},
|
||||
{"DLSS_PRESET", "default", "default|k|j", LIVE},
|
||||
{"DLSS_CHAR_MASK", "65", "0|35|65|100", LIVE}, {"FXAA", "1", "0|1", LIVE},
|
||||
{"GAME_ASPECT", "16:9", "16:9|window|21:9|32:9", RESTART}, // widescreen.c
|
||||
{"ASPECT", "fit", "fit|stretch", LIVE}, {"FOV", "100", "70..140", LIVE},
|
||||
{"ANISO", "game", "game|2|4|8|16", RESTART}, // vk_texture.c sampler_features
|
||||
// colour adjustment (vk_color.c); the preset is the menu's, the four values are what the present uses
|
||||
|
||||
@@ -192,9 +192,11 @@ static void refresh_rate_update(HWND h, int force) {
|
||||
gfx_window_set_refresh(monitor_rate_hz(mon));
|
||||
}
|
||||
|
||||
// Before the window exists (widescreen.c wide_init at start), the primary monitor: the one a fullscreen window opens on.
|
||||
int gfx_window_monitor_size(int *w, int *h) {
|
||||
MONITORINFO mi = {sizeof mi};
|
||||
if (!g_hwnd || !GetMonitorInfoW(MonitorFromWindow(g_hwnd, MONITOR_DEFAULTTOPRIMARY), &mi)) return 0;
|
||||
HMONITOR mon = g_hwnd ? MonitorFromWindow(g_hwnd, MONITOR_DEFAULTTOPRIMARY) : MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (!GetMonitorInfoW(mon, &mi)) return 0;
|
||||
*w = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
*h = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
return 1;
|
||||
|
||||
@@ -265,6 +265,8 @@ uint64_t res_heap_extra_kib(void); // added to the HeapD
|
||||
int res_heapdef_build(const void *in, size_t n, void **out, size_t *out_n); // the HeapDef table (.byml.zs) with
|
||||
// the grown heaps, malloc'd; 0 = cannot (logged)
|
||||
void res_heapdef_served(void); // romfs.c serves the grown table
|
||||
void wide_init(void); // after rt_patches_init: widescreen.c, NX2NAVI_GAME_ASPECT
|
||||
int wide_available(void); // the generated C has the widescreen sets
|
||||
void res_init(void); // after rt_patches_init: the patch page and the sets
|
||||
float res_dlss_lod_bias(void); // NX2NAVI_DLSS upscaling: texture LOD bias (<= 0)
|
||||
int res_dlss_mode(const char *mode); // NX2NAVI_DLSS changed while running: new scene size
|
||||
|
||||
@@ -53,6 +53,7 @@ void vk_queue_lock(void);
|
||||
void vk_queue_unlock(void);
|
||||
void res_sizes(unsigned out[2], unsigned scene[2]);
|
||||
int res_adjustable(void);
|
||||
int wide_available(void);
|
||||
const char *const *vk_color_preset(const char *name);
|
||||
double frame_step_limit_hz(void);
|
||||
int frame_limit_adjustable(void);
|
||||
@@ -689,6 +690,10 @@ static void tab_screen(float scale) {
|
||||
// The game resolution needs the output and scene patch sets (resolution.c res_adjustable): Ocarina's build has
|
||||
// none and always draws its own size, so the row would change nothing
|
||||
if (res_adjustable()) row_output_res();
|
||||
// Widescreen needs the patch sets of recomp/patches-v111.txt (widescreen.c wide_available)
|
||||
static const UiTextId wide[] = {UI_MENU_GAME_ASPECT_16_9, UI_MENU_GAME_ASPECT_WINDOW, UI_MENU_GAME_ASPECT_21_9,
|
||||
UI_MENU_GAME_ASPECT_32_9};
|
||||
if (wide_available()) opt_choice("NX2NAVI_GAME_ASPECT", UI_MENU_GAME_ASPECT, wide, 4, UI_MENU_GAME_ASPECT_DESC);
|
||||
static const UiTextId up[] = {UI_MENU_UPSCALER_FSR, UI_MENU_UPSCALER_BILINEAR};
|
||||
opt_choice("NX2NAVI_UPSCALER", UI_MENU_UPSCALER, up, 2, UI_MENU_UPSCALER_DESC);
|
||||
// RCAS runs only under FSR (vk_fsr.c vk_fsr_record): with bilinear the slider would do nothing
|
||||
|
||||
@@ -80,6 +80,11 @@ static const char *const text_en[UI_TEXT_COUNT] = {
|
||||
[UI_MENU_ASPECT] = "Picture shape",
|
||||
[UI_MENU_ASPECT_DESC] = "When the window's shape differs from the game resolution's (a 16:9 picture on a 21:9 "
|
||||
"screen): keep the picture's shape with black bars, or stretch it over the window.",
|
||||
[UI_MENU_GAME_ASPECT] = "Widescreen",
|
||||
[UI_MENU_GAME_ASPECT_DESC] = "The game draws a wider picture: more of the world at the sides, the HUD and menus in "
|
||||
"the middle 16:9. Window shape follows the window (the monitor in fullscreen).",
|
||||
[UI_MENU_GAME_ASPECT_16_9] = "16:9 (the game's)", [UI_MENU_GAME_ASPECT_WINDOW] = "Window shape",
|
||||
[UI_MENU_GAME_ASPECT_21_9] = "21:9", [UI_MENU_GAME_ASPECT_32_9] = "32:9",
|
||||
[UI_MENU_ASPECT_FIT] = "Black bars", [UI_MENU_ASPECT_STRETCH] = "Stretch",
|
||||
[UI_MENU_FOV] = "Field of view",
|
||||
[UI_MENU_FOV_DESC] = "How much of the world the camera shows, in percent of the game's own. Game version 1.4.3 only.",
|
||||
@@ -554,6 +559,11 @@ static const char *const text_ru[UI_TEXT_COUNT] = {
|
||||
[UI_MENU_ASPECT] = "Форма картинки",
|
||||
[UI_MENU_ASPECT_DESC] = "Когда форма окна отличается от разрешения игры (картинка 16:9 на экране 21:9): сохранить "
|
||||
"форму картинки с чёрными полосами или растянуть её на всё окно.",
|
||||
[UI_MENU_GAME_ASPECT] = "Широкий экран",
|
||||
[UI_MENU_GAME_ASPECT_DESC] = "Игра рисует более широкую картинку: больше мира по бокам, интерфейс и меню в "
|
||||
"центральной части 16:9. «По окну» берёт форму окна (монитора в полноэкранном режиме).",
|
||||
[UI_MENU_GAME_ASPECT_16_9] = "16:9 (как в игре)", [UI_MENU_GAME_ASPECT_WINDOW] = "По окну",
|
||||
[UI_MENU_GAME_ASPECT_21_9] = "21:9", [UI_MENU_GAME_ASPECT_32_9] = "32:9",
|
||||
[UI_MENU_ASPECT_FIT] = "Чёрные полосы", [UI_MENU_ASPECT_STRETCH] = "Растянуть",
|
||||
[UI_MENU_FOV] = "Поле зрения",
|
||||
[UI_MENU_FOV_DESC] = "Сколько мира показывает камера, в процентах от игрового. Только для версии игры 1.4.3.",
|
||||
@@ -1063,6 +1073,11 @@ static const char *const text_pt_br[UI_TEXT_COUNT] = {
|
||||
[UI_MENU_ASPECT] = "Formato da imagem",
|
||||
[UI_MENU_ASPECT_DESC] = "Quando o formato da janela difere do da resolução do jogo (uma imagem 16:9 numa tela "
|
||||
"21:9): manter o formato da imagem com barras pretas ou esticá-la sobre a janela.",
|
||||
[UI_MENU_GAME_ASPECT] = "Tela larga",
|
||||
[UI_MENU_GAME_ASPECT_DESC] = "O jogo desenha uma imagem mais larga: mais do mundo nas laterais, a interface e os "
|
||||
"menus no centro 16:9. Formato da janela segue a janela (o monitor em tela cheia).",
|
||||
[UI_MENU_GAME_ASPECT_16_9] = "16:9 (o do jogo)", [UI_MENU_GAME_ASPECT_WINDOW] = "Formato da janela",
|
||||
[UI_MENU_GAME_ASPECT_21_9] = "21:9", [UI_MENU_GAME_ASPECT_32_9] = "32:9",
|
||||
[UI_MENU_ASPECT_FIT] = "Barras pretas", [UI_MENU_ASPECT_STRETCH] = "Esticar",
|
||||
[UI_MENU_SHARPNESS] = "Nitidez do FSR",
|
||||
[UI_MENU_SHARPNESS_DESC] = "Aumento de nitidez após a escala do FSR, também quando a imagem é reduzida à janela; 0 "
|
||||
@@ -1578,6 +1593,11 @@ static const char *const text_zh_hans[UI_TEXT_COUNT] = {
|
||||
[UI_MENU_ASPECT] = "画面宽高比",
|
||||
[UI_MENU_ASPECT_DESC] = "当窗口宽高比和游戏分辨率不同时(21:9 屏幕上显示 16:9 画面):"
|
||||
"用黑边保持画面比例,或拉伸铺满窗口。",
|
||||
[UI_MENU_GAME_ASPECT] = "宽屏",
|
||||
[UI_MENU_GAME_ASPECT_DESC] = "游戏绘制更宽的画面:两侧显示更多场景,界面和菜单位于中间的 16:9 区域。"
|
||||
"“窗口比例”跟随窗口(全屏时跟随显示器)。",
|
||||
[UI_MENU_GAME_ASPECT_16_9] = "16:9(游戏原生)", [UI_MENU_GAME_ASPECT_WINDOW] = "窗口比例",
|
||||
[UI_MENU_GAME_ASPECT_21_9] = "21:9", [UI_MENU_GAME_ASPECT_32_9] = "32:9",
|
||||
[UI_MENU_ASPECT_FIT] = "黑边",
|
||||
[UI_MENU_ASPECT_STRETCH] = "拉伸",
|
||||
[UI_MENU_FOV] = "视野",
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef enum {
|
||||
UI_MENU_RENDER_SCALE, UI_MENU_RENDER_SCALE_DESC, UI_MENU_RENDER_SCALE_GAME,
|
||||
UI_MENU_UPSCALER, UI_MENU_UPSCALER_DESC, UI_MENU_UPSCALER_FSR, UI_MENU_UPSCALER_BILINEAR,
|
||||
UI_MENU_ASPECT, UI_MENU_ASPECT_DESC, UI_MENU_ASPECT_FIT, UI_MENU_ASPECT_STRETCH,
|
||||
UI_MENU_GAME_ASPECT, UI_MENU_GAME_ASPECT_DESC, UI_MENU_GAME_ASPECT_16_9, UI_MENU_GAME_ASPECT_WINDOW,
|
||||
UI_MENU_GAME_ASPECT_21_9, UI_MENU_GAME_ASPECT_32_9,
|
||||
UI_MENU_FOV, UI_MENU_FOV_DESC,
|
||||
UI_MENU_SHADOW_RES, UI_MENU_SHADOW_RES_DESC, UI_MENU_SHADOW_RES_GAME,
|
||||
UI_MENU_ANISO, UI_MENU_ANISO_DESC, UI_MENU_ANISO_GAME,
|
||||
|
||||
101
runtime/widescreen.c
Normal file
101
runtime/widescreen.c
Normal file
@@ -0,0 +1,101 @@
|
||||
// Widescreen (Ocarina of Time 1.1.1): the game draws a picture of another shape than 16:9, with the camera seeing more
|
||||
// of the world at the sides (Hor+: the vertical view stays the game's) instead of a stretched 16:9 view.
|
||||
//
|
||||
// The game presents a 2560x1440 picture at every console mode and renders its scene at 1920x1080, which its upscaler
|
||||
// takes to the picture's size; both sizes are constants in its code. The patch sets of recomp/patches-v111.txt read
|
||||
// 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).
|
||||
//
|
||||
// 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
|
||||
// 16:9 or narrower than it keeps the game's own sizes; the widest is 32:9.
|
||||
//
|
||||
// The page's layout is described at the top of recomp/patches-v111.txt.
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg.h"
|
||||
#include "gfx_wsys.h"
|
||||
#include "host.h"
|
||||
#include "layout.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
#define GAME_W 2560 // the picture, main+0x1202ee0 and main+0x31f39f4
|
||||
#define GAME_H 1440
|
||||
#define SCENE_H 1080
|
||||
|
||||
// The shape the setting asks for as width / height; 0 for the game's own.
|
||||
static double wanted_ratio(void) {
|
||||
const char *s = cfg_value("NX2NAVI_GAME_ASPECT");
|
||||
if (!strcmp(s, "21:9")) return 64.0 / 27.0;
|
||||
if (!strcmp(s, "32:9")) return 32.0 / 9.0;
|
||||
if (strcmp(s, "window")) return 0;
|
||||
int w = 0, h = 0;
|
||||
if (gfx_cfg_fullscreen()) {
|
||||
if (!gfx_window_monitor_size(&w, &h)) {
|
||||
rt_log("widescreen: the monitor's size is unknown; the game's own 16:9");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
gfx_cfg_window_size(&w, &h);
|
||||
}
|
||||
return h > 0 ? (double)w / h : 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");
|
||||
double r = wanted_ratio(), game = (double)GAME_W / GAME_H;
|
||||
if (r <= 0 || r < game * 1.01) {
|
||||
if (r > 0) rt_log("widescreen: a %.4f picture is not wider than 16:9; the game's own 2560x1440", r);
|
||||
return;
|
||||
}
|
||||
if (so < 0 || ss < 0 || sa < 0 || sh < 0 || sm < 0) {
|
||||
rt_log("widescreen: the generated C has no widescreen patch sets (gen.py --patches recomp/patches-v111.txt); "
|
||||
"the game's own 16:9");
|
||||
return;
|
||||
}
|
||||
if (r > 32.0 / 9.0) r = 32.0 / 9.0;
|
||||
// Widths in whole multiples of 8 pixels (the scene keeps the game's 3:4 of the picture), heights the game's.
|
||||
unsigned ow = (unsigned)lround(GAME_H * r / 8) * 8, sw = (unsigned)lround(ow * 3.0 / 4 / 8) * 8;
|
||||
uint64_t out = (uint64_t)GAME_H << 32 | ow, scene = (uint64_t)SCENE_H << 32 | sw;
|
||||
float match = 16.0f / 9.0f, ratio = (float)ow / GAME_H, tolerance = 0.01f, squeeze = match / ratio;
|
||||
float ui[2] = {2.0f / 3840.0f, 2.0f / 2160.0f}, squeeze4[4] = {squeeze, squeeze, squeeze, squeeze};
|
||||
float margin = (1.0f - squeeze) / 2;
|
||||
// the screens whose UI keeps the whole picture (recomp/patches-v111.txt, set wide_hud): the item-wheel, pause and
|
||||
// system menu backgrounds, the event and loading fades
|
||||
uint64_t keep[2] = {MOD_MAIN_BASE + 0x4bed098, MOD_MAIN_BASE + 0x4be4fb0},
|
||||
keep2[2] = {MOD_MAIN_BASE + 0x4be61c8, MOD_MAIN_BASE + 0x4be7b30};
|
||||
uint8_t *page = rt_patch_page();
|
||||
memcpy(page + 96, &out, 8);
|
||||
memcpy(page + 104, &scene, 8);
|
||||
memcpy(page + 112, &match, 4);
|
||||
memcpy(page + 116, &ratio, 4);
|
||||
memcpy(page + 120, &tolerance, 4);
|
||||
memcpy(page + 144, ui, 8);
|
||||
memcpy(page + 160, keep, 16);
|
||||
memcpy(page + 176, squeeze4, 16);
|
||||
memcpy(page + 192, &margin, 4);
|
||||
memcpy(page + 208, keep2, 16);
|
||||
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);
|
||||
rt_log("widescreen: picture %ux%u, scene %ux%u, camera aspect ratio %.4f (16:9 is %.4f), UI and movies in the "
|
||||
"middle %.1f%%", ow, GAME_H, sw, SCENE_H, ratio, game, squeeze * 100);
|
||||
}
|
||||
|
||||
// The generated C has the widescreen patch sets (the menu shows the row only then).
|
||||
int wide_available(void) {
|
||||
static const char *const names[] = {"wide_out", "wide_scene", "wide_aspect", "wide_hud", "wide_movie"};
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (rt_patch_set(names[i]) < 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user