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