We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 3354

Summary: SDL_SetSurfaceBlendMode doesn't function on indexed-colour types
Product: SDL Reporter: mattreecebentley
Component: renderAssignee: Sam Lantinga <slouken>
Status: NEW --- QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: sylvain.becker
Version: 2.0.4   
Hardware: x86_64   
OS: Windows 7   
Attachments: test case
input image for the test case

Description mattreecebentley 2016-06-05 00:07:42 UTC
This problem occurs when you have a indexed-coloured 256-colour image with a transparency colour.

If you load the 256-colour PNG8 sprite tile into a RGBA surface, then copy each sprite from that tile to a different surface, even if you set SDL_SetSurfaceBlendMode(tiles_surface, SDL_BLENDMODE_NONE);
and
SDL_SetSurfaceBlendMode(copy_surface, SDL_BLENDMODE_NONE);

Every image after the first sprite will be overlaid on top of the original image.
In other words, it's not blanket-copying the entire sprite, it's copying all pixels *Except* the transparency colour.

So unless you use SDL_FillRect on the copy_surface, you end up with some overlaid sprites.
Comment 1 Sylvain 2016-06-05 11:13:45 UTC
I would suggest you to write a minimal test case.
Comment 2 mattreecebentley 2016-06-08 02:51:45 UTC
Haven't tested this, but should be close enough


// Create a 32-bit, alpha-channeled SDL_Surface in the appropriate endian order for the given platform:
inline SDL_Surface * create_surface(const int width, const int height)
{
	/* SDL interprets each pixel as a 32-bit number, so our masks must depend
	   on the endianness (byte order) of the machine */
	#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		return SDL_CreateRGBSurface(0, width, height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
	#else
		return SDL_CreateRGBSurface(0, width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
	#endif
}



std::vector <SDL_Texture *> frames;



int add_frames_from_tile(const char *image_filename, const unsigned int number_of_frames, const unsigned int frame_width)
{
	SDL_Surface *tiles_surface = IMG_Load(image_filename);

	const int total_width = static_cast<int>(number_of_frames * frame_width);

    // Create a frame surface for copying the individual frames to:
	SDL_Surface *frame_surface = create_surface(frame_width, tiles_surface->h);
        SDL_Texture *frame;

	SDL_SetSurfaceBlendMode(tiles_surface, SDL_BLENDMODE_NONE);
	SDL_SetSurfaceBlendMode(frame_surface, SDL_BLENDMODE_NONE);
	
	SDL_Rect source_rectangle = {0, 0, static_cast<int>(frame_width), tiles_surface->h};

	for (; source_rectangle.x != total_width; source_rectangle.x += frame_width)
	{
		// Sprite tiles will be overlaid without this line:
// SDL_FillRect(frame_surface, NULL, 0x000000);
                SDL_BlitSurface(tiles_surface, &source_rectangle, frame_surface, NULL);
                frame = SDL_CreateTextureFromSurface(Renderer, frame_surface);
		frames.push_back(frame);
	}
	
	SDL_FreeSurface(tiles_surface);
	SDL_FreeSurface(frame_surface);
	return 0;
}
Comment 3 Sylvain 2016-06-08 06:58:44 UTC
Created attachment 2484 [details]
test case
Comment 4 Sylvain 2016-06-08 06:59:17 UTC
Created attachment 2485 [details]
input image for the test case
Comment 5 Sylvain 2016-06-08 07:05:46 UTC
Here's a small test case, just loading and saving surface/image.

This issue happens because the *alpha* channel of a palette surface, is in fact a color key.

So you don't have to set the "blend mode" to none, but disable the color key, then re-enable it on the output.

Since color key is color, you need to retrieve it, convert it from the input pixel_format, to the output pixel_format, to set it back. ( 


Maybe SDL_SetSurfaceBlendMode could be translated as "disable colorkey" for palette surface ? but to re-activate it, you need the explicit value.