Blitting 8-bit surfaces nukes the transparency


#1

Hi all, I have been meaning to make an account here for a while, but this problem is stumping me. My usual power-googling has returned nothing useful.

My pipeline ends in a texture rendered to the window with the format ARGB, but what I want to achieve is a palette swapping effect. To do this we begin with an INDEX8 surface, but I am trying to take advantage of SDL’s BlitSurface / BlitScaled functions to “guess” what the best colors are when converting from the original 8-bit surface to the destination 8-bit surface with the updated palette.

Simply changing the palette of the original with SDL_SetSurfacePalette produces a mangled image with poorly guessed mapping as is to be expected, but my attempted workaround involves taking advantage of the implicit conversion of SDL_BlitSurface/Scaled to make a “best guess” at the destination, and this works excellently for say, palettizing a window or a non-transparent image, as is discussed quite fully in this article. The problem is that doing so completely ignores the alpha channel, even if the palettes in both surfaces have a transparent color.

At first I thought it had something to do with the masks used in SDL_CreateRGBSurface. I’ve used the bigEndian define trick so that I can use RMASK, GMASK, BMASK, AMASK, but of course this doesn’t work at all with 8-bit surfaces (it fails to create the surface and complains about the pixel format). I understand the fundamental difference between an indexed image and an RGBA surface, but apart from my limited understanding of how these masks can actually be used to create a format (especially if you want something like ARGB and not RGBA), I have already ruled out this is not the problem.
The act of blitting itself ignores the transparency, and it doesn’t matter if I blit an eight bit surface to a thirty two bit surface, or an eight bit surface to an eight bit surface - it simply ignores the transparency and paints color from the new palette wherever the alpha channel should be.

I attempted to use CreateRGBSurfaceWithFormat instead, passing the INDEX8 pixel format, and it still does the same thing!

There has to be a way to do this. All I want is an effect similar to when you hit an enemy in Castlevania: Symphony of the Night, where an enemy adopts a new palette temporarily and cycles the position of the palette colors. I have gotten every step of this process to work but it’s not going to be much good if every time it happens, there is a huge block of color painting the back of the texture.

If anyone is able to clarify if this is possible, and if so, how, I would be extremely grateful!


#2

Bumping this with a tl;dr version.

I’m still having an issue blitting from a 256 color surface to an RGBA surface. I am trying to achieve a palette swapping effect and it works well in all respects except that it ignores transparency, and turns the ‘transparent’ color of the 8-bit surface into another color in the palette, generating an opaque block.

Is this a hard limitation of blitting 8-bit to 24/32-bit surfaces? If so, is there an efficient trick I can use to define pixels in the RGB target surface as being transparent?

This has put a real stopper in my development. I would love to know if anyone has a way to do this.


#3

Masking (not drawing a certain colour in paletted images) is a technique used by a lot of old games, but it doesn’t work well with modern hardware accelerated systems. On those systems you normally use alpha however then you lose the ability to do palette swapping. The only way around it I know of is using shaders. You can activate a shader that skips pixels that match certain values when drawing 8 bit images. Just use a slight tolerance so that different systems with different floating point accuracy all work.