Page 1 of 1

I hate myself sometimes (SDL, Transparency)

Posted: Sun Dec 09, 2012 7:18 pm
by DistortedLance
I was easily able to quickly come up with something that would give me an entirely transparent SDL_Surface* that would theoretically just be something used to combine other surfaces while maintaining their transparencies. I also wanted to generalize my drawing so that every surface would act as if I were laying overhead sheets on top of each other - that is, you can see through all the way to the bottom sheet where there isn't something solid/non-transparent.
//To create a blank texture of the given size
uint32_t BlankTexture(int width, int height)
{
     /*...*/
     SDL_Surface* surface = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height, 32, 
                            0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
     SDL_FillRect(surface, 0, SDL_MapRGBA(surface->format, 0, 0, 0, 0);
     SDL_SetAlpha(surface, SDL_SRCALPHA, 0);
     /*...*/
}
And, of course, I needed to create something that would let me actually clip a texture, otherwise there would be no real use for obtaining a new blank surface. It automatically generates a new blank surface, so I should probably change things around so I can just directly merge portions of textures with others without the middle step. Oh well.
//To clip a texture
uint32_t ClipTexture(uint32_t textureid, int x, int y, int w, int h)
{
     /*...*/
     Rect clip = {x, y, w, h};

     SDL_Surface* source = textures[textureid].surface;
     SDL_SetAlpha(source, 0, 0);

     SDL_Surface* clipped = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, 32,
                            0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
     SDL_FillRect(clipped, 0, SDL_MapRGBA(clipped->format, 0, 0, 0, 0));
     SDL_SetAlpha(clipped, SDL_SRCALPHA, 0);

     SDL_BlitSurface(source, &clip, clipped, 0);
     SDL_SetAlpha(source, SDL_SRCALPHA, 0);
     /*...*/
}
Things all went downhill when I tried to re-implement what I thought would simply be the same functionality in my generic DrawTexture() function - I would just need to copy the same SDL_SetAlpha() calls, ignoring the stuff in the middle that automatically generated a new SDL_Surface*, right?

Weeeeell, I'm really terrible at this alpha blending stuff, so I didn't actually do it right for the longest time. It turns out I don't want to be setting the source to be opaque if I'm drawing it to the screen - only if I'm drawing to another surface.
//Draws a texture onto either a texture or the screen
void DrawTexture(uint32_t textureid, int x, int y, Rect* srcclip, uint32_t desttexture = 0)
{
     SDL_Surface* destsurface = 0;
     if(!dest) destsurface = screen->GetSurface();
     else
     {
          destsurface = textures[desttexture].surface;
          SDL_SetAlpha(textures[textureid].surface, 0, 0);  //Only SetAlpha if drawing to another texture
     }    //^This call used to be outside the conditional right before the SDL_BlitSurface() call

     Rect offset = {x, y, 1337, 9001};

     SDL_SetAlpha(destsurface, SDL_SRCALPHA, 0);
     SDL_BlitSurface(textures[textureid].surface, clip, destsurface, &offset);
     SDL_SetAlpha(textures[textureid].surface, SDL_SRCALPHA, 0);   //Aaaaaand reset when you're done
}
I'd been staring at my code wondering why I was just getting white boxes every time I tried drawing things onto other textures; I was especially confused because ClipTexture() worked perfectly fine, and I thought I was doing the same exact thing. Then I tried this, and it worked. At least, I'm pretty sure it works. I haven't tested every scenario, but it certainly does what it wasn't doing before. If you see anything screwed up, I would really appreciate it being fixed ^_^

Lesson learned? Read documentation.