-
-
Notifications
You must be signed in to change notification settings - Fork 82
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
Use fixed render sizes and SDL_RenderSetLogicalSize for scaling #275
base: master
Are you sure you want to change the base?
Conversation
|
The scale is only used for the window size. It doesn't matter for fullscreen. I guess those
For the Via and Switch I use custom resolutions to avoid letterboxing -- the same resolutions that they use today. |
8ff2c57
to
3ca02b4
Compare
Status update: I think this is looking really good. It's just about ready, but I want to get more testing done before marking it as ready. Update: my friend's driver has a bug unrelated to NXengine or my changes. |
c72a478
to
486f979
Compare
I have been playing with this version for the last couple months and it has been working flawlessly for me. It's ready to consider for merging. |
Without this, the whole game is rendered at 1x resolution and linearly scaled up on high DPI screens.
If the user switches to/from widescreen mode while the inventory is open, the position of the inventory will now update instead of being offset one way or the other. Also, it's not necessary to adjust the y position of the inventory based on whether we're in widescreen mode because the screen height doesn't change.
Same as the inventory menu.
The SDL docs say this needs to be called before drawing to the render buffer, even if you plan to paint every pixel. Not calling it was causing graphical glitches outside the render area when the render area didn't fill the whole screen, such as when rendering a 4:3 viewport on a 16:9 monitor.
The x position of the camera used to be manually calculated for maps that are less wide than the screen. Now it's calcualted automatically so that these maps are always in the center of the screen, regardless of screen width.
Switch is 16:9, so the standard widescreen resolution should work fine.
To be honest, I thought this is what SDL_RenderSetLogicalSize() did, but actually it scales up each object that you draw with SDL_RenderCopy(). This is necessary because on some GPUs, scaling up can cause a sprite to bleed into an adjacent frame in the spritesheet texture. This shouldn't happen with nearest neighbor scaling, but it nevertheless does happen on some GPUs such as my laptop's embedded Intel GPU. On this GPU I saw a one pixel wide strip on the top and left of every sprite that showed the neighboring sprite frame. The strip was one pixel wide in my screen's pixels, not the logical resolution's pixels. Rendering everything to a 320x240 texture and then scaling up the whole texture at once makes strange bugs like this impossible.
486f979
to
15e475f
Compare
Rebased |
Renderer::initVideo now depends on Sprites being initialized because it calls setResolution. If the sprites aren't initialized, the Renderer can get a segfault in flushAll() when it tries to check which spritesheets are initialized and which aren't. Sprites can only detect whether the spritesheets are initialized after Sprites::init has been called, which zeroes out the spritesheets. This bug only appeared on my Raspberry Pi, so I didn't notice it in the last several months of testing. Presumably the other systems I tested on had this uninitialized memory set to all zeroes by chance.
This patch worked great for me. I was playing on an RGB30 device which has a 1:1 screen. The old scaling actually has a bug (I can open an issue if you want), where it seems like the rendered viewport doesn't match the actual area of the game rendered. I was seeing some blocks flicker in and out on the right side of the screen. This patch as is correctly draws the correct screen area only and draws black outside the configured aspect ratio. (I haven't tested the current code, I built before this branch was recently rebased) |
newWidth = 432; | ||
newHeight = 243; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code was also much easier to hack on and add a custom aspect ratio. I manually patched these "widescreen" values to be a 1:1 full screen aspect ratio. I accidentally the code I used for my build, I'm unsure what exact values I used.
I wonder, would it make sense to make these "widescreen" values configurable? Perhaps from an environment variable or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I worked on this at first, I had in mind that 320x240 was the "one true resolution" since that's what the original game had, but I added widescreen as a concession because nxengine-evo already had support for it.
Since then I've thought a lot about it. I think it could be nice to add support for a variety of ratios. The main constraint is that the vertical resolution should be 240 pixels (or very close to it). We could either have a list of hand-picked resolutions like we have here, or we could even have an algorithm that automatically makes a resolution for your aspect ratio that meets the requirements. But letting the user manually choose a resolution or aspect ratio that's not on the list is also a good idea.
In any case, I don't want to add any new features to this already quite large PR. If it's merged I would be happy to look into ideas like these.
Cool!
I believe I noticed the same thing while working on this PR and fixed it in fdbcf01. That could probably be backported to the main branch if this PR isn't accepted. |
Previously we had a range of possible resolutions of different aspect ratios. Each of these resolutions could be windowed or full screen. This change simplifies the renderer a bit. Now the renderer only supports two resolutions: the original 320x240 and a widescreen resolution of 432x243. The widescreen resolution was chosen as the integer resolution that is closest to 240 lines tall that is also has 16:9 aspect ratio.
Now the display settings are also simpler. You can choose 1x, 2x, or 3x scale, or fullscreen. Widescreen is a separate option. SDL automaticaly scales up with nearest neighbor interpolation. In fullscreen mode, if the renderer aspect ratio doesn't match the user's screen ratio, the display is simply letterboxed.
This change comes with the following benefits:
SDL_SetWindowDisplayMode
.SDL_FULLSCREEN_DESKTOP
instead of changing the monitor's mode is faster, smoother, and integrates better with the user's desktop. On Wayland, changing the monitor's mode isn't even possible in SDL.There are currently a few problems that mean this isn't ready for merging yet:
Maps are off-center in widescreen mode. See "kings" intro for example. This relates torecalc_map_offsets()
andmap.maxxscroll
.Example
Flickering outside render area in fullscreen mode; looks like uninitialized memory. SDL docs say the display should be letterboxed and the letterboxed area should just be black. This is because SDL_RenderClear is never called anywhere. It should be called once per frame.Inventory position doesn't update to center of screen if you switch to/from widescreen while the inventory is openAt some monitor resolutions in fullscreen, some sprites have overdraw. This is a GPU bug that affects certain GPU models. I implemented a workaround.Example
I don't own a Switch and Vita that I can test with, but I have simulated their screens with appropriately sized windows.
Fixes #171.
Fixes #245.
Fixes #276.