src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 08 Aug 2013 02:30:32 -0700
changeset 7601 fdf89883bbaa
parent 7511 4ce3cc948a00
child 7602 9829fb1aeac7
permissions -rw-r--r--
Fixed bug 2009 - Creating texture from 32-bit surface with colorkey and per-surface alpha ignores the colorkey

To fix this we need to ignore the alpha channel in the colorkey comparison, which is the way colorkey comparisons are defined in SDL.

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