cscg22-gearboy

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

SDL_surface.c (31763B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../SDL_internal.h"
     22
     23#include "SDL_video.h"
     24#include "SDL_sysvideo.h"
     25#include "SDL_blit.h"
     26#include "SDL_RLEaccel_c.h"
     27#include "SDL_pixels_c.h"
     28
     29/* Public routines */
     30/*
     31 * Create an empty RGB surface of the appropriate depth
     32 */
     33SDL_Surface *
     34SDL_CreateRGBSurface(Uint32 flags,
     35                     int width, int height, int depth,
     36                     Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
     37{
     38    SDL_Surface *surface;
     39    Uint32 format;
     40
     41    /* The flags are no longer used, make the compiler happy */
     42    (void)flags;
     43
     44    /* Get the pixel format */
     45    format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
     46    if (format == SDL_PIXELFORMAT_UNKNOWN) {
     47        SDL_SetError("Unknown pixel format");
     48        return NULL;
     49    }
     50
     51    /* Allocate the surface */
     52    surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
     53    if (surface == NULL) {
     54        SDL_OutOfMemory();
     55        return NULL;
     56    }
     57
     58    surface->format = SDL_AllocFormat(format);
     59    if (!surface->format) {
     60        SDL_FreeSurface(surface);
     61        return NULL;
     62    }
     63    surface->w = width;
     64    surface->h = height;
     65    surface->pitch = SDL_CalculatePitch(surface);
     66    SDL_SetClipRect(surface, NULL);
     67
     68    if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
     69        SDL_Palette *palette =
     70            SDL_AllocPalette((1 << surface->format->BitsPerPixel));
     71        if (!palette) {
     72            SDL_FreeSurface(surface);
     73            return NULL;
     74        }
     75        if (palette->ncolors == 2) {
     76            /* Create a black and white bitmap palette */
     77            palette->colors[0].r = 0xFF;
     78            palette->colors[0].g = 0xFF;
     79            palette->colors[0].b = 0xFF;
     80            palette->colors[1].r = 0x00;
     81            palette->colors[1].g = 0x00;
     82            palette->colors[1].b = 0x00;
     83        }
     84        SDL_SetSurfacePalette(surface, palette);
     85        SDL_FreePalette(palette);
     86    }
     87
     88    /* Get the pixels */
     89    if (surface->w && surface->h) {
     90        surface->pixels = SDL_malloc(surface->h * surface->pitch);
     91        if (!surface->pixels) {
     92            SDL_FreeSurface(surface);
     93            SDL_OutOfMemory();
     94            return NULL;
     95        }
     96        /* This is important for bitmaps */
     97        SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
     98    }
     99
    100    /* Allocate an empty mapping */
    101    surface->map = SDL_AllocBlitMap();
    102    if (!surface->map) {
    103        SDL_FreeSurface(surface);
    104        return NULL;
    105    }
    106
    107    /* By default surface with an alpha mask are set up for blending */
    108    if (Amask) {
    109        SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
    110    }
    111
    112    /* The surface is ready to go */
    113    surface->refcount = 1;
    114    return surface;
    115}
    116
    117/*
    118 * Create an RGB surface from an existing memory buffer
    119 */
    120SDL_Surface *
    121SDL_CreateRGBSurfaceFrom(void *pixels,
    122                         int width, int height, int depth, int pitch,
    123                         Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
    124                         Uint32 Amask)
    125{
    126    SDL_Surface *surface;
    127
    128    surface =
    129        SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
    130    if (surface != NULL) {
    131        surface->flags |= SDL_PREALLOC;
    132        surface->pixels = pixels;
    133        surface->w = width;
    134        surface->h = height;
    135        surface->pitch = pitch;
    136        SDL_SetClipRect(surface, NULL);
    137    }
    138    return surface;
    139}
    140
    141int
    142SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
    143{
    144    if (!surface) {
    145        return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
    146    }
    147    if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
    148        return -1;
    149    }
    150    SDL_InvalidateMap(surface->map);
    151
    152    return 0;
    153}
    154
    155int
    156SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
    157{
    158    int flags;
    159
    160    if (!surface) {
    161        return -1;
    162    }
    163
    164    flags = surface->map->info.flags;
    165    if (flag) {
    166        surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
    167    } else {
    168        surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
    169    }
    170    if (surface->map->info.flags != flags) {
    171        SDL_InvalidateMap(surface->map);
    172    }
    173    return 0;
    174}
    175
    176int
    177SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
    178{
    179    int flags;
    180
    181    if (!surface) {
    182        return SDL_InvalidParamError("surface");
    183    }
    184
    185    if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
    186        return SDL_InvalidParamError("key");
    187    }
    188
    189    if (flag & SDL_RLEACCEL) {
    190        SDL_SetSurfaceRLE(surface, 1);
    191    }
    192
    193    flags = surface->map->info.flags;
    194    if (flag) {
    195        surface->map->info.flags |= SDL_COPY_COLORKEY;
    196        surface->map->info.colorkey = key;
    197        if (surface->format->palette) {
    198            surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
    199            ++surface->format->palette->version;
    200            if (!surface->format->palette->version) {
    201                surface->format->palette->version = 1;
    202            }
    203        }
    204    } else {
    205        if (surface->format->palette) {
    206            surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE;
    207            ++surface->format->palette->version;
    208            if (!surface->format->palette->version) {
    209                surface->format->palette->version = 1;
    210            }
    211        }
    212        surface->map->info.flags &= ~SDL_COPY_COLORKEY;
    213    }
    214    if (surface->map->info.flags != flags) {
    215        SDL_InvalidateMap(surface->map);
    216    }
    217
    218    return 0;
    219}
    220
    221int
    222SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
    223{
    224    if (!surface) {
    225        return -1;
    226    }
    227
    228    if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
    229        return -1;
    230    }
    231
    232    if (key) {
    233        *key = surface->map->info.colorkey;
    234    }
    235    return 0;
    236}
    237
    238/* This is a fairly slow function to switch from colorkey to alpha */
    239static void
    240SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
    241{
    242    int x, y;
    243
    244    if (!surface) {
    245        return;
    246    }
    247
    248    if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
    249        !surface->format->Amask) {
    250        return;
    251    }
    252
    253    SDL_LockSurface(surface);
    254
    255    switch (surface->format->BytesPerPixel) {
    256    case 2:
    257        {
    258            Uint16 *row, *spot;
    259            Uint16 ckey = (Uint16) surface->map->info.colorkey;
    260            Uint16 mask = (Uint16) (~surface->format->Amask);
    261
    262            /* Ignore alpha in colorkey comparison */
    263            ckey &= mask;
    264            row = (Uint16 *) surface->pixels;
    265            for (y = surface->h; y--;) {
    266                spot = row;
    267                for (x = surface->w; x--;) {
    268                    if ((*spot & mask) == ckey) {
    269                        *spot &= mask;
    270                    }
    271                    ++spot;
    272                }
    273                row += surface->pitch / 2;
    274            }
    275        }
    276        break;
    277    case 3:
    278        /* FIXME */
    279        break;
    280    case 4:
    281        {
    282            Uint32 *row, *spot;
    283            Uint32 ckey = surface->map->info.colorkey;
    284            Uint32 mask = ~surface->format->Amask;
    285
    286            /* Ignore alpha in colorkey comparison */
    287            ckey &= mask;
    288            row = (Uint32 *) surface->pixels;
    289            for (y = surface->h; y--;) {
    290                spot = row;
    291                for (x = surface->w; x--;) {
    292                    if ((*spot & mask) == ckey) {
    293                        *spot &= mask;
    294                    }
    295                    ++spot;
    296                }
    297                row += surface->pitch / 4;
    298            }
    299        }
    300        break;
    301    }
    302
    303    SDL_UnlockSurface(surface);
    304
    305    SDL_SetColorKey(surface, 0, 0);
    306    SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
    307}
    308
    309int
    310SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
    311{
    312    int flags;
    313
    314    if (!surface) {
    315        return -1;
    316    }
    317
    318    surface->map->info.r = r;
    319    surface->map->info.g = g;
    320    surface->map->info.b = b;
    321
    322    flags = surface->map->info.flags;
    323    if (r != 0xFF || g != 0xFF || b != 0xFF) {
    324        surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
    325    } else {
    326        surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
    327    }
    328    if (surface->map->info.flags != flags) {
    329        SDL_InvalidateMap(surface->map);
    330    }
    331    return 0;
    332}
    333
    334
    335int
    336SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
    337{
    338    if (!surface) {
    339        return -1;
    340    }
    341
    342    if (r) {
    343        *r = surface->map->info.r;
    344    }
    345    if (g) {
    346        *g = surface->map->info.g;
    347    }
    348    if (b) {
    349        *b = surface->map->info.b;
    350    }
    351    return 0;
    352}
    353
    354int
    355SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
    356{
    357    int flags;
    358
    359    if (!surface) {
    360        return -1;
    361    }
    362
    363    surface->map->info.a = alpha;
    364
    365    flags = surface->map->info.flags;
    366    if (alpha != 0xFF) {
    367        surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
    368    } else {
    369        surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
    370    }
    371    if (surface->map->info.flags != flags) {
    372        SDL_InvalidateMap(surface->map);
    373    }
    374    return 0;
    375}
    376
    377int
    378SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
    379{
    380    if (!surface) {
    381        return -1;
    382    }
    383
    384    if (alpha) {
    385        *alpha = surface->map->info.a;
    386    }
    387    return 0;
    388}
    389
    390int
    391SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
    392{
    393    int flags, status;
    394
    395    if (!surface) {
    396        return -1;
    397    }
    398
    399    status = 0;
    400    flags = surface->map->info.flags;
    401    surface->map->info.flags &=
    402        ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
    403    switch (blendMode) {
    404    case SDL_BLENDMODE_NONE:
    405        break;
    406    case SDL_BLENDMODE_BLEND:
    407        surface->map->info.flags |= SDL_COPY_BLEND;
    408        break;
    409    case SDL_BLENDMODE_ADD:
    410        surface->map->info.flags |= SDL_COPY_ADD;
    411        break;
    412    case SDL_BLENDMODE_MOD:
    413        surface->map->info.flags |= SDL_COPY_MOD;
    414        break;
    415    default:
    416        status = SDL_Unsupported();
    417        break;
    418    }
    419
    420    if (surface->map->info.flags != flags) {
    421        SDL_InvalidateMap(surface->map);
    422    }
    423
    424    return status;
    425}
    426
    427int
    428SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
    429{
    430    if (!surface) {
    431        return -1;
    432    }
    433
    434    if (!blendMode) {
    435        return 0;
    436    }
    437
    438    switch (surface->map->
    439            info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
    440    case SDL_COPY_BLEND:
    441        *blendMode = SDL_BLENDMODE_BLEND;
    442        break;
    443    case SDL_COPY_ADD:
    444        *blendMode = SDL_BLENDMODE_ADD;
    445        break;
    446    case SDL_COPY_MOD:
    447        *blendMode = SDL_BLENDMODE_MOD;
    448        break;
    449    default:
    450        *blendMode = SDL_BLENDMODE_NONE;
    451        break;
    452    }
    453    return 0;
    454}
    455
    456SDL_bool
    457SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
    458{
    459    SDL_Rect full_rect;
    460
    461    /* Don't do anything if there's no surface to act on */
    462    if (!surface) {
    463        return SDL_FALSE;
    464    }
    465
    466    /* Set up the full surface rectangle */
    467    full_rect.x = 0;
    468    full_rect.y = 0;
    469    full_rect.w = surface->w;
    470    full_rect.h = surface->h;
    471
    472    /* Set the clipping rectangle */
    473    if (!rect) {
    474        surface->clip_rect = full_rect;
    475        return SDL_TRUE;
    476    }
    477    return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
    478}
    479
    480void
    481SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
    482{
    483    if (surface && rect) {
    484        *rect = surface->clip_rect;
    485    }
    486}
    487
    488/*
    489 * Set up a blit between two surfaces -- split into three parts:
    490 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
    491 * verification.  The lower part is a pointer to a low level
    492 * accelerated blitting function.
    493 *
    494 * These parts are separated out and each used internally by this
    495 * library in the optimimum places.  They are exported so that if
    496 * you know exactly what you are doing, you can optimize your code
    497 * by calling the one(s) you need.
    498 */
    499int
    500SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
    501              SDL_Surface * dst, SDL_Rect * dstrect)
    502{
    503    /* Check to make sure the blit mapping is valid */
    504    if ((src->map->dst != dst) ||
    505        (dst->format->palette &&
    506         src->map->dst_palette_version != dst->format->palette->version) ||
    507        (src->format->palette &&
    508         src->map->src_palette_version != src->format->palette->version)) {
    509        if (SDL_MapSurface(src, dst) < 0) {
    510            return (-1);
    511        }
    512        /* just here for debugging */
    513/*         printf */
    514/*             ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */
    515/*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
    516/*              dst->map->info.flags, src->map->blit); */
    517    }
    518    return (src->map->blit(src, srcrect, dst, dstrect));
    519}
    520
    521
    522int
    523SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
    524              SDL_Surface * dst, SDL_Rect * dstrect)
    525{
    526    SDL_Rect fulldst;
    527    int srcx, srcy, w, h;
    528
    529    /* Make sure the surfaces aren't locked */
    530    if (!src || !dst) {
    531        return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
    532    }
    533    if (src->locked || dst->locked) {
    534        return SDL_SetError("Surfaces must not be locked during blit");
    535    }
    536
    537    /* If the destination rectangle is NULL, use the entire dest surface */
    538    if (dstrect == NULL) {
    539        fulldst.x = fulldst.y = 0;
    540        fulldst.w = dst->w;
    541        fulldst.h = dst->h;
    542        dstrect = &fulldst;
    543    }
    544
    545    /* clip the source rectangle to the source surface */
    546    if (srcrect) {
    547        int maxw, maxh;
    548
    549        srcx = srcrect->x;
    550        w = srcrect->w;
    551        if (srcx < 0) {
    552            w += srcx;
    553            dstrect->x -= srcx;
    554            srcx = 0;
    555        }
    556        maxw = src->w - srcx;
    557        if (maxw < w)
    558            w = maxw;
    559
    560        srcy = srcrect->y;
    561        h = srcrect->h;
    562        if (srcy < 0) {
    563            h += srcy;
    564            dstrect->y -= srcy;
    565            srcy = 0;
    566        }
    567        maxh = src->h - srcy;
    568        if (maxh < h)
    569            h = maxh;
    570
    571    } else {
    572        srcx = srcy = 0;
    573        w = src->w;
    574        h = src->h;
    575    }
    576
    577    /* clip the destination rectangle against the clip rectangle */
    578    {
    579        SDL_Rect *clip = &dst->clip_rect;
    580        int dx, dy;
    581
    582        dx = clip->x - dstrect->x;
    583        if (dx > 0) {
    584            w -= dx;
    585            dstrect->x += dx;
    586            srcx += dx;
    587        }
    588        dx = dstrect->x + w - clip->x - clip->w;
    589        if (dx > 0)
    590            w -= dx;
    591
    592        dy = clip->y - dstrect->y;
    593        if (dy > 0) {
    594            h -= dy;
    595            dstrect->y += dy;
    596            srcy += dy;
    597        }
    598        dy = dstrect->y + h - clip->y - clip->h;
    599        if (dy > 0)
    600            h -= dy;
    601    }
    602
    603    /* Switch back to a fast blit if we were previously stretching */
    604    if (src->map->info.flags & SDL_COPY_NEAREST) {
    605        src->map->info.flags &= ~SDL_COPY_NEAREST;
    606        SDL_InvalidateMap(src->map);
    607    }
    608
    609    if (w > 0 && h > 0) {
    610        SDL_Rect sr;
    611        sr.x = srcx;
    612        sr.y = srcy;
    613        sr.w = dstrect->w = w;
    614        sr.h = dstrect->h = h;
    615        return SDL_LowerBlit(src, &sr, dst, dstrect);
    616    }
    617    dstrect->w = dstrect->h = 0;
    618    return 0;
    619}
    620
    621int
    622SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
    623              SDL_Surface * dst, SDL_Rect * dstrect)
    624{
    625    double src_x0, src_y0, src_x1, src_y1;
    626    double dst_x0, dst_y0, dst_x1, dst_y1;
    627    SDL_Rect final_src, final_dst;
    628    double scaling_w, scaling_h;
    629    int src_w, src_h;
    630    int dst_w, dst_h;
    631
    632    /* Make sure the surfaces aren't locked */
    633    if (!src || !dst) {
    634        return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
    635    }
    636    if (src->locked || dst->locked) {
    637        return SDL_SetError("Surfaces must not be locked during blit");
    638    }
    639
    640    if (NULL == srcrect) {
    641        src_w = src->w;
    642        src_h = src->h;
    643    } else {
    644        src_w = srcrect->w;
    645        src_h = srcrect->h;
    646    }
    647
    648    if (NULL == dstrect) {
    649        dst_w = dst->w;
    650        dst_h = dst->h;
    651    } else {
    652        dst_w = dstrect->w;
    653        dst_h = dstrect->h;
    654    }
    655
    656    if (dst_w == src_w && dst_h == src_h) {
    657        /* No scaling, defer to regular blit */
    658        return SDL_BlitSurface(src, srcrect, dst, dstrect);
    659    }
    660
    661    scaling_w = (double)dst_w / src_w;
    662    scaling_h = (double)dst_h / src_h;
    663
    664    if (NULL == dstrect) {
    665        dst_x0 = 0;
    666        dst_y0 = 0;
    667        dst_x1 = dst_w - 1;
    668        dst_y1 = dst_h - 1;
    669    } else {
    670        dst_x0 = dstrect->x;
    671        dst_y0 = dstrect->y;
    672        dst_x1 = dst_x0 + dst_w - 1;
    673        dst_y1 = dst_y0 + dst_h - 1;
    674    }
    675
    676    if (NULL == srcrect) {
    677        src_x0 = 0;
    678        src_y0 = 0;
    679        src_x1 = src_w - 1;
    680        src_y1 = src_h - 1;
    681    } else {
    682        src_x0 = srcrect->x;
    683        src_y0 = srcrect->y;
    684        src_x1 = src_x0 + src_w - 1;
    685        src_y1 = src_y0 + src_h - 1;
    686
    687        /* Clip source rectangle to the source surface */
    688
    689        if (src_x0 < 0) {
    690            dst_x0 -= src_x0 * scaling_w;
    691            src_x0 = 0;
    692        }
    693
    694        if (src_x1 >= src->w) {
    695            dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
    696            src_x1 = src->w - 1;
    697        }
    698
    699        if (src_y0 < 0) {
    700            dst_y0 -= src_y0 * scaling_h;
    701            src_y0 = 0;
    702        }
    703
    704        if (src_y1 >= src->h) {
    705            dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
    706            src_y1 = src->h - 1;
    707        }
    708    }
    709
    710    /* Clip destination rectangle to the clip rectangle */
    711
    712    /* Translate to clip space for easier calculations */
    713    dst_x0 -= dst->clip_rect.x;
    714    dst_x1 -= dst->clip_rect.x;
    715    dst_y0 -= dst->clip_rect.y;
    716    dst_y1 -= dst->clip_rect.y;
    717
    718    if (dst_x0 < 0) {
    719        src_x0 -= dst_x0 / scaling_w;
    720        dst_x0 = 0;
    721    }
    722
    723    if (dst_x1 >= dst->clip_rect.w) {
    724        src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
    725        dst_x1 = dst->clip_rect.w - 1;
    726    }
    727
    728    if (dst_y0 < 0) {
    729        src_y0 -= dst_y0 / scaling_h;
    730        dst_y0 = 0;
    731    }
    732
    733    if (dst_y1 >= dst->clip_rect.h) {
    734        src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
    735        dst_y1 = dst->clip_rect.h - 1;
    736    }
    737
    738    /* Translate back to surface coordinates */
    739    dst_x0 += dst->clip_rect.x;
    740    dst_x1 += dst->clip_rect.x;
    741    dst_y0 += dst->clip_rect.y;
    742    dst_y1 += dst->clip_rect.y;
    743
    744    final_src.x = SDL_floor(src_x0 + 0.5);
    745    final_src.y = SDL_floor(src_y0 + 0.5);
    746    final_src.w = SDL_floor(src_x1 - src_x0 + 1.5);
    747    final_src.h = SDL_floor(src_y1 - src_y0 + 1.5);
    748
    749    final_dst.x = SDL_floor(dst_x0 + 0.5);
    750    final_dst.y = SDL_floor(dst_y0 + 0.5);
    751    final_dst.w = SDL_floor(dst_x1 - dst_x0 + 1.5);
    752    final_dst.h = SDL_floor(dst_y1 - dst_y0 + 1.5);
    753
    754    if (final_dst.w < 0)
    755        final_dst.w = 0;
    756    if (final_dst.h < 0)
    757        final_dst.h = 0;
    758
    759    if (dstrect)
    760        *dstrect = final_dst;
    761
    762    if (final_dst.w == 0 || final_dst.h == 0 ||
    763        final_src.w <= 0 || final_src.h <= 0) {
    764        /* No-op. */
    765        return 0;
    766    }
    767
    768    return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
    769}
    770
    771/**
    772 *  This is a semi-private blit function and it performs low-level surface
    773 *  scaled blitting only.
    774 */
    775int
    776SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
    777                SDL_Surface * dst, SDL_Rect * dstrect)
    778{
    779    static const Uint32 complex_copy_flags = (
    780        SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
    781        SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD |
    782        SDL_COPY_COLORKEY
    783    );
    784
    785    if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
    786        src->map->info.flags |= SDL_COPY_NEAREST;
    787        SDL_InvalidateMap(src->map);
    788    }
    789
    790    if ( !(src->map->info.flags & complex_copy_flags) &&
    791         src->format->format == dst->format->format &&
    792         !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
    793        return SDL_SoftStretch( src, srcrect, dst, dstrect );
    794    } else {
    795        return SDL_LowerBlit( src, srcrect, dst, dstrect );
    796    }
    797}
    798
    799/*
    800 * Lock a surface to directly access the pixels
    801 */
    802int
    803SDL_LockSurface(SDL_Surface * surface)
    804{
    805    if (!surface->locked) {
    806        /* Perform the lock */
    807        if (surface->flags & SDL_RLEACCEL) {
    808            SDL_UnRLESurface(surface, 1);
    809            surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
    810        }
    811    }
    812
    813    /* Increment the surface lock count, for recursive locks */
    814    ++surface->locked;
    815
    816    /* Ready to go.. */
    817    return (0);
    818}
    819
    820/*
    821 * Unlock a previously locked surface
    822 */
    823void
    824SDL_UnlockSurface(SDL_Surface * surface)
    825{
    826    /* Only perform an unlock if we are locked */
    827    if (!surface->locked || (--surface->locked > 0)) {
    828        return;
    829    }
    830
    831    /* Update RLE encoded surface with new data */
    832    if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
    833        surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
    834        SDL_RLESurface(surface);
    835    }
    836}
    837
    838/*
    839 * Convert a surface into the specified pixel format.
    840 */
    841SDL_Surface *
    842SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
    843                   Uint32 flags)
    844{
    845    SDL_Surface *convert;
    846    Uint32 copy_flags;
    847    SDL_Color copy_color;
    848    SDL_Rect bounds;
    849
    850    /* Check for empty destination palette! (results in empty image) */
    851    if (format->palette != NULL) {
    852        int i;
    853        for (i = 0; i < format->palette->ncolors; ++i) {
    854            if ((format->palette->colors[i].r != 0xFF) ||
    855                (format->palette->colors[i].g != 0xFF) ||
    856                (format->palette->colors[i].b != 0xFF))
    857                break;
    858        }
    859        if (i == format->palette->ncolors) {
    860            SDL_SetError("Empty destination palette");
    861            return (NULL);
    862        }
    863    }
    864
    865    /* Create a new surface with the desired format */
    866    convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
    867                                   format->BitsPerPixel, format->Rmask,
    868                                   format->Gmask, format->Bmask,
    869                                   format->Amask);
    870    if (convert == NULL) {
    871        return (NULL);
    872    }
    873
    874    /* Copy the palette if any */
    875    if (format->palette && convert->format->palette) {
    876        SDL_memcpy(convert->format->palette->colors,
    877                   format->palette->colors,
    878                   format->palette->ncolors * sizeof(SDL_Color));
    879        convert->format->palette->ncolors = format->palette->ncolors;
    880    }
    881
    882    /* Save the original copy flags */
    883    copy_flags = surface->map->info.flags;
    884    copy_color.r = surface->map->info.r;
    885    copy_color.g = surface->map->info.g;
    886    copy_color.b = surface->map->info.b;
    887    copy_color.a = surface->map->info.a;
    888    surface->map->info.r = 0xFF;
    889    surface->map->info.g = 0xFF;
    890    surface->map->info.b = 0xFF;
    891    surface->map->info.a = 0xFF;
    892    surface->map->info.flags = 0;
    893    SDL_InvalidateMap(surface->map);
    894
    895    /* Copy over the image data */
    896    bounds.x = 0;
    897    bounds.y = 0;
    898    bounds.w = surface->w;
    899    bounds.h = surface->h;
    900    SDL_LowerBlit(surface, &bounds, convert, &bounds);
    901
    902    /* Clean up the original surface, and update converted surface */
    903    convert->map->info.r = copy_color.r;
    904    convert->map->info.g = copy_color.g;
    905    convert->map->info.b = copy_color.b;
    906    convert->map->info.a = copy_color.a;
    907    convert->map->info.flags =
    908        (copy_flags &
    909         ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
    910           | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
    911           SDL_COPY_RLE_ALPHAKEY));
    912    surface->map->info.r = copy_color.r;
    913    surface->map->info.g = copy_color.g;
    914    surface->map->info.b = copy_color.b;
    915    surface->map->info.a = copy_color.a;
    916    surface->map->info.flags = copy_flags;
    917    SDL_InvalidateMap(surface->map);
    918    if (copy_flags & SDL_COPY_COLORKEY) {
    919        SDL_bool set_colorkey_by_color = SDL_FALSE;
    920
    921        if (surface->format->palette) {
    922            if (format->palette &&
    923                surface->format->palette->ncolors <= format->palette->ncolors &&
    924                (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
    925                  surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
    926                /* The palette is identical, just set the same colorkey */
    927                SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
    928            } else if (format->Amask) {
    929                /* The alpha was set in the destination from the palette */
    930            } else {
    931                set_colorkey_by_color = SDL_TRUE;
    932            }
    933        } else {
    934            set_colorkey_by_color = SDL_TRUE;
    935        }
    936
    937        if (set_colorkey_by_color) {
    938            /* Set the colorkey by color, which needs to be unique */
    939            Uint8 keyR, keyG, keyB, keyA;
    940
    941            SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
    942                        &keyG, &keyB, &keyA);
    943            SDL_SetColorKey(convert, 1,
    944                            SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
    945            /* This is needed when converting for 3D texture upload */
    946            SDL_ConvertColorkeyToAlpha(convert);
    947        }
    948    }
    949    SDL_SetClipRect(convert, &surface->clip_rect);
    950
    951    /* Enable alpha blending by default if the new surface has an
    952     * alpha channel or alpha modulation */
    953    if ((surface->format->Amask && format->Amask) ||
    954        (copy_flags & (SDL_COPY_COLORKEY|SDL_COPY_MODULATE_ALPHA))) {
    955        SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
    956    }
    957    if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
    958        SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
    959    }
    960
    961    /* We're ready to go! */
    962    return (convert);
    963}
    964
    965SDL_Surface *
    966SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
    967                         Uint32 flags)
    968{
    969    SDL_PixelFormat *fmt;
    970    SDL_Surface *convert = NULL;
    971
    972    fmt = SDL_AllocFormat(pixel_format);
    973    if (fmt) {
    974        convert = SDL_ConvertSurface(surface, fmt, flags);
    975        SDL_FreeFormat(fmt);
    976    }
    977    return convert;
    978}
    979
    980/*
    981 * Create a surface on the stack for quick blit operations
    982 */
    983static SDL_INLINE SDL_bool
    984SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
    985                         void * pixels, int pitch, SDL_Surface * surface,
    986                         SDL_PixelFormat * format, SDL_BlitMap * blitmap)
    987{
    988    if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
    989        SDL_SetError("Indexed pixel formats not supported");
    990        return SDL_FALSE;
    991    }
    992    if (SDL_InitFormat(format, pixel_format) < 0) {
    993        return SDL_FALSE;
    994    }
    995
    996    SDL_zerop(surface);
    997    surface->flags = SDL_PREALLOC;
    998    surface->format = format;
    999    surface->pixels = pixels;
   1000    surface->w = width;
   1001    surface->h = height;
   1002    surface->pitch = pitch;
   1003    /* We don't actually need to set up the clip rect for our purposes */
   1004    /* SDL_SetClipRect(surface, NULL); */
   1005
   1006    /* Allocate an empty mapping */
   1007    SDL_zerop(blitmap);
   1008    blitmap->info.r = 0xFF;
   1009    blitmap->info.g = 0xFF;
   1010    blitmap->info.b = 0xFF;
   1011    blitmap->info.a = 0xFF;
   1012    surface->map = blitmap;
   1013
   1014    /* The surface is ready to go */
   1015    surface->refcount = 1;
   1016    return SDL_TRUE;
   1017}
   1018
   1019/*
   1020 * Copy a block of pixels of one format to another format
   1021 */
   1022int SDL_ConvertPixels(int width, int height,
   1023                      Uint32 src_format, const void * src, int src_pitch,
   1024                      Uint32 dst_format, void * dst, int dst_pitch)
   1025{
   1026    SDL_Surface src_surface, dst_surface;
   1027    SDL_PixelFormat src_fmt, dst_fmt;
   1028    SDL_BlitMap src_blitmap, dst_blitmap;
   1029    SDL_Rect rect;
   1030    void *nonconst_src = (void *) src;
   1031
   1032    /* Check to make sure we are blitting somewhere, so we don't crash */
   1033    if (!dst) {
   1034        return SDL_InvalidParamError("dst");
   1035    }
   1036    if (!dst_pitch) {
   1037        return SDL_InvalidParamError("dst_pitch");
   1038    }
   1039
   1040    /* Fast path for same format copy */
   1041    if (src_format == dst_format) {
   1042        int bpp, i;
   1043
   1044        if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   1045            switch (src_format) {
   1046            case SDL_PIXELFORMAT_YUY2:
   1047            case SDL_PIXELFORMAT_UYVY:
   1048            case SDL_PIXELFORMAT_YVYU:
   1049                bpp = 2;
   1050                break;
   1051            case SDL_PIXELFORMAT_YV12:
   1052            case SDL_PIXELFORMAT_IYUV:
   1053            case SDL_PIXELFORMAT_NV12:
   1054            case SDL_PIXELFORMAT_NV21:
   1055                bpp = 1;
   1056                break;
   1057            default:
   1058                return SDL_SetError("Unknown FOURCC pixel format");
   1059            }
   1060        } else {
   1061            bpp = SDL_BYTESPERPIXEL(src_format);
   1062        }
   1063        width *= bpp;
   1064
   1065        for (i = height; i--;) {
   1066            SDL_memcpy(dst, src, width);
   1067            src = (Uint8*)src + src_pitch;
   1068            dst = (Uint8*)dst + dst_pitch;
   1069        }
   1070
   1071        if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
   1072            /* U and V planes are a quarter the size of the Y plane */
   1073            width /= 2;
   1074            height /= 2;
   1075            src_pitch /= 2;
   1076            dst_pitch /= 2;
   1077            for (i = height * 2; i--;) {
   1078                SDL_memcpy(dst, src, width);
   1079                src = (Uint8*)src + src_pitch;
   1080                dst = (Uint8*)dst + dst_pitch;
   1081            }
   1082        } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
   1083            /* U/V plane is half the height of the Y plane */
   1084            height /= 2;
   1085            for (i = height; i--;) {
   1086                SDL_memcpy(dst, src, width);
   1087                src = (Uint8*)src + src_pitch;
   1088                dst = (Uint8*)dst + dst_pitch;
   1089            }
   1090        }
   1091        return 0;
   1092    }
   1093
   1094    if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
   1095                                  src_pitch,
   1096                                  &src_surface, &src_fmt, &src_blitmap)) {
   1097        return -1;
   1098    }
   1099    if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
   1100                                  &dst_surface, &dst_fmt, &dst_blitmap)) {
   1101        return -1;
   1102    }
   1103
   1104    /* Set up the rect and go! */
   1105    rect.x = 0;
   1106    rect.y = 0;
   1107    rect.w = width;
   1108    rect.h = height;
   1109    return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
   1110}
   1111
   1112/*
   1113 * Free a surface created by the above function.
   1114 */
   1115void
   1116SDL_FreeSurface(SDL_Surface * surface)
   1117{
   1118    if (surface == NULL) {
   1119        return;
   1120    }
   1121    if (surface->flags & SDL_DONTFREE) {
   1122        return;
   1123    }
   1124    if (--surface->refcount > 0) {
   1125        return;
   1126    }
   1127    while (surface->locked > 0) {
   1128        SDL_UnlockSurface(surface);
   1129    }
   1130    if (surface->flags & SDL_RLEACCEL) {
   1131        SDL_UnRLESurface(surface, 0);
   1132    }
   1133    if (surface->format) {
   1134        SDL_SetSurfacePalette(surface, NULL);
   1135        SDL_FreeFormat(surface->format);
   1136        surface->format = NULL;
   1137    }
   1138    if (surface->map != NULL) {
   1139        SDL_FreeBlitMap(surface->map);
   1140        surface->map = NULL;
   1141    }
   1142    if (!(surface->flags & SDL_PREALLOC)) {
   1143        SDL_free(surface->pixels);
   1144    }
   1145    SDL_free(surface);
   1146}
   1147
   1148/* vi: set ts=4 sw=4 expandtab: */