Rendering a tilemap with SDL_RenderSetLogicalSize

Hello !

I’m working on a project where I’m trying to render a tilemap with a texture atlas. Until now, it works good but I just enable full screen window, and I want my tilemap fill the maximum of the window by zooming in. Instead of manually compute positions and sizes of images with a zoom value, I have found the function SDL_RenderSetLogicalSize that can do all this for me. My code is now like this :

void Window::CreateWindow()
{
    m_window = SDL_CreateWindow(m_title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, 
    
    m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);

    SDL_RenderSetLogicalSize(m_renderer, m_width, m_height);
}

I can just now specify the dimension of the grid of tiles I want, and it’s working :

Window::Window(const std::string& title, const int grid_width, const int grid_height, const SDL_Color bg_color) :
{
    m_width = grid_width*32; // 32 is my tile size
    m_height = grid_height*32;
    InitSdl();
    CreateWindow();
}

Ok great, but now I have sometimes strange vertical lines that appears between two tiles :

I’m almost sure my problems is related to conversion from float to int, because of the scale factor. Using this line resolve the problem (but the scaling is not enough to fill the window, so I can’t avoid using a float I guess).

SDL_RenderSetIntegerScale(renderer, SDL_TRUE);

Is it a common problem ? I think I’m doing something wrong…

You can look the code here : Atlacp/src at main · Loick01/Atlacp · GitHub

Thanks

I’m not an expert on that issue but I think it has to do with how SDL is sampling from the texture and that the nearest pixels are bleeding through.
I have seen people solve this by having 1-2 transparent pixels between each column/row of tiles in the tileset texture.
I checked your tileset textures and the tiles in those are tightly packed next to each other, so you can try adding some whitespace between them. It should solve the issue you’re having.

I’m pretty sure the issue has to do with the default scale mode algorithm. I think I solved it in my program by using SDL_SetTextureScaleMode to set the texture’s mode to nearest neighbor SDL_ScaleModeNearest instead of the default of linear.
It has been years so I don’t have the source files anymore, it’s possible I have those two modes reversed.

I tried with each of the scale ScaleMode, but none seems to solve the problem :

You’re right, it seems to be texture bleeding, the vertical lines correspond to the neighboring tile in the tileset :

I tried to add padding to my tileset, and I have these holes between my tile, through which I can the background color (blue in the screen below) :

My understanding of this problem is that it has to do with using non-integer scales and coordinates which leads to “rounding errors”.

What you could do is render everything to an intermediate texture using an integer scaling factor and then render that to the screen at the size that you want.

I assume you use “nearest” interpolation when rendering to the intermediate texture, otherwise there are other issues with bleeding and such that you need to consider.

You could make the intermediate texture as small as possible and render without scaling (scaling factor: 1). This makes sense if you use “nearest” interpolation when drawing the intermediate texture onto the screen …

… but for best quality (assuming a scaling factor > 1) you might want make the intermediate texture slightly larger than (or same size as) the window and use “linear” or “best” instead. This prevents the problem of having pixel rows and pixel columns with different widths (see irregular grass and waves above) while still minimizing blur.

Exactly.

Other workaround include splitting your tilemap to individual `SDL_Texture`s to avoid “grabbing” neighboring pixels when doing non-integer scaling. You can avoid rendering to intermediate texture if you go this way.

Wouldn’t that still lead to gaps between some tiles (unless you make the tiles slightly larger so that they overlap slightly)?

Should not, with SDL_RenderSetLogicalSize I see no gaps