src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 04 Sep 2017 11:46:14 -0700
changeset 11448 52dcef74bdc5
parent 11289 ca3c2c98f2e1
child 11496 3d1698bc2747
permissions -rw-r--r--
Fixed bug 3790 - Memory leak with surfaces blitting on each other

bastien.bouclet

When creating two surfaces and blitting them onto the other, SDL's internal reference counting fails, and one of the surfaces is not freed when calling SDL_FreeSurface.

Example code :

SDL_Surface *s1 = SDL_CreateRGBSurfaceWithFormat(0, 640, 480, 32, SDL_PIXELFORMAT_ARGB8888);
SDL_Surface *s2 = SDL_CreateRGBSurfaceWithFormat(0, 640, 480, 32, SDL_PIXELFORMAT_ARGB8888);

SDL_BlitSurface(s1, NULL, s2, NULL);
SDL_BlitSurface(s2, NULL, s1, NULL);

SDL_FreeSurface(s2);
SDL_FreeSurface(s1);

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