Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 4:3 aspect ratio and add 8:7. #193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

vanfanel
Copy link
Contributor

Description

On the SNES, Zelda ALTTP is rendered internally at 256x224, which is an 8:7 resolution, not 4:3.
However, when output to TV, the game is stretched to 4:3 by the SNES hardware. That's true for every SNES game running at 256x224.

So the game looks better at 4:3 as it looks on a real SNES on a real TV. At 8:7, everything is too "thin".

What this does is make 4:3 really 4:3 (graphics are slightly stretched by OpenGL/SDL2, as in the SNES), and add a 8:7 ratio that matches the internal resolution. This 8:7 ratio is what was previously called 4:3 (that was wrong, because 256x224 is not 4:3 by any means).

Will this Pull Request break anything?

No.

Suggested Testing Steps

Run the game at 4:3 and run it at 8:7 (both can be set on the zelda3.ini file) and compare.

This is simple but somewhat important stuff so the game looks as intended, IMHO.

@FitzRoyX
Copy link
Contributor

This isn't actually true. Nintendo's artists stopped trying to compensate for the stretch after the NES. Every square and circle in lttp, smw, smetroid, only holds that shape at 8:7. The SNES was originally designed to have backwards compatibility with the NES to increase sales. That never happened, but the PPU resolution stuck. So everything gets a bit stretched. Janky, but acceptably so.

@vanfanel
Copy link
Contributor Author

This isn't actually true. Nintendo's artists stopped trying to compensate for the stretch after the NES. Every square and circle in lttp, smw, smetroid, only holds that shape at 8:7. The SNES was originally designed to have backwards compatibility with the NES to increase sales. That never happened, but the PPU resolution stuck. So everything gets a bit stretched. Janky, but acceptably so.

History details apart, there are two facts here:
-The game was displayed at 4:3 on CRT TVs.
-Current 4:3 option is not 4:3, but 8:7.

So, in any case, what this PR does is a good idea, the game looks as it looked on a TV when the 4:3 option is selected, and won't harm anybody.

@FitzRoyX
Copy link
Contributor

It gets even more complicated. The SNES aspect ratio isn't really 8:7, it's 16:15. The main resolution output by the system is 256x240 with line 1 blank, and 15 extra lines blanked when ntsc overscan bit is set. Blanked lines are still output, so their existence can't be ignored in trying to replicate how much crts widened pixels. The multiplier for 256 would be more like 1.25x and not 1.16x.

@gerudoga
Copy link

gerudoga commented May 11, 2024

I wanted to game to render at a very different resolution (720x720, or better 240x240 scaled up by 3) for a specific device. I made some changes here
https://github.com/gerudoga/zelda3
that now allow any and every (I hope) combination of aspect ratio, pixel resolution and display resolution to be set simply via the config ini.

Your case, @vanfanel, would be achieved via:

AspectRatio = 8:7 # this is also the default now
WindowSize = 640x480 # possibly scaled up further
IgnoreAspectRatio = 1

I will rename IgnoreAspectRatio since it is confusing. It sounds like the setting AspectRatio will be ignored... I'll switch to PerfectPixel = 0 or StretchToFit = 1.

@metchebe
Copy link

@gerudoga Hi. Sorry to use this thread to ask, but the topic seemed the most appropriate.

I'm trying out your fork on my RGB30 (720x720 display) and everything works well, except that I've been unable to get a 1:1 image (240x240p times 3) centered on the display (the right gets cut off). From reading the source, I think this should work. Do you have any configuration tips? Thanks.

@gerudoga
Copy link

@metchebe That's exactly the same device I am using. So, the main purpose of my changes was to make that work well. Specifically, the asymmetric cropping should be fixed. I don't understand why you would still see it.

The config that works for me is:

[General]
AspectRatio = 1:1
ExtendedY = 1

[Graphics]
WindowScale = 3

But it sounds like that's what you are using.

Can you enable Debug and check what you get there? It should say:

[Derived]
SNES pixel resolution: 240x240
ext. aspect ratio:     0

@metchebe
Copy link

@gerudoga Yes that's exactly what I'm using, and debug shows those values. However the display instead of showing the square image centered, it seems to stretch it horizontally and crop off the right side. The weird thing is that other wider aspect ratios work as expected (16:15 works good and is the best comprimise for me right now).

It might be a quirk in my OS (the latest Rocknix), or the fact that I'm using KMSDRM.

@gerudoga
Copy link

@metchebe Could you post your full config file?

@metchebe
Copy link

@gerudoga My ini file is copied below. I also want to add that none of this happens when I try 1:1 on my PC, this only happens on the RGB30.

I tried to reproduce what I see in an image editor. From what I can tell, the 240x240 (SNES resolution) image gets trimmed to something like 232x240, then stretched back to 240x240 resulting in this:

zelda3

[General]
# Automatically save state on quit and reload on start
Autosave = 0

# Print debug information
Debug = 1

# Display FPS counter in window title
DisplayPerfInTitle = 0

# Aspect ratio, e.g., 16:9, 16:10, 18:9, 4:3, etc.
# The default 8:7 results in the normal 256x224 SNES resolution.
AspectRatio = 1:1

# Display 240 lines instead of 224.
# This needs to be taken into account when setting AspectRatio.
# For instance, 256x240 SNES resolution corresponds to: AspectRatio = 16:15
ExtendedY = 1

# Avoid changing sprite spawn/die behavior. Without this replays will be incompatible.
UnchangedSprites = 0

# Avoid fixing some graphics glitches (for example with Cape).
# This won't affect replays/game behavior but the memory compare will not work.
NoVisualFixes = 0

# Disable the SDL_Delay that happens each frame (Gives slightly better perf if your
# display is set to exactly 60hz)
DisableFrameDelay = 0

# Allows to quit the game by pressing start and select buttons together
GamepadQuit = 1

# Set which language to use. Note. In order to use other languages you need to create
# the assets file appropriately.
# python restool.py --extract-dialogue -r german.sfc
# python restool.py --languages=de
# Language = de

[Graphics]
# Window size ( Auto or WidthxHeight )
WindowSize = Auto

# Fullscreen mode (0=windowed, 1=desktop fullscreen, 2=fullscreen w/mode change)
Fullscreen = 0

# Window scale (1=100%, 2=200%, 3=300%, etc.)
WindowScale = 3

# Use an optimized (but potentially more buggy) SNES PPU implementation
NewRenderer = 1

# Display the world map with higher resolution
EnhancedMode7 = 0

# Stretch image to fit the window. This may change the pixel aspect ratio.
# For instance, the classic SNES on CRT TVs image is achieved like this:
# AspectRatio = 8:7 # this is also the default
# WindowSize = 640x480 # possibly scaled up further
# StretchToFit = 1
StretchToFit = 0

# Enable this option to remove the sprite limits per scan line
NoSpriteLimits = 1

# Change the appearance of Link by loading a ZSPR file
# See all sprites here: https://snesrev.github.io/sprites-gfx/snes/zelda3/link/
# Download the files with "git clone https://github.com/snesrev/sprites-gfx.git"
# LinkGraphics = sprites-gfx/snes/zelda3/link/sheets/megaman-x.2.zspr

# Use either SDL, SDL-Software, OpenGL, or OpenGL ES as the output method
# SDL-Software rendering might give better performance on Raspberry pi.
OutputMethod = SDL

# Set to true to use linear filtering. Gives less crisp pixels. Works with SDL and OpenGL.
LinearFiltering = 0

# Set a glsl shader. Only supported with the OpenGL output method
# This can be the path to a .glsl or .glslp file
# Get them with: git clone https://github.com/snesrev/glsl-shaders
Shader =

# Recreate the behavior of the Virtual Console releases, where flashing effects are lessened
DimFlashes = 0

[Sound]
EnableAudio = 1

# DSP frequency in samples per second (e.g. 48000, 44100, 32000, 22050, 11025)
AudioFreq = 44100

# number of separate sound channels (1=mono, 2=stereo)
AudioChannels = 2

# Audio buffer size in samples (power of 2; e.g., 4096, 2048, 1024) [try 1024 if sound is crackly]. The higher the more lag before you hear sounds.
AudioSamples = 512

# Enable MSU support for audio. Supports MSU or MSU Deluxe in PCM or OPUZ format.
# OPUZ is around 10% of the size compared to PCM.
# PCM MSU requires AudioFreq = 44100 to work properly while OPUZ needs 48000.
# The following values are accepted: false, true, deluxe, opuz, deluxe-opuz
EnableMSU = false

# The path to the MSU files. The number and the file extension are appended automatically.
MSUPath = msu/alttp_msu-

# Remember MSU position and return back to the same position when entering
# an overworld area. (Only remembers one area)
ResumeMSU = 1

# Change the volume of the MSU playback, a value between 0-100
MSUVolume = 100%

[Features]
# Item switch on L/R. Also allows reordering of items in inventory by pressing Y+direction.
# Hold X, L, or R inside of the item selection screen to assign items to those buttons.
# If X is reassigned, Select opens the map. Push Select while paused to save or quit.
# When L or R are assigned items, those buttons will no longer cycle items.
ItemSwitchLR = 0

# Enable this to limit the ItemSwitchLR item cycling to the first 4 items.
ItemSwitchLRLimit = 0

# Allow turning while dashing
TurnWhileDashing = 0

# Allow mirror to be used to warp to the Dark World
MirrorToDarkworld = 0

# Collect items (like hearts) with sword instead of having to touch them
CollectItemsWithSword = 0

# Level 2-4 sword can be used to break pots
BreakPotsWithSword = 0

# Disable the low health beep
DisableLowHealthBeep = 0

# Avoid waiting too much at the start
SkipIntroOnKeypress = 0

# Display max rupees/bombs/arrows with orange/yellow color
ShowMaxItemsInYellow = 0

# Allows up to four bombs active at a time instead of two.
MoreActiveBombs = 0

# Can carry 9999 rupees instead of 999
CarryMoreRupees = 0

# Enable various zelda bug fixes
MiscBugFixes = 0

# Enable some more advanced zelda bugfixes that change game behavior
GameChangingBugFixes = 0

# Allow bird travel to be cancelled by hitting the X key
CancelBirdTravel = 0


[KeyMap]
# Change what keyboard keys map to the joypad
# Order: Up, Down, Left, Right, Select, Start, A, B, X, Y, L, R

# This default is suitable for QWERTY keyboards.
Controls = Up, Down, Left, Right, Right Shift, Return, x, z, s, a, c, v

# This default is suitable for QWERTZ keyboards.
#Controls = Up, Down, Left, Right, Right Shift, Return, x, y, s, a, c, v

# This one is suitable for AZERTY keyboards.
#Controls = Up, Down, Left, Right, Right Shift, Return, x, w, s, q, c, v

CheatLife = w
CheatKeys = o
CheatWalkThroughWalls = Ctrl+e
ClearKeyLog = k
StopReplay = l
Fullscreen = Alt+Return
Reset = Ctrl+r
Pause = Shift+p
PauseDimmed = p
Turbo = Tab
ReplayTurbo = t
WindowBigger = Ctrl+Up
WindowSmaller = Ctrl+Down

VolumeUp = Shift+=
VolumeDown = Shift+-

Load =      F1,     F2,     F3,     F4,     F5,     F6,     F7,     F8,     F9,     F10
Save = Shift+F1,Shift+F2,Shift+F3,Shift+F4,Shift+F5,Shift+F6,Shift+F7,Shift+F8,Shift+F9,Shift+F10
Replay= Ctrl+F1,Ctrl+F2,Ctrl+F3,Ctrl+F4,Ctrl+F5,Ctrl+F6,Ctrl+F7,Ctrl+F8,Ctrl+F9,Ctrl+F10

# Uncomment this to allow loading of reference saves
#LoadRef = 1,2,3,4,5,6,7,8,9,0,-,=,Backspace
#ReplayRef = Ctrl+1,Ctrl+2,Ctrl+3,Ctrl+4,Ctrl+5,Ctrl+6,Ctrl+7,Ctrl+8,Ctrl+9,Ctrl+0,Ctrl+-,Ctrl+=,Ctrl+Backspace

[GamepadMap]
# Any keys used in KeyMap can be used also in this section.
# The shoulder button is called L1/Lb and L2, and the thumbstick button is called L3
Controls = DpadUp, DpadDown, DpadLeft, DpadRight, Back, Start, A, B, X, Y, Lb, Rb

@gerudoga
Copy link

@metchebe Your config is virtually identical to mine. I have EnhancedMode7 enabled as well as a few of the extra features. And I needed to adjust the gamepad button configuration to map correctly to the RGB30. But none of these should play a role.

I fear we need to dig a bit deeper and I need to somehow reproduce it... Or you need to find where the bug is in the code on your hardware :)

I would suggest you create a new issue with all info in my repo since it's actually not related to @vanfanel changes in this PR: https://github.com/gerudoga/zelda3/issues

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.

4 participants