[SDL] Colorkey and GL renderer

Mason Wheeler masonwheeler at yahoo.com
Wed Apr 14 20:51:38 PDT 2010


>>----- Original Message ----

>>From: Mason Wheeler <masonwheeler at yahoo.com>
>>Subject: [SDL] Colorkey and GL renderer
>>
>>As I mentioned this morning, when I use the GL renderer,
>>all my sprites are suddenly showing their colorkeys.  I've
>>managed to trace this down to a bug in my own code where
>>I was assigning the colorkey to the SDL_Surface *after*
>>calling SDL_CreateTextureFromSurface for some sprites.  This
>>was apparently working correctly under the software renderer
>>because the texture is based very closely on the underlying
>>surface, or something like that.
>>
>So... why doesn't SDL_CreateTextureFromSurface respect
>colorkeys when creating OpenGL textures?

OK, I found out why.  Hard to say whether or not this is by design,
though.

Inside SDL_CreateTextureFromSurface, if the surface you passed
in is not of the same pixel format as the texture you're creating, it
does the following:

        dst = SDL_ConvertSurface(surface, &dst_fmt, 0);
        if (dst) {
            SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch);
            SDL_FreeSurface(dst);
        }

Inside SDL_ConvertSurface, it carefully translates colorkey data into
per-pixel alpha.  It even says,
/* This is needed when converting for 3D texture upload */
Then it sets the blend mode to take advantage of the per-pixel alpha:
        SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);

...and then it returns, uploads the texture from the converted surface,
and throws the converted surface (and its blend mode) away.  All this
has been run in a conditional block, of course, so it won't necessarily
have executed.

After this, the following unconditional block of code runs. "surface" is
the original surface that was passed in.

    {
        Uint8 r, g, b, a;
        int blendMode;
        int scaleMode;

        SDL_GetSurfaceColorMod(surface, &r, &g, &b);
        SDL_SetTextureColorMod(texture, r, g, b);

        SDL_GetSurfaceAlphaMod(surface, &a);
        SDL_SetTextureAlphaMod(texture, a);

        SDL_GetSurfaceBlendMode(surface, &blendMode);
        SDL_SetTextureBlendMode(texture, blendMode);

        SDL_GetSurfaceScaleMode(surface, &scaleMode);
        SDL_SetTextureScaleMode(texture, scaleMode);
    }

It's using the original surface's blend mode, which was set (or not set)
as appropriate for the original surface's pixel format, instead of the
new one that was calculated inside SDL_ConvertSurface specifically
for this purpose.

This suggests an obvious workaround:  If you know about this, you can
make sure to set the blend mode that will be correct for the texture on
the original surface, and then it works.  But I don't really like that
solution.  It doesn't feel right.  It's requiring you to change one value to
something that may be inappropriate in its context, in order to achieve
a side effect in another context later on.

So there's the problem.  Does anyone have any ideas as to how to fix
it?




More information about the SDL mailing list