15

How using SDL_CreateTexture create transparent texture? By default I'm creating texure with such code:

SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);

And then I'm paining on this texture with redirecting output to this texture. However at the end what I want to render this on screen any (nonupdated) pixel is black.

I have tried different ways with using of:

 SDL_RenderClear(_Renderer);

or even with drawing and on created texture with painting transparent Rect with different blending modes but all I had as a result was still nontransparent texture :/

   SDL_Rect rect={0,0,Width,Height};
   SDL_SetRenderDrawBlendMode(_Renderer,SDL_BLENDMODE_BLEND);
   SDL_SetRenderDrawColor(_Renderer,255,255,255,0);
   SDL_RenderFillRect(_Renderer,&rect);

To be more specific:

    //this->texDefault.get()->get() = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET, x, y);
    SDL_SetRenderTarget(_Renderer.get()->get(), this->texDefault.get()->get());
    SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
    SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,0,255,0);
    SDL_RenderClear(this->_Renderer.get()->get());
    //SDL_Rect rect={0,0,Width,Height};
    //SDL_SetRenderDrawColor(this->_Renderer.get()->get(),255,255,255,255);
    //SDL_RenderFillRect(this->_Renderer.get()->get(),&rect);
    //SDL_RenderClear(this->_Renderer.get()->get());
    //SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_NONE);
    SDL_SetRenderTarget(_Renderer.get()->get(), NULL);
    SDL_Rect rect= {relTop+Top,relLeft+Left,Height,Width};
    SDL_SetRenderDrawBlendMode(this->_Renderer.get()->get(),SDL_BLENDMODE_BLEND);
    SDL_RenderCopy(this->_Renderer.get()->get(), this->texDefault->get(), NULL, &rect);

This code is always producing nontransparent Texture independenty what i will set for blending and alpha

The result is :

enter image description here

Maybe there is some other simple method to create transparent empty texture in SDL2 something like x/y-sized fully transparent png but loading having such image in file is little bit pointless :/

mpromonet
  • 11,326
  • 43
  • 62
  • 91
Lemonek
  • 175
  • 1
  • 1
  • 10
  • You can use SDL_Surface and SDL_SetAlpha() for transparency(or semi-transparency). [link](www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsetalpha.html) – Mahesh Bansod Jun 16 '14 at 15:01
  • What's this got to do with OpenGL? It might be layered on top of OpenGL, but there is nothing here that can be answered using anything related to OpenGL :-\ – Andon M. Coleman Jun 17 '14 at 01:27

2 Answers2

16
  • First, you need to set renderer blend mode: SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);.
  • Second, you need to set texture blend mode: SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);.

Here is working example I created. You can use keys A and S to change alpha channel of third texture, which is invisible at start of the application.

#include <iostream>
#include <vector>
#include <SDL.h>

void fillTexture(SDL_Renderer *renderer, SDL_Texture *texture, int r, int g, int b, int a)
{
    SDL_SetRenderTarget(renderer, texture);
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
    SDL_SetRenderDrawColor(renderer, r, g, b, a);
    SDL_RenderFillRect(renderer, NULL);
}

void prepareForRendering(SDL_Renderer *renderer)
{
    SDL_SetRenderTarget(renderer, NULL);
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
}

void checkSdlError()
{
    const char *sdlError = SDL_GetError();
    if(sdlError && *sdlError)
    {
        ::std::cout << "SDL ERROR: " << sdlError << ::std::endl;
    }
}

int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_HAPTIC);

    SDL_Window *window = SDL_CreateWindow("SDL test",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        320, 240,
        SDL_WINDOW_OPENGL);
    SDL_Renderer *renderer = SDL_CreateRenderer(
        window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);

    const int width = 50;
    const int height = 50;

    ::std::vector<SDL_Texture*> textures;

    SDL_Texture *redTexture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
    textures.push_back(redTexture);

    SDL_Texture *greenTexture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
    textures.push_back(greenTexture);

    SDL_Texture *purpleTexture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
    textures.push_back(purpleTexture);

    // Here is setting the blend mode for each and every used texture:
    for(int i = 0; i < textures.size(); ++i)
    {
        SDL_SetTextureBlendMode(textures[i], SDL_BLENDMODE_BLEND);
    }

    int purpleAlpha = 0;

    fillTexture(renderer, redTexture, 255, 0, 0, 255);
    fillTexture(renderer, greenTexture, 0, 255, 0, 128);
    fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);

    prepareForRendering(renderer);

    bool running = true;
    while(running)
    {
        SDL_Rect rect;
        rect.w = width;
        rect.h = height;

        SDL_RenderClear(renderer);

        rect.x = 50;
        rect.y = 50;
        SDL_RenderCopy(renderer, redTexture, NULL, &rect);

        rect.x = 75;
        rect.y = 70;
        SDL_RenderCopy(renderer, greenTexture, NULL, &rect);

        rect.x = 75;
        rect.y = 30;
        SDL_RenderCopy(renderer, purpleTexture, NULL, &rect);

        SDL_RenderPresent(renderer);

        // Process events
        {
            SDL_Event event;
            while(SDL_PollEvent(&event) == 1)
            {
                if(event.type == SDL_QUIT)
                {
                    running = false;
                }
                else if(event.type == SDL_KEYDOWN)
                {
                    switch(event.key.keysym.sym)
                    {
                    case SDLK_ESCAPE:
                        running = false;
                        break;
                    case SDLK_a:
                        purpleAlpha = ::std::max(purpleAlpha - 32, 0);
                        fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
                        prepareForRendering(renderer);
                        ::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
                        break;
                    case SDLK_s:
                        purpleAlpha = ::std::min(purpleAlpha + 32, 255);
                        fillTexture(renderer, purpleTexture, 255, 0, 255, purpleAlpha);
                        prepareForRendering(renderer);
                        ::std::cout << "Alpha: " << purpleAlpha << ::std::endl;
                        break;
                    }
                }
            }

            checkSdlError();
        }
    }

    for(int i = 0; i < textures.size(); ++i)
    {
        SDL_DestroyTexture(textures[i]);
    }
    textures.clear();

    SDL_DestroyRenderer(renderer);
    renderer = NULL;
    SDL_DestroyWindow(window);
    window = NULL;

    SDL_Quit();

    checkSdlError();

    return 0;
}

EDIT: Completely rewritten the answer, original one basically contained blend mode of renderer.

  • Nope :/ Mixing with color and alpha and blending always is resulting in color (depeding on used values) non but nontransparent texture – Lemonek Jun 16 '14 at 11:55
  • @Lemonek What happens (changes) with the `SDL_BLENDMODE_NONE`? Best thing would be screenshots with your original (`SDL_BLENDMODE_BLEND`) and with updated version. (Regrettably, I cannot currently experiment with SDL...) –  Jun 16 '14 at 12:18
  • 1
    @Lemonek I finally had little time to look into this and I found out that you need to set blend mode not only for renderer, but also for texture. I changed this answer accordingly and added working example. –  Jun 17 '14 at 08:18
  • Nice - it started to work - I didnt knew that i need to additionally set blending mode texture, independently from renderer blending mode. This is working for all textures created with flag SDL_TEXTUREACCESS_TARGET, is there some easy way to switch between this flag and SDL_TEXTUREACCESS_STREAMING??? To have ability to render to texture and then access this with SDL_TextureLock?? BTW - Thank you for support – Lemonek Jun 17 '14 at 08:59
  • @Lemonek Heh, I didn't know it either until I wrote that code, it didn't work and I noticed it in documentation - http://wiki.libsdl.org/FrontPage ... About switching access flag - first, I would like to again point out that my experience with SDL2 was zero, currently you can add the program above. Anyway, from documentation and Google, I think it's not possible. However, there is multiple ways how to achieve what you want; –  Jun 17 '14 at 09:42
  • @Lemonek First I wanted to suggest to use `SDL_CreateTextureFromSurface`, but I found out you cannot set access flag (that's stupid!). Anyway, first solution would be to use `SDL_TextureLock` to write data you want so it would be created as _STREAM at the first place. Other solution would be to use renderer directly and then `SDL_RenderReadPixels` to read data and then clear it and render what you want to display. Other version of this solution would be to create two renderers for window - first one would be hidden and you could use it for off-screen rendering (I would suggest to use previous) –  Jun 17 '14 at 09:50
  • @Lemonek Next possibility is to use `SDL_UpdateTexture` - it allows you to set pixels for all texture types. Another solution is not nice in terms of learning. Use OpenGL directly - it gives you more freedom, but it requires low-level access. –  Jun 17 '14 at 10:01
  • @Leathnes - well I didnt get lucky with SDL_RenderReadPixels (while renderer is rediceted to texture) and SDL_UpdateTexture - I'm not getting any SDL Errors but nothing is changed at the end :/ – Lemonek Jun 17 '14 at 12:03
  • @Lemonek I'm afraid I won't have the time to look more deeply into this anytime soon. So I would recommend asking on SDL forums (as you can see, there on stackoverflow aren't many SDL-experienced people)... Btw. even though I have no idea why `SDL_RenderReadPixels` shouldn't work during renderer redirected to a texture, I meant it to use it without the redirection. –  Jun 17 '14 at 13:01
  • Stumbled across this while using render targets for texture batching. I did not realize that `SDL_RenderClear` does **not** respect the render draw color's *alpha channel* while `SDL_FillRect` does (respective of the render draw blend mode, of course). My batched textures kept getting flattened, but now I can batch textures together on the fly with full alpha support. I'm using this for custom text rendering. – monkey0506 Jun 04 '20 at 21:58
0

You can render a semi-transparent rectangle on top of the texture, as @user1476710 suggested. However a more straightforward way is to just enable alpha blending for the texture itself, set texture alpha to whatever you want, then proceed with rendering. For example to render a semi-transparent texture with alpha=127:

...
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
texture_rect=(SDL_Rect){...};
...
SDL_SetTextureAlphaMod(texture, 127);
SDL_RenderCopy(renderer, texture, NULL, texture_rect);
SDL_RenderPresent(renderer);
...
Pap
  • 448
  • 1
  • 10
  • 15