Skip to content

feat: Monitor's shape for screens narrower than 16:9 (4:3, 16:10, 5:4) - #1224

Open
nesrodzair wants to merge 2 commits into
NotRexed:mainfrom
nesrodzair:feat/narrow-screens
Open

nesrodzair wants to merge 2 commits into
NotRexed:mainfrom
nesrodzair:feat/narrow-screens

Conversation

@nesrodzair

Copy link
Copy Markdown

What changed

The Ultrawide option's Monitor's shape only acted on screens wider than 16:9. On a 4:3 or 16:10 screen the log said a 1.3333 screen is not wider than 16:9: the game's own picture and the game showed its 16:9 picture with black bars.

host/hos_main.c now runs the same sizing for a narrower screen too, down to 5:4 (a narrower one is kept at 5:4, the same floor as present_window_size in rx_present_fx.cpp):

  • the picture keeps the game's height and gets narrower: 1920 x 1440 for a 4:3 screen at the 1440 output, 2880 x 2160 at the 4K one;
  • the scene stays 3/4 of the picture (1440 x 1080 for 4:3);
  • the cameras take the picture's ratio (same height as 16:9, narrower sides);
  • hos_wide_squeeze is capped at 1, so the HUD and menus fill the picture's width instead of a middle 16:9 wider than the screen (it was 133% and cut the menus at both sides). hos_wide_margin is then 0 and movies fill the picture.

Screens wider than 16:9 go through the exact same code as before (same sizes, squeeze and margin, checked by the test for 21:9 and 32:9). A 16:9 screen still gets the game's own picture. The menu's help line and the readme's Ultrawide rows now mention narrower screens.

Known limitation

As with ultrawide, the HUD is drawn on the game's 16:9 grid and stretched to the picture: on 4:3 it is 25% narrower than on 16:9, and movies are squeezed the same way. Proper 4:3 HUD placement would need new UI patches in nx2/oot_wide.py and is not part of this PR.

How it was tested

  • tests/test_widescreen_shapes.py (new, game-free, registered in tests/run_all.py): lifts the block out of hos_main.c and checks picture, scene, camera ratio, HUD squeeze and movie margin for 4:3, 16:10, 5:4, narrower than 5:4, 4:3 at the 4K output, 16:9, 21:9, 32:9 and Ultrawide off. It fails on main for the narrow cases and passes for the wide ones unchanged.
  • python -I -B tests/run_all.py: 140 passed, 0 failed, 17 skipped (Linux, missing headers or tools only).
  • In game: the same change was first tried as a binary patch of hookshot.exe (threshold of the 16:9 test, min(ratio, 16/9) for the HUD width). Played on a 4:3 IBM CRT at 2048 x 1536 (RTX 5080, Windows): the log shows picture 1920x1440, scene 1440x1080, camera ratio 1.3333, HUD and movies in the middle 100.0%, no black bars, correct camera and FOV, and the pause and System menus fit on screen. Kokiri Forest and Link's house.

@hckrman101 hckrman101 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, small change. What I checked:

  • Wider than 16:9 still goes through the exact same math (only the new || arm and the 5:4 clamp are added; fmin(1.0, ...) is a no-op when the ratio is above 16:9), so 21:9 / 32:9 results are unchanged.
  • With squeeze = 1 and margin = 0, the HUD and MOVIE patches in nx2/oot_wide.py become no-ops (*= 1.0, and _m > 0.0f is false), so a narrow screen just gets the game's 16:9 UI stretched to the picture, which is the limitation you describe.
  • hos_rt_pool_size takes the larger of the output and the widescreen picture, so a narrower picture can't shrink the RT pool.
  • The new else-branch log text is right: that branch is now only reached for 16:9 +-1%.
  • The test lifts the real block out of hos_main.c, checks real values (including 21:9/32:9 as regression cases) and is registered in run_all.py with --cc gcc, like the other C fixtures.

One issue before this is ready:

The default window stretches the 4:3 picture. host/display.c (and host/posix/display_sdl.c on Linux) size the initial window as hos_aspect_ratio > 1.8f ? 720 * ratio : 1280, so with this PR a 4:3 or 16:10 screen still opens a 1280x720 window. On the Vulkan path vk_replay.cpp sets preserve_stretch whenever aspect_ratio() > 1.0f, so present_rect stretches the 1920x1440 picture over the whole 16:9 window: everything ends up 33% too wide until the player goes fullscreen. Fullscreen is off by default, and your CRT test was fullscreen, so this probably didn't show up. Something like (hos_aspect_ratio > 1.8f || (hos_aspect_ratio > 0.0f && hos_aspect_ratio < 1.76f)) ? (int)(720 * hos_aspect_ratio + 0.5f) : 1280 in both files would open a 960x720 window for 4:3 instead.

Small things:

  • The comments that describe the feature still say it only widens: the block comment above this code in hos_main.c ("the world wider at the sides", "the HUD, menus and movies the middle 16:9") and the nx2/oot_wide.py docstring ("the width grows"). Worth updating so they match.
  • FYI, #1183 (save picture on ultrawide) uses hos_wide_squeeze too. With squeeze = 1 its patch leaves the viewport alone, so on 4:3 the save thumbnail will be the whole 4:3 picture squashed into the 16:9 texture. Not a blocker, just something to keep in mind if both land.

Comment thread host/hos_main.c Resolved
Saiyajin and others added 2 commits November 9, 2026 20:37
The Ultrawide option's Monitor's shape only acted on screens wider than
16:9: a 4:3 or 16:10 screen got the game's own 16:9 picture with black
bars. The same sizing now runs for a narrower screen too, down to 5:4:
the picture keeps the game's height and is narrower (1920 x 1440 for a
4:3 CRT at the 1440 output), the scene stays 3/4 of it, the cameras take
its ratio, and the HUD fills the picture's width (squeeze capped at 1)
instead of a middle 16:9 wider than the screen. Screens wider than 16:9
are unchanged.

tests/test_widescreen_shapes.py checks the sizes for 4:3, 16:10, 5:4,
16:9, 21:9 and 32:9 screens without the game.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvkjzHAcf259i979SBbeS
…ddle band, comments

From the review of NotRexed#1224:
- host/display.c and host/posix/display_sdl.c open the default window at
  the picture's shape whenever Monitor's shape set one (960 x 720 for
  4:3): a 1280 x 720 window stretched the 4:3 picture 33% too wide on the
  Vulkan path (preserve_stretch) until fullscreen.
- nx2/oot_wide.py's save picture (NotRexed#1183) reads hos_wide_ratio: past 16:9
  its viewport is widened as before, narrower than 16:9 it is made taller
  so the picture's middle band fills the 543 x 306 texture at its own
  shape. tests/test_oot_wide_save_picture.py covers 4:3, 16:10 and 5:4.
- hos_main.c's block comment, oot_wide.py's docstring and the menu hint
  describe narrower screens too.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EKvkjzHAcf259i979SBbeS

@hckrman101 hckrman101 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks. The window now opens at the picture's shape on both platforms (960x720 for 4:3), HOS_WINDOW_SIZE and the DPI scaling are unaffected, and 16:9 and wide are unchanged. The save picture crop checks out too: the viewport is 306*(16/9)/ratio tall, centred, so the middle band fills the texture at the picture's own shape. Comments and tests are updated and registered. CI shows nothing run yet (workflows waiting for approval).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants