ihhub / fheroes2

fheroes2 is a recreation of Heroes of Might and Magic II game engine.
https://ihhub.github.io/fheroes2/
GNU General Public License v2.0
2.72k stars 377 forks source link

Independent Source Size and Rendering Resolution with Multiple Scaling Options (à la HOMM3 HD) #5373

Closed Professor-CDawg closed 1 year ago

Professor-CDawg commented 2 years ago

Preliminary checks

Describe the problem requiring a solution

I prefer to play at resolutions lower than my monitor's native 1920x1080 because I find the game objects too small at 1080p.

This is currently possible in fheroes2's settings menu, but only at resolutions reported as supported from the OS. Furthermore, the image is scaled directly by the GPU's built-in scaling, which is quite blurry in my case (and I suspect the vast majority of cases).

I would like to be able to set a custom resolution not inherently supported by my OS (i.e., 853x480) so I can have a wider variety of widescreen options at resolutions lower than 1080p. Additionally, I would like to be able to select from multiple scaling options other than linear filtering, such as Cubic and Lanczos, as these produce an image that is much more pleasing to my eye.

The features I have described and requested are present in the HOMM3 HD mod for Heroes 3 (hence why I missed them when I tried fheroes2). In HOMM3 HD, I play at a "source size" of 1180x664 (a 16:9 resolution not supported by my OS), and use the Cubic "stretch filter" option.

Describe the possible solution

I may be phrasing this wrongly, but I believe what I'm asking for could be summarized as an implementation of "software upscaling" (as opposed to how fheroes2 currently only allows for "hardware upscaling" via the system's GPU).

Put another way, add a "source size" option that is independent of the final rendering resolution; the final rendering resolution is arrived at via a selectable "stretch filter" (e.g. Cubic, Lanzcos).

Additional info

Examples of HOMM3 HD's implementation of the feature:

source size: 1180x664; stretch filter: Linear image

source size: 1180x664; stretch filter: Cubic image

source size: 1066x600; stretch filter: Cubic image

oleg-derevenetz commented 2 years ago

Duplicate of #4946

tarboss commented 2 years ago
hiddensprite commented 2 years ago

So I've looked into this a bit for my personal interest, both the "independent source size" and the "scaling options" part. These are actually issues that are independent of each other, I'm going to focus on the first one for now.

My motivation for this is similar to @Professor-CDawg's. I've got an older Surface 3 tablet with the somewhat unsual display aspect ratio of 3:2 (1920x1280 resolution). The OS/display driver only supports this aspect ratio for its native resolution. In return that means that I can't utilize the full screen space unless picking the native resolution in fheroes 2 (which makes the game objects way too small).

That's one reason why it would be great to fully decouple internal resolution from display output resolution in fheroes2. There's actually very little change in code needed in order to support this, as SDL will handle the scaling (unless you want custom filters as a second step). The SDL_Window needs to be created with a different width/height than the SDL_Surface/Texture: _window = SDL_CreateWindow( _previousWindowTitle.data(), _prevWindowPos.x, _prevWindowPos.y, displayWidth, displayHeight, flags ); Also, the GetNearestResolution() function would need to apply to this new display width/height setting instead of the logical resolution. That way the logical resolution becomes independent from display resolution.

Even then, how to present this option to the user? A simple solution from a developers perspective would be a new setting in fheroes2.txt that describes the display resolution (additional to the current "videomode"). But the question is if it is acceptable to let the user enter the logical resolution in a free form text field (e.g. typing "1280x720" manually) instead of selecting it from a list as it is done now. Another idea would be to let the user decide for a factor based on the lowest supported fheroes 2 resolution (640x480). The application could then compute the proper logical resolution based on the aspect ratio of the user's display (e.g. 16:9 with a scale factor of 2.25 -> 1920x1080).

Or maybe there's a better solution I haven't though of? What do you think?

In any case I'd be happy to share code or submit a pull request if there's interest.

ihhub commented 2 years ago

Hi @hiddensprite , having to modify something in a file a big no from user perspective. Everything must be within the game's UI. We also cannot allow to enter any random resolution as OSes don't support them and will fit to the nearest in fullscreen mode.

Integer scaling is the only reasonable choice. Imagine to scale by 1.5, then one line of original thickness of 1 pixel would be 1 pixel thick and another - 2 pixels just because of scaling. It would look ugly in the game. We are talking about pixel art, not pre-rendered sprites from 3D models. Don't forget that some algorithms are more optimized for integer scaling even with nearest neighbour approach then for non-integer.

In case of your device 2x scaling is the most optimal making the source / original resolution as 960 x 540 which is by far the best among small resolutions.

hiddensprite commented 2 years ago

I think there might be bit a of misunderstanding, I'll try to express it differently:

I agree that it wouldn't be a good idea to tell the user he should edit something in a file (although it's always good to keep it editable for the tech savvy folks). The question is how one would implement a proper user interface for such a feature: Present a drop-down list at it is now (with the disadvantage that it limits the possible options), make a new resolution entry text field that the user can edit (like in the "save game" dialog), make a scale factor selection, or something entirely different.

Regarding the topic of integer scaling: Personally I think it beauty is in the eye of the beholder in this case, and that it would be good idea to offer choices. As it is implemented right now in fheroes2, there's no properly defined scaling at all. If the user selects a resolution that differs from his native resolution, the scaling will be done by either his display or the GPU driver that manages upscaling. In other words, upscaling will be handled differently on every computer, and the user is unlikely to be aware that he might be able to change the upscaling behavior (displays and drivers sometimes offer differing options). The most commonly selected default upscaling algorithm for displays/drivers is not integer scaling/nearest neighbor but more likely a bilinear filter or something similar (even if the native resolution is evenly divisible by the selected resolution). In effect, most users (that don't select their display's native resolution in the menu) right now are likely playing fheroes2 with a blurred image instead of a pixel perfect one, whether they like it or not.

codeflorist commented 2 years ago

dosbox-staging supports pixel perfect upscaling, perfectly preserving the original look on higher resolutions. it also uses SDL and might be worth a peek for anyone looking for a solution.

imho pixel perfect upscaling is definitively the way to go for preserving these pixelart games.

ihhub commented 1 year ago

I am closing this issue as we have an option for filtering as well as the engine allows to select scaled resolutions. The rest of idea should be covered in #4946.