Search code examples
c++sdl-2alpha

Textures created with SDL_CreateTexture don't appear to support transparency


I want to copy multiple surfaces (created with TTF_*) to a single texture, and I can't seem to get that resulting texture to render onto the window with transparency handled correctly.

static void example(void) {
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
    TTF_Init();

    SDL_Window*   w = SDL_CreateWindow("", 0, 0, 200, 200, 0);
    SDL_Renderer* r = SDL_CreateRenderer(w, -1, 0);
    TTF_Font*     f = TTF_OpenFont(MY_FONT, 100);
    SDL_Color     c = {.r = 0, .g = 255, .b = 0, .a = 255};
    SDL_Surface*  s = TTF_RenderGlyph32_Blended(f, 'A', c);
    SDL_Texture*  t = SDL_CreateTextureFromSurface(r, s);

#ifdef RENDER_COPY
    SDL_Texture* t2 = SDL_CreateTexture(
      r,
      SDL_PIXELFORMAT_ARGB8888,
      SDL_TEXTUREACCESS_TARGET,
      s->w,
      s->h);

    SDL_SetRenderTarget(r, t2);
    SDL_RenderCopy(r, t, NULL, NULL);
    SDL_SetRenderTarget(r, NULL);

    t = t2;
#endif

#ifdef RENDER_MEMCPY
    SDL_Texture* t2 = SDL_CreateTexture(
      r,
      SDL_PIXELFORMAT_ARGB8888,
      SDL_TEXTUREACCESS_STREAMING,
      s->w,
      s->h);

    SDL_Surface* s2;
    sdl_try(SDL_LockTextureToSurface(t2, NULL, &s2));
    memcpy(s2->pixels, s->pixels, s->w * s->h * sizeof(SDL_Color));
    SDL_UnlockTexture(t2);

    t = t2;
#endif

#ifdef RENDER_BLEND
    SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND);
#endif

    SDL_SetRenderDrawColor(r, 255, 255, 255, 255);
    SDL_RenderClear(r);

    SDL_Rect rect = {.x = 0, .y = 0};
    SDL_QueryTexture(t, NULL, NULL, &rect.w, &rect.h);
    SDL_RenderCopy(r, t, &rect, &rect);

    SDL_RenderPresent(r);

    SDL_Event event;
    do { SDL_WaitEvent(&event); } while (event.type != SDL_KEYDOWN);
}

Without RENDER_COPY, I get a texture (created via SDL_CreateTextureFromSurface) that blends correctly onto a render target (this is what I want, but with multiple surfaces combined into one texture.)

texture from SDL_CreateTextureFromSurface

With RENDER_COPY (i.e. a second texture is created and then copied onto) the background of the texture is black. This is a contrived example since there is only one surface being copied, but I want to copy multiple surfaces to t2.)

texture created and then copied into from original texture

With RENDER_BLEND, the black is mostly gone but it's as if the texture was blended onto a black background.

texture created and then copied into, but with SDL_BLENDMODE_BLEND

Is there a way to create a texture that can be set completely transparent instead of a solid color? I've also tried to set the pixels directly (RENDER_MEMCPY) but that just ends up being a solid color as it appears the alpha in each pixel is ignored:

texture copied manually

SDL version is 2.0.20.


Solution

  • Figured it out. When doing SDL_RenderCopy from the first texture to the second, the blend mode on the first texture should be set to none:

     SDL_SetTextureBlendMode(t, SDL_BLENDMODE_NONE);
    

    Now when the second texture is copied (with SDL_BLENDMODE_BLEND) the edges don't have the black artifacts.