src/render/software/SDL_rotate.c
author Sam Lantinga
Fri, 07 Oct 2016 18:00:30 -0700
changeset 10489 1e1ce9f6d215
parent 10485 63cc8dcc2ef9
child 10512 c6d79a1bec47
permissions -rw-r--r--
Fixed bug 3029 - software renderer cuts off edges when rotate-blitting with a multiple of 90 degrees

Adam M.

When doing a rotated texture copy with the software renderer, where the angle is a multiple of 90 degrees, one or two edges of the image get cut off. This is because of the following line in sw_rotate.c:
if ((unsigned)dx < (unsigned)sw && (unsigned)dy < (unsigned)sh) {
which is effectively saying:
if (dx >= 0 && dx < src->w-1 && dy >= 0 && dy < src->h-1) {

As a result, it doesn't process pixels in the right column or bottom row of the source image (except when they're accessed as part of the bilinear filtering for nearby pixels). This causes it to look like the edges are cut off, and it's especially obvious with an exact multiple of 90 degrees.
gabomdq@6320
     1
/*
gabomdq@6320
     2
gabomdq@6320
     3
SDL_rotate.c: rotates 32bit or 8bit surfaces
gabomdq@6320
     4
gabomdq@6320
     5
Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows:
gabomdq@6320
     6
gabomdq@6320
     7
Copyright (C) 2001-2011  Andreas Schiffler
gabomdq@6320
     8
gabomdq@6320
     9
This software is provided 'as-is', without any express or implied
gabomdq@6320
    10
warranty. In no event will the authors be held liable for any damages
gabomdq@6320
    11
arising from the use of this software.
gabomdq@6320
    12
gabomdq@6320
    13
Permission is granted to anyone to use this software for any purpose,
gabomdq@6320
    14
including commercial applications, and to alter it and redistribute it
gabomdq@6320
    15
freely, subject to the following restrictions:
gabomdq@6320
    16
gabomdq@6320
    17
   1. The origin of this software must not be misrepresented; you must not
gabomdq@6320
    18
   claim that you wrote the original software. If you use this software
gabomdq@6320
    19
   in a product, an acknowledgment in the product documentation would be
gabomdq@6320
    20
   appreciated but is not required.
gabomdq@6320
    21
gabomdq@6320
    22
   2. Altered source versions must be plainly marked as such, and must not be
gabomdq@6320
    23
   misrepresented as being the original software.
gabomdq@6320
    24
gabomdq@6320
    25
   3. This notice may not be removed or altered from any source
gabomdq@6320
    26
   distribution.
gabomdq@6320
    27
gabomdq@6320
    28
Andreas Schiffler -- aschiffler at ferzkopp dot net
gabomdq@6320
    29
gabomdq@6320
    30
*/
icculus@8093
    31
#include "../../SDL_internal.h"
gabomdq@6320
    32
slouken@7828
    33
#if defined(__WIN32__)
slouken@7828
    34
#include "../../core/windows/SDL_windows.h"
gabomdq@6320
    35
#endif
gabomdq@6320
    36
gabomdq@6320
    37
#include <stdlib.h>
gabomdq@6320
    38
#include <string.h>
gabomdq@6320
    39
gabomdq@6320
    40
#include "SDL.h"
gabomdq@6320
    41
#include "SDL_rotate.h"
gabomdq@6320
    42
gabomdq@6320
    43
/* ---- Internally used structures */
gabomdq@6320
    44
gabomdq@7678
    45
/* !
gabomdq@6320
    46
\brief A 32 bit RGBA pixel.
gabomdq@6320
    47
*/
gabomdq@6320
    48
typedef struct tColorRGBA {
gabomdq@6320
    49
    Uint8 r;
gabomdq@6320
    50
    Uint8 g;
gabomdq@6320
    51
    Uint8 b;
gabomdq@6320
    52
    Uint8 a;
gabomdq@6320
    53
} tColorRGBA;
gabomdq@6320
    54
gabomdq@7678
    55
/* !
gabomdq@6320
    56
\brief A 8bit Y/palette pixel.
gabomdq@6320
    57
*/
gabomdq@6320
    58
typedef struct tColorY {
gabomdq@6320
    59
    Uint8 y;
gabomdq@6320
    60
} tColorY;
gabomdq@6320
    61
gabomdq@7678
    62
/* !
gabomdq@6320
    63
\brief Returns maximum of two numbers a and b.
gabomdq@6320
    64
*/
gabomdq@6320
    65
#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
gabomdq@6320
    66
gabomdq@7678
    67
/* !
gabomdq@6320
    68
\brief Number of guard rows added to destination surfaces.
gabomdq@6320
    69
gabomdq@6320
    70
This is a simple but effective workaround for observed issues.
gabomdq@6320
    71
These rows allocate extra memory and are then hidden from the surface.
gabomdq@6320
    72
Rows are added to the end of destination surfaces when they are allocated.
gabomdq@6320
    73
This catches any potential overflows which seem to happen with
gabomdq@6320
    74
just the right src image dimensions and scale/rotation and can lead
gabomdq@6320
    75
to a situation where the program can segfault.
gabomdq@6320
    76
*/
gabomdq@6320
    77
#define GUARD_ROWS (2)
gabomdq@6320
    78
gabomdq@7678
    79
/* !
gabomdq@6320
    80
\brief Lower limit of absolute zoom factor or rotation degrees.
gabomdq@6320
    81
*/
gabomdq@6320
    82
#define VALUE_LIMIT 0.001
gabomdq@6320
    83
gabomdq@7678
    84
/* !
gabomdq@6320
    85
\brief Returns colorkey info for a surface
gabomdq@6320
    86
*/
slouken@7859
    87
static Uint32
slouken@7859
    88
_colorkey(SDL_Surface *src)
gabomdq@6320
    89
{
gabomdq@6320
    90
    Uint32 key = 0;
gabomdq@6320
    91
    SDL_GetColorKey(src, &key);
gabomdq@6320
    92
    return key;
gabomdq@6320
    93
}
gabomdq@6320
    94
gabomdq@6320
    95
gabomdq@7678
    96
/* !
gabomdq@6320
    97
\brief Internal target surface sizing function for rotations with trig result return.
gabomdq@6320
    98
gabomdq@6320
    99
\param width The source surface width.
gabomdq@6320
   100
\param height The source surface height.
gabomdq@6320
   101
\param angle The angle to rotate in degrees.
gabomdq@6320
   102
\param dstwidth The calculated width of the destination surface.
gabomdq@6320
   103
\param dstheight The calculated height of the destination surface.
gabomdq@6320
   104
\param cangle The sine of the angle
gabomdq@6320
   105
\param sangle The cosine of the angle
gabomdq@6320
   106
gabomdq@6320
   107
*/
slouken@7859
   108
void
slouken@7859
   109
SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle,
slouken@7859
   110
                               int *dstwidth, int *dstheight,
slouken@7859
   111
                               double *cangle, double *sangle)
gabomdq@6320
   112
{
slouken@10489
   113
    /* The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees */
slouken@10489
   114
    int angle90 = (int)(angle/90);
slouken@10489
   115
    if(angle90 == angle/90) { /* if the angle is a multiple of 90 degrees */
slouken@10489
   116
        angle90 %= 4;
slouken@10489
   117
        if(angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */
slouken@10489
   118
        if(angle90 & 1) {
slouken@10489
   119
            *dstwidth  = height;
slouken@10489
   120
            *dstheight = width;
slouken@10489
   121
            *cangle = 0;
slouken@10489
   122
            *sangle = angle90 == 1 ? -1 : 1; /* reversed because our rotations are clockwise */
slouken@10489
   123
        } else {
slouken@10489
   124
            *dstwidth  = width;
slouken@10489
   125
            *dstheight = height;
slouken@10489
   126
            *cangle = angle90 == 0 ? 1 : -1;
slouken@10489
   127
            *sangle = 0;
slouken@10489
   128
        }
slouken@10489
   129
    } else {
slouken@10489
   130
        double x, y, cx, cy, sx, sy;
slouken@10489
   131
        double radangle;
slouken@10489
   132
        int dstwidthhalf, dstheighthalf;
slouken@10489
   133
        /*
slouken@10489
   134
        * Determine destination width and height by rotating a centered source box
slouken@10489
   135
        */
slouken@10489
   136
        radangle = angle * (M_PI / -180.0); /* reverse the angle because our rotations are clockwise */
slouken@10489
   137
        *sangle = SDL_sin(radangle);
slouken@10489
   138
        *cangle = SDL_cos(radangle);
slouken@10489
   139
        x = (double)(width / 2);
slouken@10489
   140
        y = (double)(height / 2);
slouken@10489
   141
        cx = *cangle * x;
slouken@10489
   142
        cy = *cangle * y;
slouken@10489
   143
        sx = *sangle * x;
slouken@10489
   144
        sy = *sangle * y;
slouken@10489
   145
        
slouken@10489
   146
        dstwidthhalf = MAX((int)
slouken@10489
   147
            SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1);
slouken@10489
   148
        dstheighthalf = MAX((int)
slouken@10489
   149
            SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1);
slouken@10489
   150
        *dstwidth = 2 * dstwidthhalf;
slouken@10489
   151
        *dstheight = 2 * dstheighthalf;
slouken@10489
   152
    }
gabomdq@6320
   153
}
gabomdq@6320
   154
slouken@10489
   155
/* Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees. */
slouken@10489
   156
static void
slouken@10489
   157
computeSourceIncrements90(SDL_Surface * src, int bpp, int angle, int flipx, int flipy,
slouken@10489
   158
                          int *sincx, int *sincy, int *signx, int *signy)
slouken@10489
   159
{
slouken@10489
   160
    int pitch = flipy ? -src->pitch : src->pitch;
slouken@10489
   161
    if (flipx) {
slouken@10489
   162
        bpp = -bpp;
slouken@10489
   163
    }
slouken@10489
   164
    switch (angle) { /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */
slouken@10489
   165
    case 0: *sincx = bpp; *sincy = pitch - src->w * *sincx; *signx = *signy = 1; break;
slouken@10489
   166
    case 1: *sincx = -pitch; *sincy = bpp - *sincx * src->h; *signx = 1; *signy = -1; break;
slouken@10489
   167
    case 2: *sincx = -bpp; *sincy = -src->w * *sincx - pitch; *signx = *signy = -1; break;
slouken@10489
   168
    case 3: default: *sincx = pitch; *sincy = -*sincx * src->h - bpp; *signx = -1; *signy = 1; break;
slouken@10489
   169
    }
slouken@10489
   170
    if (flipx) {
slouken@10489
   171
        *signx = -*signx;
slouken@10489
   172
    }
slouken@10489
   173
    if (flipy) {
slouken@10489
   174
        *signy = -*signy;
slouken@10489
   175
    }
slouken@10489
   176
}
slouken@10489
   177
slouken@10489
   178
/* Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees. */
slouken@10489
   179
#define TRANSFORM_SURFACE_90(pixelType) \
slouken@10489
   180
    int dy, dincy = dst->pitch - dst->w*sizeof(pixelType), sincx, sincy, signx, signy;                      \
slouken@10489
   181
    Uint8 *sp = (Uint8*)src->pixels, *dp = (Uint8*)dst->pixels, *de;                                        \
slouken@10489
   182
                                                                                                            \
slouken@10489
   183
    computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \
slouken@10489
   184
    if (signx < 0) sp += (src->w-1)*sizeof(pixelType);                                                      \
slouken@10489
   185
    if (signy < 0) sp += (src->h-1)*src->pitch;                                                             \
slouken@10489
   186
                                                                                                            \
slouken@10489
   187
    for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) {                                             \
slouken@10489
   188
        if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use memcpy */               \
slouken@10489
   189
            SDL_memcpy(dp, sp, dst->w*sizeof(pixelType));                                                   \
slouken@10489
   190
            sp += dst->w*sizeof(pixelType);                                                                 \
slouken@10489
   191
            dp += dst->w*sizeof(pixelType);                                                                 \
slouken@10489
   192
        } else {                                                                                            \
slouken@10489
   193
            for (de = dp + dst->w*sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) {      \
slouken@10489
   194
                *(pixelType*)dp = *(pixelType*)sp;                                                          \
slouken@10489
   195
            }                                                                                               \
slouken@10489
   196
        }                                                                                                   \
slouken@10489
   197
    }
slouken@10489
   198
slouken@10489
   199
static void
slouken@10489
   200
transformSurfaceRGBA90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy)
slouken@10489
   201
{
slouken@10489
   202
    TRANSFORM_SURFACE_90(tColorRGBA);
slouken@10489
   203
}
slouken@10489
   204
slouken@10489
   205
static void
slouken@10489
   206
transformSurfaceY90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy)
slouken@10489
   207
{
slouken@10489
   208
    TRANSFORM_SURFACE_90(tColorY);
slouken@10489
   209
}
slouken@10489
   210
slouken@10489
   211
#undef TRANSFORM_SURFACE_90
gabomdq@6320
   212
gabomdq@7678
   213
/* !
gabomdq@6320
   214
\brief Internal 32 bit rotozoomer with optional anti-aliasing.
gabomdq@6320
   215
gabomdq@6320
   216
Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
gabomdq@6320
   217
parameters by scanning the destination surface and applying optionally anti-aliasing
gabomdq@6320
   218
by bilinear interpolation.
gabomdq@6320
   219
Assumes src and dst surfaces are of 32 bit depth.
gabomdq@6320
   220
Assumes dst surface was allocated with the correct dimensions.
gabomdq@6320
   221
gabomdq@6320
   222
\param src Source surface.
gabomdq@6320
   223
\param dst Destination surface.
gabomdq@6320
   224
\param cx Horizontal center coordinate.
gabomdq@6320
   225
\param cy Vertical center coordinate.
gabomdq@6320
   226
\param isin Integer version of sine of angle.
gabomdq@6320
   227
\param icos Integer version of cosine of angle.
gabomdq@6320
   228
\param flipx Flag indicating horizontal mirroring should be applied.
gabomdq@6320
   229
\param flipy Flag indicating vertical mirroring should be applied.
gabomdq@6320
   230
\param smooth Flag indicating anti-aliasing should be used.
gabomdq@6320
   231
*/
slouken@7859
   232
static void
slouken@7859
   233
_transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth)
gabomdq@6320
   234
{
gabomdq@6320
   235
    int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
gabomdq@6320
   236
    tColorRGBA c00, c01, c10, c11, cswap;
gabomdq@6320
   237
    tColorRGBA *pc, *sp;
gabomdq@6320
   238
    int gap;
gabomdq@6320
   239
gabomdq@6320
   240
    /*
gabomdq@6320
   241
    * Variable setup
gabomdq@6320
   242
    */
gabomdq@6320
   243
    xd = ((src->w - dst->w) << 15);
gabomdq@6320
   244
    yd = ((src->h - dst->h) << 15);
gabomdq@6320
   245
    ax = (cx << 16) - (icos * cx);
gabomdq@6320
   246
    ay = (cy << 16) - (isin * cx);
gabomdq@6320
   247
    sw = src->w - 1;
gabomdq@6320
   248
    sh = src->h - 1;
gabomdq@6320
   249
    pc = (tColorRGBA*) dst->pixels;
gabomdq@6320
   250
    gap = dst->pitch - dst->w * 4;
gabomdq@6320
   251
gabomdq@6320
   252
    /*
gabomdq@6320
   253
    * Switch between interpolating and non-interpolating code
gabomdq@6320
   254
    */
gabomdq@6320
   255
    if (smooth) {
gabomdq@6320
   256
        for (y = 0; y < dst->h; y++) {
gabomdq@6320
   257
            dy = cy - y;
gabomdq@6320
   258
            sdx = (ax + (isin * dy)) + xd;
gabomdq@6320
   259
            sdy = (ay - (icos * dy)) + yd;
gabomdq@6320
   260
            for (x = 0; x < dst->w; x++) {
gabomdq@6320
   261
                dx = (sdx >> 16);
gabomdq@6320
   262
                dy = (sdy >> 16);
gabomdq@6320
   263
                if (flipx) dx = sw - dx;
gabomdq@6320
   264
                if (flipy) dy = sh - dy;
slouken@9762
   265
                if ((unsigned)dx < (unsigned)sw && (unsigned)dy < (unsigned)sh) {
slouken@9762
   266
                    sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy) + dx;
gabomdq@6320
   267
                    c00 = *sp;
gabomdq@6320
   268
                    sp += 1;
gabomdq@6320
   269
                    c01 = *sp;
gabomdq@6320
   270
                    sp += (src->pitch/4);
gabomdq@6320
   271
                    c11 = *sp;
gabomdq@6320
   272
                    sp -= 1;
gabomdq@6320
   273
                    c10 = *sp;
gabomdq@6320
   274
                    if (flipx) {
gabomdq@6320
   275
                        cswap = c00; c00=c01; c01=cswap;
gabomdq@6320
   276
                        cswap = c10; c10=c11; c11=cswap;
gabomdq@6320
   277
                    }
gabomdq@6320
   278
                    if (flipy) {
gabomdq@6320
   279
                        cswap = c00; c00=c10; c10=cswap;
gabomdq@6320
   280
                        cswap = c01; c01=c11; c11=cswap;
gabomdq@6320
   281
                    }
gabomdq@6320
   282
                    /*
gabomdq@6320
   283
                    * Interpolate colors
gabomdq@6320
   284
                    */
gabomdq@6320
   285
                    ex = (sdx & 0xffff);
gabomdq@6320
   286
                    ey = (sdy & 0xffff);
gabomdq@6320
   287
                    t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
gabomdq@6320
   288
                    t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
gabomdq@6320
   289
                    pc->r = (((t2 - t1) * ey) >> 16) + t1;
gabomdq@6320
   290
                    t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
gabomdq@6320
   291
                    t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
gabomdq@6320
   292
                    pc->g = (((t2 - t1) * ey) >> 16) + t1;
gabomdq@6320
   293
                    t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
gabomdq@6320
   294
                    t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
gabomdq@6320
   295
                    pc->b = (((t2 - t1) * ey) >> 16) + t1;
gabomdq@6320
   296
                    t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
gabomdq@6320
   297
                    t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
gabomdq@6320
   298
                    pc->a = (((t2 - t1) * ey) >> 16) + t1;
gabomdq@6320
   299
                }
gabomdq@6320
   300
                sdx += icos;
gabomdq@6320
   301
                sdy += isin;
gabomdq@6320
   302
                pc++;
gabomdq@6320
   303
            }
gabomdq@6320
   304
            pc = (tColorRGBA *) ((Uint8 *) pc + gap);
gabomdq@6320
   305
        }
gabomdq@6320
   306
    } else {
gabomdq@6320
   307
        for (y = 0; y < dst->h; y++) {
gabomdq@6320
   308
            dy = cy - y;
gabomdq@6320
   309
            sdx = (ax + (isin * dy)) + xd;
gabomdq@6320
   310
            sdy = (ay - (icos * dy)) + yd;
gabomdq@6320
   311
            for (x = 0; x < dst->w; x++) {
slouken@9762
   312
                dx = (sdx >> 16);
slouken@9762
   313
                dy = (sdy >> 16);
slouken@9762
   314
                if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
slouken@9762
   315
                    if(flipx) dx = sw - dx;
slouken@9762
   316
                    if(flipy) dy = sh - dy;
slouken@9762
   317
                    *pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx);
gabomdq@6320
   318
                }
gabomdq@6320
   319
                sdx += icos;
gabomdq@6320
   320
                sdy += isin;
gabomdq@6320
   321
                pc++;
gabomdq@6320
   322
            }
gabomdq@6320
   323
            pc = (tColorRGBA *) ((Uint8 *) pc + gap);
gabomdq@6320
   324
        }
gabomdq@6320
   325
    }
gabomdq@6320
   326
}
gabomdq@6320
   327
gabomdq@7678
   328
/* !
gabomdq@6320
   329
gabomdq@6320
   330
\brief Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
gabomdq@6320
   331
gabomdq@6320
   332
Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
gabomdq@6320
   333
parameters by scanning the destination surface.
gabomdq@6320
   334
Assumes src and dst surfaces are of 8 bit depth.
gabomdq@6320
   335
Assumes dst surface was allocated with the correct dimensions.
gabomdq@6320
   336
gabomdq@6320
   337
\param src Source surface.
gabomdq@6320
   338
\param dst Destination surface.
gabomdq@6320
   339
\param cx Horizontal center coordinate.
gabomdq@6320
   340
\param cy Vertical center coordinate.
gabomdq@6320
   341
\param isin Integer version of sine of angle.
gabomdq@6320
   342
\param icos Integer version of cosine of angle.
gabomdq@6320
   343
\param flipx Flag indicating horizontal mirroring should be applied.
gabomdq@6320
   344
\param flipy Flag indicating vertical mirroring should be applied.
gabomdq@6320
   345
*/
slouken@7859
   346
static void
slouken@7859
   347
transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy)
gabomdq@6320
   348
{
icculus@6389
   349
    int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay;
slouken@9762
   350
    tColorY *pc;
gabomdq@6320
   351
    int gap;
gabomdq@6320
   352
gabomdq@6320
   353
    /*
gabomdq@6320
   354
    * Variable setup
gabomdq@6320
   355
    */
gabomdq@6320
   356
    xd = ((src->w - dst->w) << 15);
gabomdq@6320
   357
    yd = ((src->h - dst->h) << 15);
gabomdq@6320
   358
    ax = (cx << 16) - (icos * cx);
gabomdq@6320
   359
    ay = (cy << 16) - (isin * cx);
gabomdq@6320
   360
    pc = (tColorY*) dst->pixels;
gabomdq@6320
   361
    gap = dst->pitch - dst->w;
gabomdq@6320
   362
    /*
gabomdq@6320
   363
    * Clear surface to colorkey
gabomdq@6320
   364
    */
gabomdq@6320
   365
    SDL_memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h);
gabomdq@6320
   366
    /*
gabomdq@6320
   367
    * Iterate through destination surface
gabomdq@6320
   368
    */
gabomdq@6320
   369
    for (y = 0; y < dst->h; y++) {
gabomdq@6320
   370
        dy = cy - y;
gabomdq@6320
   371
        sdx = (ax + (isin * dy)) + xd;
gabomdq@6320
   372
        sdy = (ay - (icos * dy)) + yd;
gabomdq@6320
   373
        for (x = 0; x < dst->w; x++) {
slouken@9762
   374
            dx = (sdx >> 16);
slouken@9762
   375
            dy = (sdy >> 16);
slouken@9762
   376
            if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
slouken@9762
   377
                if (flipx) dx = (src->w-1)-dx;
slouken@9762
   378
                if (flipy) dy = (src->h-1)-dy;
slouken@9762
   379
                *pc = *((tColorY *)src->pixels + src->pitch * dy + dx);
gabomdq@6320
   380
            }
gabomdq@6320
   381
            sdx += icos;
gabomdq@6320
   382
            sdy += isin;
gabomdq@6320
   383
            pc++;
gabomdq@6320
   384
        }
gabomdq@6320
   385
        pc += gap;
gabomdq@6320
   386
    }
gabomdq@6320
   387
}
gabomdq@6320
   388
gabomdq@6320
   389
gabomdq@7678
   390
/* !
gabomdq@6320
   391
\brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
gabomdq@6320
   392
gabomdq@6320
   393
Rotates a 32bit or 8bit 'src' surface to newly created 'dst' surface.
gabomdq@6320
   394
'angle' is the rotation in degrees, 'centerx' and 'centery' the rotation center. If 'smooth' is set
gabomdq@6320
   395
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
gabomdq@6320
   396
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
gabomdq@6320
   397
gabomdq@6320
   398
\param src The surface to rotozoom.
gabomdq@6320
   399
\param angle The angle to rotate in degrees.
gabomdq@6320
   400
\param centerx The horizontal coordinate of the center of rotation
gabomdq@6320
   401
\param zoomy The vertical coordinate of the center of rotation
gabomdq@6320
   402
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
gabomdq@6320
   403
\param flipx Set to 1 to flip the image horizontally
gabomdq@6320
   404
\param flipy Set to 1 to flip the image vertically
gabomdq@6320
   405
\param dstwidth The destination surface width
gabomdq@6320
   406
\param dstheight The destination surface height
gabomdq@6320
   407
\param cangle The angle cosine
gabomdq@6320
   408
\param sangle The angle sine
gabomdq@6320
   409
\return The new rotated surface.
gabomdq@6320
   410
gabomdq@6320
   411
*/
gabomdq@6320
   412
slouken@7859
   413
SDL_Surface *
slouken@7859
   414
SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle)
gabomdq@6320
   415
{
gabomdq@6320
   416
    SDL_Surface *rz_src;
gabomdq@6320
   417
    SDL_Surface *rz_dst;
slouken@10489
   418
    int is32bit, angle90;
slouken@9763
   419
    int i;
slouken@10342
   420
    Uint8 r = 0, g = 0, b = 0;
gabomdq@6320
   421
    Uint32 colorkey = 0;
gabomdq@6320
   422
    int colorKeyAvailable = 0;
gabomdq@6320
   423
    double sangleinv, cangleinv;
gabomdq@6320
   424
gabomdq@6320
   425
    /*
gabomdq@6320
   426
    * Sanity check
gabomdq@6320
   427
    */
gabomdq@6320
   428
    if (src == NULL)
gabomdq@6320
   429
        return (NULL);
gabomdq@6320
   430
gabomdq@7678
   431
    if (src->flags & SDL_TRUE/* SDL_SRCCOLORKEY */)
gabomdq@6320
   432
    {
gabomdq@6320
   433
        colorkey = _colorkey(src);
gabomdq@6320
   434
        SDL_GetRGB(colorkey, src->format, &r, &g, &b);
gabomdq@6320
   435
        colorKeyAvailable = 1;
gabomdq@6320
   436
    }
gabomdq@6320
   437
    /*
gabomdq@6320
   438
    * Determine if source surface is 32bit or 8bit
gabomdq@6320
   439
    */
gabomdq@6320
   440
    is32bit = (src->format->BitsPerPixel == 32);
gabomdq@6320
   441
    if ((is32bit) || (src->format->BitsPerPixel == 8)) {
gabomdq@6320
   442
        /*
gabomdq@6320
   443
        * Use source surface 'as is'
gabomdq@6320
   444
        */
gabomdq@6320
   445
        rz_src = src;
gabomdq@6320
   446
    } else {
slouken@9763
   447
        Uint32 format = SDL_MasksToPixelFormatEnum(32,
gabomdq@6320
   448
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
gabomdq@6320
   449
            0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
gabomdq@6320
   450
#else
gabomdq@6320
   451
            0xff000000,  0x00ff0000, 0x0000ff00, 0x000000ff
gabomdq@6320
   452
#endif
slouken@9763
   453
        );
slouken@9763
   454
        rz_src = SDL_ConvertSurfaceFormat(src, format, src->flags);
slouken@10485
   455
        if (rz_src == NULL) {
slouken@10485
   456
            return NULL;
slouken@10485
   457
        }
gabomdq@6320
   458
        is32bit = 1;
gabomdq@6320
   459
    }
gabomdq@6320
   460
gabomdq@6320
   461
    /* Determine target size */
gabomdq@7678
   462
    /* _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle); */
gabomdq@6320
   463
gabomdq@6320
   464
    /*
gabomdq@6320
   465
    * Calculate target factors from sin/cos and zoom
gabomdq@6320
   466
    */
gabomdq@6320
   467
    sangleinv = sangle*65536.0;
gabomdq@6320
   468
    cangleinv = cangle*65536.0;
gabomdq@6320
   469
gabomdq@6320
   470
    /*
gabomdq@6320
   471
    * Alloc space to completely contain the rotated surface
gabomdq@6320
   472
    */
gabomdq@6320
   473
    if (is32bit) {
gabomdq@6320
   474
        /*
gabomdq@6320
   475
        * Target surface is 32bit with source RGBA/ABGR ordering
gabomdq@6320
   476
        */
gabomdq@6320
   477
        rz_dst =
gabomdq@6320
   478
            SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 32,
gabomdq@6320
   479
            rz_src->format->Rmask, rz_src->format->Gmask,
gabomdq@6320
   480
            rz_src->format->Bmask, rz_src->format->Amask);
gabomdq@6320
   481
    } else {
gabomdq@6320
   482
        /*
gabomdq@6320
   483
        * Target surface is 8bit
gabomdq@6320
   484
        */
gabomdq@6320
   485
        rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0);
gabomdq@6320
   486
    }
gabomdq@6320
   487
gabomdq@6320
   488
    /* Check target */
gabomdq@6320
   489
    if (rz_dst == NULL)
gabomdq@6320
   490
        return NULL;
gabomdq@6320
   491
gabomdq@6320
   492
    /* Adjust for guard rows */
gabomdq@6320
   493
    rz_dst->h = dstheight;
gabomdq@6320
   494
gabomdq@6320
   495
    if (colorKeyAvailable == 1){
gabomdq@6320
   496
        colorkey = SDL_MapRGB(rz_dst->format, r, g, b);
gabomdq@6320
   497
gabomdq@6320
   498
        SDL_FillRect(rz_dst, NULL, colorkey );
gabomdq@6320
   499
    }
gabomdq@6320
   500
gabomdq@6320
   501
    /*
gabomdq@6320
   502
    * Lock source surface
gabomdq@6320
   503
    */
gabomdq@6320
   504
    if (SDL_MUSTLOCK(rz_src)) {
gabomdq@6320
   505
        SDL_LockSurface(rz_src);
gabomdq@6320
   506
    }
gabomdq@6320
   507
slouken@10489
   508
    /* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce
slouken@10489
   509
     * the off-by-one problem in _transformSurfaceRGBA that expresses itself when the rotation is near
slouken@10489
   510
     * multiples of 90 degrees.
slouken@10489
   511
     */
slouken@10489
   512
    angle90 = (int)(angle/90);
slouken@10489
   513
    if (angle90 == angle/90) {
slouken@10489
   514
        angle90 %= 4;
slouken@10489
   515
        if (angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */
slouken@10489
   516
    } else {
slouken@10489
   517
        angle90 = -1;
slouken@10489
   518
    }
slouken@10489
   519
gabomdq@6320
   520
    /*
gabomdq@6320
   521
    * Check which kind of surface we have
gabomdq@6320
   522
    */
gabomdq@6320
   523
    if (is32bit) {
gabomdq@6320
   524
        /*
gabomdq@6320
   525
        * Call the 32bit transformation routine to do the rotation (using alpha)
gabomdq@6320
   526
        */
slouken@10489
   527
        if (angle90 >= 0) {
slouken@10489
   528
            transformSurfaceRGBA90(rz_src, rz_dst, angle90, flipx, flipy);
slouken@10489
   529
        } else {
slouken@10489
   530
            _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery, (int) (sangleinv), (int) (cangleinv), flipx, flipy, smooth);
slouken@10489
   531
        }
gabomdq@6320
   532
        /*
gabomdq@6320
   533
        * Turn on source-alpha support
gabomdq@6320
   534
        */
gabomdq@7678
   535
        /* SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); */
gabomdq@7678
   536
        SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
gabomdq@6320
   537
    } else {
gabomdq@6320
   538
        /*
gabomdq@6320
   539
        * Copy palette and colorkey info
gabomdq@6320
   540
        */
gabomdq@6320
   541
        for (i = 0; i < rz_src->format->palette->ncolors; i++) {
gabomdq@6320
   542
            rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
gabomdq@6320
   543
        }
gabomdq@6320
   544
        rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
gabomdq@6320
   545
        /*
gabomdq@6320
   546
        * Call the 8bit transformation routine to do the rotation
gabomdq@6320
   547
        */
slouken@10489
   548
        if(angle90 >= 0) {
slouken@10489
   549
            transformSurfaceY90(rz_src, rz_dst, angle90, flipx, flipy);
slouken@10489
   550
        } else {
slouken@10489
   551
            transformSurfaceY(rz_src, rz_dst, centerx, centery, (int)(sangleinv), (int)(cangleinv), flipx, flipy);
slouken@10489
   552
        }
gabomdq@7678
   553
        SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src));
gabomdq@6320
   554
    }
slouken@9763
   555
slouken@9763
   556
    /* copy alpha mod, color mod, and blend mode */
slouken@9763
   557
    {
slouken@9763
   558
      SDL_BlendMode blendMode;
icculus@9775
   559
      Uint8 alphaMod, cr, cg, cb;
slouken@9763
   560
      SDL_GetSurfaceAlphaMod(src, &alphaMod);
slouken@9763
   561
      SDL_GetSurfaceBlendMode(src, &blendMode);
icculus@9775
   562
      SDL_GetSurfaceColorMod(src, &cr, &cg, &cb);
slouken@9763
   563
      SDL_SetSurfaceAlphaMod(rz_dst, alphaMod);
slouken@9763
   564
      SDL_SetSurfaceBlendMode(rz_dst, blendMode);
icculus@9775
   565
      SDL_SetSurfaceColorMod(rz_dst, cr, cg, cb);
slouken@9763
   566
    }
slouken@9763
   567
gabomdq@6320
   568
    /*
gabomdq@6320
   569
    * Unlock source surface
gabomdq@6320
   570
    */
gabomdq@6320
   571
    if (SDL_MUSTLOCK(rz_src)) {
gabomdq@6320
   572
        SDL_UnlockSurface(rz_src);
gabomdq@6320
   573
    }
gabomdq@6320
   574
gabomdq@6320
   575
    /*
gabomdq@6320
   576
    * Cleanup temp surface
gabomdq@6320
   577
    */
slouken@9763
   578
    if (rz_src != src) {
gabomdq@6320
   579
        SDL_FreeSurface(rz_src);
gabomdq@6320
   580
    }
gabomdq@6320
   581
gabomdq@6320
   582
    /*
gabomdq@6320
   583
    * Return destination surface
gabomdq@6320
   584
    */
gabomdq@6320
   585
    return (rz_dst);
gabomdq@6320
   586
}