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 1181

Summary: SDL_RenderCopyFlipped
Product: SDL Reporter: Mason Wheeler <masonwheeler>
Component: videoAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: enhancement    
Priority: P2 CC: gabomdq
Version: HG 2.0   
Hardware: x86   
OS: Windows 7   

Description Mason Wheeler 2011-04-09 16:45:53 UTC
Adding support for a RenderCopy operation flipped around the X, Y or both axes.

Add the following two definitions to SDL_render.h:

typedef enum
{
	SDL_RENDERFLIP_HORIZ = 0x00000001,
	SDL_RENDERFLIP_VERT  = 0x00000002,
	SDL_RENDERFLIP_BOTH  = 0x00000003
} SDL_RenderFlip;

...

/**
 *  \brief Copy a portion of the texture to the current rendering target, flipped
 *         around one or both axes.
 *  
 *  \param texture The source texture.
 *  \param srcrect   A pointer to the source rectangle, or NULL for the entire 
 *                   texture.
 *  \param dstrect   A pointer to the destination rectangle, or NULL for the 
 *                   entire rendering target.
 *  \param axes      Which axes to flip the image around.
 *  
 *  \return 0 on success, or -1 on error
 */
extern DECLSPEC int SDLCALL SDL_RenderCopyFlipped(SDL_Renderer * renderer,
		  SDL_Texture * texture,
		  const SDL_Rect * srcrect,
		  const SDL_Rect * dstrect,
		  SDL_RenderFlip axes);



Then replace the implementation of SDL_RenderCopy with:

SDL_bool SDL_ClipRects(SDL_Renderer * renderer, SDL_Texture * texture,
               const SDL_Rect * srcrect, const SDL_Rect * dstrect,
			   SDL_Rect * real_srcrect, SDL_Rect * real_dstrect)
{
    real_srcrect->x = 0;
    real_srcrect->y = 0;
    real_srcrect->w = texture->w;
    real_srcrect->h = texture->h;
    if (srcrect) {
        if (!SDL_IntersectRect(srcrect, real_srcrect, real_srcrect)) {
			return SDL_FALSE;
        }
    }

    real_dstrect->x = 0;
    real_dstrect->y = 0;
    real_dstrect->w = renderer->viewport.w;
    real_dstrect->h = renderer->viewport.h;
    if (dstrect) {
        if (!SDL_IntersectRect(dstrect, real_dstrect, real_dstrect)) {
            return SDL_FALSE;
        }
        /* Clip srcrect by the same amount as dstrect was clipped */
        if (dstrect->w != real_dstrect->w) {
            int deltax = (real_dstrect->x - dstrect->x);
            int deltaw = (real_dstrect->w - dstrect->w);
            real_srcrect->x += (deltax * real_srcrect->w) / dstrect->w;
            real_srcrect->w += (deltaw * real_srcrect->w) / dstrect->w;
        }
        if (dstrect->h != real_dstrect->h) {
            int deltay = (real_dstrect->y - dstrect->y);
            int deltah = (real_dstrect->h - dstrect->h);
            real_srcrect->y += (deltay * real_srcrect->h) / dstrect->h;
            real_srcrect->h += (deltah * real_srcrect->h) / dstrect->h;
        }
    }
	return SDL_TRUE;
}

int
SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
               const SDL_Rect * srcrect, const SDL_Rect * dstrect)
{
    SDL_Rect real_srcrect;
    SDL_Rect real_dstrect;

    CHECK_RENDERER_MAGIC(renderer, -1);
    CHECK_TEXTURE_MAGIC(texture, -1);

    if (renderer != texture->renderer) {
        SDL_SetError("Texture was not created with this renderer");
        return -1;
    }

	if (!SDL_ClipRects(renderer, texture, srcrect, dstrect, &real_srcrect,
		          &real_dstrect))
	  return 0;

    if (texture->native) {
        texture = texture->native;
    }

    return renderer->RenderCopy(renderer, texture, &real_srcrect,
                                &real_dstrect);
}

int
SDL_RenderCopyFlipped(SDL_Renderer * renderer, SDL_Texture * texture,
                      const SDL_Rect * srcrect, const SDL_Rect * dstrect,
					  int axes)
{
    SDL_Rect real_srcrect;
    SDL_Rect real_dstrect;

    CHECK_RENDERER_MAGIC(renderer, -1);
    CHECK_TEXTURE_MAGIC(texture, -1);

    if (renderer != texture->renderer) {
        SDL_SetError("Texture was not created with this renderer");
        return -1;
    }

	if (!SDL_ClipRects(renderer, texture, srcrect, dstrect, &real_srcrect,
		          &real_dstrect))
	  return 0;

    if (texture->native) {
        texture = texture->native;
    }

	if (axes & SDL_RENDERFLIP_HORIZ)
	{
		real_dstrect.x += real_dstrect.w;
		real_dstrect.w *= -1;
	}

	if (axes & SDL_RENDERFLIP_VERT)
	{
		real_dstrect.y += real_dstrect.h;
		real_dstrect.h *= -1;
	}

    return renderer->RenderCopy(renderer, texture, &real_srcrect,
                                &real_dstrect);
}
Comment 1 Sam Lantinga 2012-01-07 00:59:00 UTC
Does this work for the software and Direct3D renderers as well?
Comment 2 Mason Wheeler 2012-01-08 05:31:23 UTC
(In reply to comment #1)
> Does this work for the software and Direct3D renderers as well?

It should work for Direct3D, for the same reason it works for OpenGL: all it does is reverse the vertices for the texture coordinates.  Not sure how it will work with non-accelerated renderers that don't use the same system.
Comment 3 Sam Lantinga 2012-01-08 10:48:53 UTC
I'm pretty sure the software renderer wouldn't do the right thing. ;)

There's very similar discussion in bug 1308, maybe you want to drop by and comment?
Comment 4 Gabriel Jacobo 2012-06-21 07:51:57 UTC
SDL_RenderCopyEx has landed.