YesBox said:
I mean if the road paint line is 1 pixel wide on my 32 x 32 sprite, which can disappear when zooming out and moving the view, upscaling it by 400% doesn't change that behavior. Which vaguely makes sense from the little I understand from what's going on under the hood.
Ah ok, yes - this stuff will still disappear. The upscaling proposal helps to preserve a pixel art look and enables ‘low res’ pixels on high res frame buffer with support for filtering to get smooth scaling or rotations.
But it does not handle extreme minification, because if the sampling frequency is much higher than your thin lines are wide, we will still miss many of them completely.
Basically we talk about an undersampling problem. There are generally two options to solve this:
1. More samples. We would make many samples inside the square of a frame buffer pixel (covering the whole area of the pixel) and average them. Some of those samples would hit the thin lines, so they would contribute to the average as desired.
2. Prefiltering the domain we want to sample. We would make a lower resolution image, e.g. by using the average of 2x2 texels of the original image to get one pixel for the new image at half resolution. After that, taking just one sample is good enough, because the thin features are already integrated in the texels of the low res image. That's exactly how mip maps work.
Option 1 is bad for us, becasue the more we zoom out, the more samples we need, and even a simple 2D game like yours would cause performance issues at some point.
So you want option 2, and you already tried that with drawing down scaled textures.
But for smooth scaling, you need to interpolate two of your discrete textures so there is no hard switch.
(just summing up what we already know)
The question now is how could you do such mip interpolation within SFML?
Two options:
1. Get hardware mip maps to work, which would be the least effort. After some searching, i found SFML has a function generateMipmap(). Maybe you only need to call this when loading the texture, and then setSmooth() also enables trilinear filter (bilinear interpolation of texels AND interpolation of two mips). This might just work.
2. Use pixel shaders and implement it yourself. I saw SFML has support for shaders, but i'd try the first option first.
EDIT:
Notice generateMipmap() would generate all texture detail levels by halfing resolutions for each level. So no more need to draw down scaled textures manually, but also no option of smaller sqrt(2) steps. But due to inerpolation, smaller steps should not be needed.