diff options
author | 2016-11-16 16:26:13 +0100 | |
---|---|---|
committer | 2016-11-16 16:28:01 +0100 | |
commit | 47a05778bff9388fc6c479461dd3804c79d7b539 (patch) | |
tree | bb3d4dc8df676b8aa478339b3fd0cd305dc4ac4d /3rdparty/SDL2/src/render/software/SDL_rotate.c | |
parent | e61b392edfbfe5b9d70908c087632da915a3abd8 (diff) |
Updated SDL2 to 2.0.5 (nw)
Diffstat (limited to '3rdparty/SDL2/src/render/software/SDL_rotate.c')
-rw-r--r-- | 3rdparty/SDL2/src/render/software/SDL_rotate.c | 165 |
1 files changed, 124 insertions, 41 deletions
diff --git a/3rdparty/SDL2/src/render/software/SDL_rotate.c b/3rdparty/SDL2/src/render/software/SDL_rotate.c index 8d92758f875..0141d174d9f 100644 --- a/3rdparty/SDL2/src/render/software/SDL_rotate.c +++ b/3rdparty/SDL2/src/render/software/SDL_rotate.c @@ -110,31 +110,105 @@ SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle) { - double x, y, cx, cy, sx, sy; - double radangle; - int dstwidthhalf, dstheighthalf; + /* The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees */ + int angle90 = (int)(angle/90); + if(angle90 == angle/90) { /* if the angle is a multiple of 90 degrees */ + angle90 %= 4; + if(angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + if(angle90 & 1) { + *dstwidth = height; + *dstheight = width; + *cangle = 0; + *sangle = angle90 == 1 ? -1 : 1; /* reversed because our rotations are clockwise */ + } else { + *dstwidth = width; + *dstheight = height; + *cangle = angle90 == 0 ? 1 : -1; + *sangle = 0; + } + } else { + double x, y, cx, cy, sx, sy; + double radangle; + int dstwidthhalf, dstheighthalf; + /* + * Determine destination width and height by rotating a centered source box + */ + radangle = angle * (M_PI / -180.0); /* reverse the angle because our rotations are clockwise */ + *sangle = SDL_sin(radangle); + *cangle = SDL_cos(radangle); + x = (double)(width / 2); + y = (double)(height / 2); + cx = *cangle * x; + cy = *cangle * y; + sx = *sangle * x; + sy = *sangle * y; + + dstwidthhalf = MAX((int) + SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1); + dstheighthalf = MAX((int) + SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1); + *dstwidth = 2 * dstwidthhalf; + *dstheight = 2 * dstheighthalf; + } +} - /* - * Determine destination width and height by rotating a centered source box - */ - radangle = angle * (M_PI / 180.0); - *sangle = SDL_sin(radangle); - *cangle = SDL_cos(radangle); - x = (double)(width / 2); - y = (double)(height / 2); - cx = *cangle * x; - cy = *cangle * y; - sx = *sangle * x; - sy = *sangle * y; - - dstwidthhalf = MAX((int) - SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1); - dstheighthalf = MAX((int) - SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1); - *dstwidth = 2 * dstwidthhalf; - *dstheight = 2 * dstheighthalf; +/* Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees. */ +static void +computeSourceIncrements90(SDL_Surface * src, int bpp, int angle, int flipx, int flipy, + int *sincx, int *sincy, int *signx, int *signy) +{ + int pitch = flipy ? -src->pitch : src->pitch; + if (flipx) { + bpp = -bpp; + } + switch (angle) { /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + case 0: *sincx = bpp; *sincy = pitch - src->w * *sincx; *signx = *signy = 1; break; + case 1: *sincx = -pitch; *sincy = bpp - *sincx * src->h; *signx = 1; *signy = -1; break; + case 2: *sincx = -bpp; *sincy = -src->w * *sincx - pitch; *signx = *signy = -1; break; + case 3: default: *sincx = pitch; *sincy = -*sincx * src->h - bpp; *signx = -1; *signy = 1; break; + } + if (flipx) { + *signx = -*signx; + } + if (flipy) { + *signy = -*signy; + } +} + +/* Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees. */ +#define TRANSFORM_SURFACE_90(pixelType) \ + int dy, dincy = dst->pitch - dst->w*sizeof(pixelType), sincx, sincy, signx, signy; \ + Uint8 *sp = (Uint8*)src->pixels, *dp = (Uint8*)dst->pixels, *de; \ + \ + computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \ + if (signx < 0) sp += (src->w-1)*sizeof(pixelType); \ + if (signy < 0) sp += (src->h-1)*src->pitch; \ + \ + for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) { \ + if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use memcpy */ \ + SDL_memcpy(dp, sp, dst->w*sizeof(pixelType)); \ + sp += dst->w*sizeof(pixelType); \ + dp += dst->w*sizeof(pixelType); \ + } else { \ + for (de = dp + dst->w*sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) { \ + *(pixelType*)dp = *(pixelType*)sp; \ + } \ + } \ + } + +static void +transformSurfaceRGBA90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorRGBA); +} + +static void +transformSurfaceY90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorY); } +#undef TRANSFORM_SURFACE_90 /* ! \brief Internal 32 bit rotozoomer with optional anti-aliasing. @@ -341,9 +415,9 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, { SDL_Surface *rz_src; SDL_Surface *rz_dst; - int is32bit; + int is32bit, angle90; int i; - Uint8 r,g,b; + Uint8 r = 0, g = 0, b = 0; Uint32 colorkey = 0; int colorKeyAvailable = 0; double sangleinv, cangleinv; @@ -370,18 +444,13 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, */ rz_src = src; } else { - Uint32 format = SDL_MasksToPixelFormatEnum(32, -#if SDL_BYTEORDER == SDL_LIL_ENDIAN - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 -#else - 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff -#endif - ); - rz_src = SDL_ConvertSurfaceFormat(src, format, src->flags); + rz_src = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_ARGB32, src->flags); + if (rz_src == NULL) { + return NULL; + } is32bit = 1; } - /* Determine target size */ /* _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle); */ @@ -394,7 +463,6 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Alloc space to completely contain the rotated surface */ - rz_dst = NULL; if (is32bit) { /* * Target surface is 32bit with source RGBA/ABGR ordering @@ -430,6 +498,18 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, SDL_LockSurface(rz_src); } + /* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce + * the off-by-one problem in _transformSurfaceRGBA that expresses itself when the rotation is near + * multiples of 90 degrees. + */ + angle90 = (int)(angle/90); + if (angle90 == angle/90) { + angle90 %= 4; + if (angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + } else { + angle90 = -1; + } + /* * Check which kind of surface we have */ @@ -437,10 +517,11 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Call the 32bit transformation routine to do the rotation (using alpha) */ - _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery, - (int) (sangleinv), (int) (cangleinv), - flipx, flipy, - smooth); + if (angle90 >= 0) { + transformSurfaceRGBA90(rz_src, rz_dst, angle90, flipx, flipy); + } else { + _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery, (int) (sangleinv), (int) (cangleinv), flipx, flipy, smooth); + } /* * Turn on source-alpha support */ @@ -457,9 +538,11 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Call the 8bit transformation routine to do the rotation */ - transformSurfaceY(rz_src, rz_dst, centerx, centery, - (int) (sangleinv), (int) (cangleinv), - flipx, flipy); + if(angle90 >= 0) { + transformSurfaceY90(rz_src, rz_dst, angle90, flipx, flipy); + } else { + transformSurfaceY(rz_src, rz_dst, centerx, centery, (int)(sangleinv), (int)(cangleinv), flipx, flipy); + } SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src)); } |