SDL3 custom bitmap font transparency

Hello!

I’m trying to load a bitmap font from a PGM grayscale file, which was generated by my own tool using stb_truetype. The file is good because I can preview it on my file explorer. Now Im trying to load this as a texture with the SDL3 Renderer API

auto* atlas_surface = SDL_CreateSurface(atlas_w, atlas_h, SDL_PIXELFORMAT_INDEX8);
SDL_LockSurface(atlas_surface);

auto* atlas_pixels = reinterpret_cast<char*>(atlas_surface->pixels);

// Read every char from the PGM file
for (std::size_t i{}; i < atlas_size; ++i)
{
    char in{};
    pgm_stream.get(in);
    atlas_pixels[i] = in;
}

SDL_UnlockSurface(atlas_surface);

When I want to make a texture from this surface, SDL tells me I need to create a palette first. Ok

std::vector<SDL_Color> grayscale(256);

for (std::size_t i{}; i < grayscale.size(); ++i)
{
    auto val = static_cast<std::uint8_t>(i);
    grayscale[i] = { val, val, val, 255u };
}

auto* palette = SDL_CreatePalette(grayscale.size());
SDL_SetPaletteColors(palette, grayscale.data(), 0, grayscale.size());
SDL_SetSurfacePalette(atlas_surface, palette);
SDL_DestroyPalette(palette);

Now the texture can be created

auto* atlas_texture = SDL_CreateTextureFromSurface(app.m_renderer, atlas_surface);
SDL_DestroySurface(atlas_surface);

The question is: how can I give the text transparent background and a solid color? I’ve tried these:

SDL_SetTextureBlendMode(atlas_texture, SDL_BLENDMODE_ADD);
SDL_SetTextureColorMod(atlas_texture, 255u, 255u, 1u);

// Rendering code (in the main loop)
SDL_RenderTexture(app.m_renderer, atlas_texture, &glyph_rect_src, &glyph_rect_dst);

Using SDL_BLENDMODE_NONE / SDL_BLENDMODE_BLEND

Using SDL_BLENDMODE_ADD but NO texture color mod. Perfect for white text

Using SDL_BLENDMODE_ADD + texture mod color

I’m used to do this with SDL + OpenGL in a shader, and it works. But now I’m using SDL3 Renderer. Do I need to convert the texture to RGBA for this to work as expected? or am I missing something?

Ok, I forgot to set the transparent color before converting the surface into a texture

SDL_SetSurfaceColorKey(atlas_surface, true, 0U);

Transparency and color are working fine. But now you can clearly see a black line of pixels around the text. How can I fix this?

post01

A color key is only useful if you have one single value that is fully transparent while the rest is not transparent at all. In your case it looks like you want to have many values with different level of transparency which is what the alpha channel is for.

I suspect you want

grayscale[i] = { 255u, 255u, 255u, val };

instead of

grayscale[i] = { val, val, val, 255u };

This would mean that it’s no longer “grayscale”, but rather white with different levels of transparency, but I think this is what you want.

2 Likes

Indeed, it looks perfect now. Thank you, Peter!