cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_rotate.c (15718B)


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