• Advertisement
Sign in to follow this  

PNGs with transparency in SDL.

This topic is 1653 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm drawing some PNGs with transparency in SDL (using SDL_BlitSurface(), which works just fine), but I'm having problems with changing the alpha values (to fade the image in/out).
 
I've tried doing something like this for all the pixels:
 
*pixel = SDL_MapRGBA(image->format, r, g, b, a);
 
Changing the value for "a" in the call to SDL_MapRGBA() works as expected on PNG files without transparency, but if the image has transparency, I instead end up with this:
 
lolwut.jpg
 
Here, "a" was set to 255. Changing the alpha still works (changes the opacity), but it's like all the pixels have been replaced by black ones, except for the 40 lines of pixels at the top, which are white.
 
Any idea what's going on?

Share this post


Link to post
Share on other sites
Advertisement
Maybe you should posts some more code.

Share this post


Link to post
Share on other sites
Alright.

I set the video mode like this:
screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);

Then I load an image using SDL_image:
SDL_Surface* temp  = IMG_Load(file.c_str());
SDL_Surface* image = SDL_DisplayFormatAlpha(temp);

Then I draw it to the screen:
SDL_BlitSurface(source, NULL, destination, NULL);

This works fine, transparency and everything. If I load a .png without transparency (or a .bmp or whatever) I can play around with the alpha bits and it works fine, but like I said, if I try that with a .png with transparency, everything gets screwed up.

Share this post


Link to post
Share on other sites
I could start throwing guesses at you but it would be easier if you posted the whole code if it's not too long.

Share this post


Link to post
Share on other sites
#include <sdl.h>
#include <sdl_image.h>

void applySurface(SDL_Surface* source, SDL_Surface* destination, int x, int y)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(source, NULL, destination, &offset);
}

SDL_Surface* loadImage(std::string file)
{
    SDL_Surface* temp = IMG_Load(file.c_str());
    SDL_Surface* image = SDL_DisplayFormatAlpha(temp);
    SDL_FreeSurface(temp);

    return(image);
}

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_Surface* screen(nullptr);
    screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);

    SDL_ShowCursor(SDL_DISABLE);

    SDL_Surface* bg = loadImage("data/bg.png");
    SDL_Surface* img1 = loadImage("data/img1.png");

    bool done(false);
    SDL_Event event;

    while(!done)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE))
            {
                done = true;
            }
        }

        applySurface(bg, screen, 0, 0);

        static Uint8 alpha(0);

        for(int y(0); y < img1->h; ++y)
        {
            for(int x(0); x < img1->w; ++x)
            {
                Uint32* pixel = (Uint32*)img1->pixels + (x + y * img1->w);

                Uint8 r;
                Uint8 g;
                Uint8 b;
                Uint8 a;

                SDL_GetRGBA(*pixel, img1->format, &r, &g, &b, &a);
                *pixel = SDL_MapRGBA(screen->format, r, g, b, alpha);
            }
        }

        ++alpha;

        applySurface(img1, screen, 0, 0);

        SDL_Flip(screen);
    }

    SDL_Quit();

    return(0);
}

I've tried several different ways of changing the alpha value, but all with the same result.

Share this post


Link to post
Share on other sites
You are passing the wrong format to SDL_MapRGBA. screen->format should be img1->format.

When you set the alpha value for each pixel you are ignoring the alpha values that the image was saved as so you will see pixels that are not supposed to be seen.

To not destroy the original alpha values you could draw to the screen surface directly. If you change alpha to a floating point type and slowly change it from 0 to 1 and do something like this inside the loop
*screenPixel = SDL_MapRGBA(screen->format, r, g, b, a * alpha);
I think you will get the effect you want.

Another way I thought would work was to set the per-surface alpha value using SDL_SetAlpha but that doesn't appear to work.

Share this post


Link to post
Share on other sites

To not destroy the original alpha values you could draw to the screen surface directly. If you change alpha to a floating point type and slowly change it from 0 to 1 and do something like this inside the loop

*screenPixel = SDL_MapRGBA(screen->format, r, g, b, a * alpha);
I think you will get the effect you want.

 


Yes, that works. Thank you. smile.png

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement