src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 02 Dec 2008 17:14:04 +0000
changeset 2824 4dba7aa7ea77
parent 2807 365fe1a2aad5
child 2853 6258fa7cd300
permissions -rw-r--r--
Added slow but complete blit fallback
Don't try to RLE encode surfaces that have alpha channel and alpha modulation
Don't turn on blending when converting an RGB surface to RGBA format
Do turn on blending when converting colorkey to alpha channel
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
#include "SDL_video.h"
slouken@1895
    25
#include "SDL_compat.h"
slouken@0
    26
#include "SDL_sysvideo.h"
slouken@0
    27
#include "SDL_blit.h"
slouken@0
    28
#include "SDL_RLEaccel_c.h"
slouken@0
    29
#include "SDL_pixels_c.h"
slouken@0
    30
#include "SDL_leaks.h"
slouken@0
    31
icculus@1251
    32
slouken@0
    33
/* Public routines */
slouken@0
    34
/*
slouken@0
    35
 * Create an empty RGB surface of the appropriate depth
slouken@0
    36
 */
slouken@1895
    37
SDL_Surface *
slouken@1895
    38
SDL_CreateRGBSurface(Uint32 flags,
slouken@1895
    39
                     int width, int height, int depth,
slouken@1895
    40
                     Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
slouken@0
    41
{
slouken@1895
    42
    SDL_Surface *surface;
slouken@0
    43
slouken@2807
    44
    /* The flags are no longer used, make the compiler happy */
slouken@2807
    45
    flags;
slouken@2807
    46
slouken@1895
    47
    /* Allocate the surface */
slouken@1920
    48
    surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
slouken@1895
    49
    if (surface == NULL) {
slouken@1895
    50
        SDL_OutOfMemory();
slouken@1895
    51
        return NULL;
slouken@1895
    52
    }
slouken@940
    53
slouken@1895
    54
    surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
slouken@1895
    55
    if (!surface->format) {
slouken@1895
    56
        SDL_FreeSurface(surface);
slouken@1895
    57
        return NULL;
slouken@1895
    58
    }
slouken@1895
    59
    surface->w = width;
slouken@1895
    60
    surface->h = height;
slouken@1895
    61
    surface->pitch = SDL_CalculatePitch(surface);
slouken@1895
    62
    SDL_SetClipRect(surface, NULL);
slouken@0
    63
slouken@1895
    64
    if (surface->format->BitsPerPixel <= 8) {
slouken@1895
    65
        SDL_Palette *palette =
slouken@1895
    66
            SDL_AllocPalette((1 << surface->format->BitsPerPixel));
slouken@1895
    67
        if (!palette) {
slouken@1895
    68
            SDL_FreeSurface(surface);
slouken@1895
    69
            return NULL;
slouken@1895
    70
        }
slouken@1895
    71
        if (Rmask || Bmask || Gmask) {
slouken@1895
    72
            const SDL_PixelFormat *format = surface->format;
slouken@0
    73
slouken@1895
    74
            /* create palette according to masks */
slouken@1895
    75
            int i;
slouken@1895
    76
            int Rm = 0, Gm = 0, Bm = 0;
slouken@1895
    77
            int Rw = 0, Gw = 0, Bw = 0;
slouken@0
    78
slouken@1895
    79
            if (Rmask) {
slouken@1895
    80
                Rw = 8 - format->Rloss;
slouken@1895
    81
                for (i = format->Rloss; i > 0; i -= Rw)
slouken@1895
    82
                    Rm |= 1 << i;
slouken@1895
    83
            }
slouken@1895
    84
            if (Gmask) {
slouken@1895
    85
                Gw = 8 - format->Gloss;
slouken@1895
    86
                for (i = format->Gloss; i > 0; i -= Gw)
slouken@1895
    87
                    Gm |= 1 << i;
slouken@1895
    88
            }
slouken@1895
    89
            if (Bmask) {
slouken@1895
    90
                Bw = 8 - format->Bloss;
slouken@1895
    91
                for (i = format->Bloss; i > 0; i -= Bw)
slouken@1895
    92
                    Bm |= 1 << i;
slouken@1895
    93
            }
slouken@1895
    94
            for (i = 0; i < palette->ncolors; ++i) {
slouken@1895
    95
                int r, g, b;
slouken@1895
    96
                r = (i & Rmask) >> format->Rshift;
slouken@1895
    97
                r = (r << format->Rloss) | ((r * Rm) >> Rw);
slouken@1895
    98
                palette->colors[i].r = r;
slouken@0
    99
slouken@1895
   100
                g = (i & Gmask) >> format->Gshift;
slouken@1895
   101
                g = (g << format->Gloss) | ((g * Gm) >> Gw);
slouken@1895
   102
                palette->colors[i].g = g;
slouken@1895
   103
slouken@1895
   104
                b = (i & Bmask) >> format->Bshift;
slouken@1895
   105
                b = (b << format->Bloss) | ((b * Bm) >> Bw);
slouken@1895
   106
                palette->colors[i].b = b;
slouken@1895
   107
            }
slouken@1895
   108
        } else if (palette->ncolors == 2) {
slouken@1895
   109
            /* Create a black and white bitmap palette */
slouken@1895
   110
            palette->colors[0].r = 0xFF;
slouken@1895
   111
            palette->colors[0].g = 0xFF;
slouken@1895
   112
            palette->colors[0].b = 0xFF;
slouken@1895
   113
            palette->colors[1].r = 0x00;
slouken@1895
   114
            palette->colors[1].g = 0x00;
slouken@1895
   115
            palette->colors[1].b = 0x00;
slouken@1895
   116
        }
slouken@1895
   117
        SDL_SetSurfacePalette(surface, palette);
slouken@1895
   118
        SDL_FreePalette(palette);
slouken@1895
   119
    }
slouken@1895
   120
slouken@1895
   121
    /* Get the pixels */
slouken@1895
   122
    if (surface->w && surface->h) {
slouken@1895
   123
        surface->pixels = SDL_malloc(surface->h * surface->pitch);
slouken@1895
   124
        if (!surface->pixels) {
slouken@1895
   125
            SDL_FreeSurface(surface);
slouken@1895
   126
            SDL_OutOfMemory();
slouken@1895
   127
            return NULL;
slouken@1895
   128
        }
slouken@1895
   129
        /* This is important for bitmaps */
slouken@1895
   130
        SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
slouken@1895
   131
    }
slouken@1895
   132
slouken@1895
   133
    /* Allocate an empty mapping */
slouken@1895
   134
    surface->map = SDL_AllocBlitMap();
slouken@1895
   135
    if (!surface->map) {
slouken@1895
   136
        SDL_FreeSurface(surface);
slouken@1895
   137
        return NULL;
slouken@1895
   138
    }
slouken@1895
   139
    SDL_FormatChanged(surface);
slouken@1895
   140
slouken@2267
   141
    /* By default surface with an alpha mask are set up for blending */
slouken@2267
   142
    if (Amask) {
slouken@2267
   143
        SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND);
slouken@2267
   144
    }
slouken@2267
   145
slouken@1895
   146
    /* The surface is ready to go */
slouken@1895
   147
    surface->refcount = 1;
slouken@0
   148
#ifdef CHECK_LEAKS
slouken@1895
   149
    ++surfaces_allocated;
slouken@0
   150
#endif
slouken@1895
   151
    return surface;
slouken@0
   152
}
slouken@1895
   153
slouken@0
   154
/*
slouken@0
   155
 * Create an RGB surface from an existing memory buffer
slouken@0
   156
 */
slouken@1895
   157
SDL_Surface *
slouken@1895
   158
SDL_CreateRGBSurfaceFrom(void *pixels,
slouken@1895
   159
                         int width, int height, int depth, int pitch,
slouken@1895
   160
                         Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
slouken@1895
   161
                         Uint32 Amask)
slouken@0
   162
{
slouken@1895
   163
    SDL_Surface *surface;
slouken@0
   164
slouken@1895
   165
    surface =
slouken@1895
   166
        SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
slouken@1895
   167
    if (surface != NULL) {
slouken@1895
   168
        surface->flags |= SDL_PREALLOC;
slouken@1895
   169
        surface->pixels = pixels;
slouken@1895
   170
        surface->w = width;
slouken@1895
   171
        surface->h = height;
slouken@1895
   172
        surface->pitch = pitch;
slouken@1895
   173
        SDL_SetClipRect(surface, NULL);
slouken@1895
   174
    }
slouken@1895
   175
    return surface;
slouken@0
   176
}
slouken@1895
   177
slouken@1895
   178
static int
slouken@1895
   179
SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
slouken@1895
   180
{
slouken@1895
   181
    SDL_Surface *surface = (SDL_Surface *) userdata;
slouken@1895
   182
slouken@1895
   183
    SDL_FormatChanged(surface);
slouken@1895
   184
slouken@1895
   185
    return 0;
slouken@1895
   186
}
slouken@1895
   187
slouken@1895
   188
int
slouken@1895
   189
SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
slouken@1895
   190
{
slouken@1895
   191
    if (!surface || !surface->format) {
slouken@1895
   192
        SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
slouken@1895
   193
        return -1;
slouken@1895
   194
    }
slouken@1895
   195
slouken@1895
   196
    if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
slouken@1895
   197
        SDL_SetError
slouken@1895
   198
            ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
slouken@1895
   199
        return -1;
slouken@1895
   200
    }
slouken@1895
   201
slouken@1895
   202
    if (surface->format->palette == palette) {
slouken@1895
   203
        return 0;
slouken@1895
   204
    }
slouken@1895
   205
slouken@1895
   206
    if (surface->format->palette) {
slouken@1895
   207
        SDL_DelPaletteWatch(surface->format->palette,
slouken@1895
   208
                            SDL_SurfacePaletteChanged, surface);
slouken@1895
   209
    }
slouken@1895
   210
slouken@1895
   211
    surface->format->palette = palette;
slouken@1895
   212
slouken@1895
   213
    if (surface->format->palette) {
slouken@1895
   214
        SDL_AddPaletteWatch(surface->format->palette,
slouken@1895
   215
                            SDL_SurfacePaletteChanged, surface);
slouken@1895
   216
    }
slouken@1895
   217
    return 0;
slouken@1895
   218
}
slouken@1895
   219
slouken@2267
   220
int
slouken@2267
   221
SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
slouken@0
   222
{
slouken@2267
   223
    int flags;
slouken@0
   224
slouken@2266
   225
    if (!surface) {
slouken@2266
   226
        return -1;
slouken@1895
   227
    }
slouken@0
   228
slouken@2267
   229
    flags = surface->map->info.flags;
slouken@1895
   230
    if (flag) {
slouken@2267
   231
        surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
slouken@1895
   232
    } else {
slouken@2267
   233
        surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
slouken@1895
   234
    }
slouken@2267
   235
    if (surface->map->info.flags != flags) {
slouken@1895
   236
        SDL_InvalidateMap(surface->map);
slouken@1895
   237
    }
slouken@1895
   238
    return 0;
slouken@431
   239
}
slouken@0
   240
slouken@2267
   241
int
slouken@2267
   242
SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
slouken@2266
   243
{
slouken@2266
   244
    int flags;
slouken@2266
   245
slouken@2266
   246
    if (!surface) {
slouken@2266
   247
        return -1;
slouken@2266
   248
    }
slouken@2266
   249
slouken@2266
   250
    if (flag & SDL_RLEACCEL) {
slouken@2266
   251
        SDL_SetSurfaceRLE(surface, 1);
slouken@2266
   252
    }
slouken@2266
   253
slouken@2266
   254
    flags = surface->map->info.flags;
slouken@2266
   255
    if (flag) {
slouken@2266
   256
        surface->map->info.flags |= SDL_COPY_COLORKEY;
slouken@2266
   257
        surface->map->info.colorkey = key;
slouken@2266
   258
    } else {
slouken@2266
   259
        surface->map->info.flags &= ~SDL_COPY_COLORKEY;
slouken@2266
   260
    }
slouken@2266
   261
    if (surface->map->info.flags != flags) {
slouken@2266
   262
        SDL_InvalidateMap(surface->map);
slouken@2266
   263
    }
slouken@2267
   264
slouken@2267
   265
    /* Compatibility mode */
slouken@2267
   266
    if (surface->map->info.flags & SDL_COPY_COLORKEY) {
slouken@2267
   267
        surface->flags |= SDL_SRCCOLORKEY;
slouken@2267
   268
    } else {
slouken@2267
   269
        surface->flags &= ~SDL_SRCCOLORKEY;
slouken@2267
   270
    }
slouken@2267
   271
slouken@2266
   272
    return 0;
slouken@2266
   273
}
slouken@2266
   274
slouken@2785
   275
/* This is a fairly slow function to switch from colorkey to alpha */
slouken@2787
   276
static void
slouken@2786
   277
SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
slouken@2785
   278
{
slouken@2786
   279
    int x, y;
slouken@2785
   280
slouken@2786
   281
    if (!surface) {
slouken@2786
   282
        return;
slouken@2786
   283
    }
slouken@2785
   284
slouken@2786
   285
    if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
slouken@2786
   286
        !surface->format->Amask) {
slouken@2786
   287
        return;
slouken@2786
   288
    }
slouken@2785
   289
slouken@2786
   290
    SDL_LockSurface(surface);
slouken@2785
   291
slouken@2786
   292
    switch (surface->format->BytesPerPixel) {
slouken@2786
   293
    case 2:
slouken@2786
   294
        {
slouken@2786
   295
            Uint16 *row, *spot;
slouken@2786
   296
            Uint16 ckey = (Uint16) surface->map->info.colorkey;
slouken@2786
   297
            Uint16 mask = (Uint16) (~surface->format->Amask);
slouken@2785
   298
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@2786
   303
                    if (*spot == 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@2786
   321
            row = (Uint32 *) surface->pixels;
slouken@2786
   322
            for (y = surface->h; y--;) {
slouken@2786
   323
                spot = row;
slouken@2786
   324
                for (x = surface->w; x--;) {
slouken@2786
   325
                    if (*spot == ckey) {
slouken@2786
   326
                        *spot &= mask;
slouken@2786
   327
                    }
slouken@2786
   328
                    ++spot;
slouken@2786
   329
                }
slouken@2786
   330
                row += surface->pitch / 4;
slouken@2786
   331
            }
slouken@2786
   332
        }
slouken@2786
   333
        break;
slouken@2786
   334
    }
slouken@2785
   335
slouken@2786
   336
    SDL_UnlockSurface(surface);
slouken@2785
   337
slouken@2786
   338
    SDL_SetColorKey(surface, 0, 0);
slouken@2824
   339
    SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND);
slouken@2785
   340
}
slouken@2785
   341
slouken@2267
   342
int
slouken@2267
   343
SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
slouken@2266
   344
{
slouken@2266
   345
    int flags;
slouken@2266
   346
slouken@2266
   347
    if (!surface) {
slouken@2266
   348
        return -1;
slouken@2266
   349
    }
slouken@2266
   350
slouken@2266
   351
    surface->map->info.r = r;
slouken@2266
   352
    surface->map->info.g = g;
slouken@2266
   353
    surface->map->info.b = b;
slouken@2266
   354
slouken@2266
   355
    flags = surface->map->info.flags;
slouken@2266
   356
    if (r != 0xFF || g != 0xFF || b != 0xFF) {
slouken@2266
   357
        surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
slouken@2266
   358
    } else {
slouken@2266
   359
        surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
slouken@2266
   360
    }
slouken@2266
   361
    if (surface->map->info.flags != flags) {
slouken@2266
   362
        SDL_InvalidateMap(surface->map);
slouken@2266
   363
    }
slouken@2266
   364
    return 0;
slouken@2266
   365
}
slouken@2266
   366
slouken@2266
   367
slouken@2267
   368
int
slouken@2267
   369
SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
slouken@2266
   370
{
slouken@2266
   371
    if (!surface) {
slouken@2266
   372
        return -1;
slouken@2266
   373
    }
slouken@2266
   374
slouken@2266
   375
    if (r) {
slouken@2266
   376
        *r = surface->map->info.r;
slouken@2266
   377
    }
slouken@2266
   378
    if (g) {
slouken@2266
   379
        *g = surface->map->info.g;
slouken@2266
   380
    }
slouken@2266
   381
    if (b) {
slouken@2266
   382
        *b = surface->map->info.b;
slouken@2266
   383
    }
slouken@2266
   384
    return 0;
slouken@2266
   385
}
slouken@2266
   386
slouken@2267
   387
int
slouken@2267
   388
SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
slouken@2266
   389
{
slouken@2266
   390
    int flags;
slouken@2266
   391
slouken@2266
   392
    if (!surface) {
slouken@2266
   393
        return -1;
slouken@2266
   394
    }
slouken@2266
   395
slouken@2266
   396
    surface->map->info.a = alpha;
slouken@2266
   397
slouken@2266
   398
    flags = surface->map->info.flags;
slouken@2266
   399
    if (alpha != 0xFF) {
slouken@2266
   400
        surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
slouken@2266
   401
    } else {
slouken@2266
   402
        surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
slouken@2266
   403
    }
slouken@2266
   404
    if (surface->map->info.flags != flags) {
slouken@2266
   405
        SDL_InvalidateMap(surface->map);
slouken@2266
   406
    }
slouken@2266
   407
    return 0;
slouken@2266
   408
}
slouken@2266
   409
slouken@2267
   410
int
slouken@2267
   411
SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
slouken@2266
   412
{
slouken@2266
   413
    if (!surface) {
slouken@2266
   414
        return -1;
slouken@2266
   415
    }
slouken@2266
   416
slouken@2266
   417
    if (alpha) {
slouken@2266
   418
        *alpha = surface->map->info.a;
slouken@2266
   419
    }
slouken@2266
   420
    return 0;
slouken@2266
   421
}
slouken@2266
   422
slouken@2267
   423
int
slouken@2267
   424
SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
slouken@2266
   425
{
slouken@2266
   426
    int flags, status;
slouken@2266
   427
slouken@2266
   428
    if (!surface) {
slouken@2266
   429
        return -1;
slouken@2266
   430
    }
slouken@2266
   431
slouken@2266
   432
    status = 0;
slouken@2266
   433
    flags = surface->map->info.flags;
slouken@2267
   434
    surface->map->info.flags &=
slouken@2267
   435
        ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
slouken@2266
   436
    switch (blendMode) {
slouken@2266
   437
    case SDL_TEXTUREBLENDMODE_NONE:
slouken@2266
   438
        break;
slouken@2266
   439
    case SDL_TEXTUREBLENDMODE_MASK:
slouken@2266
   440
        surface->map->info.flags |= SDL_COPY_MASK;
slouken@2266
   441
        break;
slouken@2266
   442
    case SDL_TEXTUREBLENDMODE_BLEND:
slouken@2266
   443
        surface->map->info.flags |= SDL_COPY_BLEND;
slouken@2266
   444
        break;
slouken@2266
   445
    case SDL_TEXTUREBLENDMODE_ADD:
slouken@2266
   446
        surface->map->info.flags |= SDL_COPY_ADD;
slouken@2266
   447
        break;
slouken@2266
   448
    case SDL_TEXTUREBLENDMODE_MOD:
slouken@2266
   449
        surface->map->info.flags |= SDL_COPY_MOD;
slouken@2266
   450
        break;
slouken@2266
   451
    default:
slouken@2266
   452
        SDL_Unsupported();
slouken@2266
   453
        status = -1;
slouken@2266
   454
        break;
slouken@2266
   455
    }
slouken@2266
   456
slouken@2266
   457
    if (surface->map->info.flags != flags) {
slouken@2266
   458
        SDL_InvalidateMap(surface->map);
slouken@2266
   459
    }
slouken@2267
   460
slouken@2267
   461
    /* Compatibility mode */
slouken@2267
   462
    if (surface->map->info.flags & SDL_COPY_BLEND) {
slouken@2267
   463
        surface->flags |= SDL_SRCALPHA;
slouken@2267
   464
    } else {
slouken@2267
   465
        surface->flags &= ~SDL_SRCALPHA;
slouken@2267
   466
    }
slouken@2267
   467
slouken@2266
   468
    return status;
slouken@2266
   469
}
slouken@2266
   470
slouken@2267
   471
int
slouken@2267
   472
SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
slouken@2266
   473
{
slouken@2266
   474
    if (!surface) {
slouken@2266
   475
        return -1;
slouken@2266
   476
    }
slouken@2266
   477
slouken@2266
   478
    if (!blendMode) {
slouken@2266
   479
        return 0;
slouken@2266
   480
    }
slouken@2266
   481
slouken@2735
   482
    switch (surface->map->
slouken@2735
   483
            info.flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
slouken@2735
   484
                          SDL_COPY_MOD)) {
slouken@2266
   485
    case SDL_COPY_MASK:
slouken@2267
   486
        *blendMode = SDL_TEXTUREBLENDMODE_MASK;
slouken@2266
   487
        break;
slouken@2266
   488
    case SDL_COPY_BLEND:
slouken@2267
   489
        *blendMode = SDL_TEXTUREBLENDMODE_BLEND;
slouken@2266
   490
        break;
slouken@2266
   491
    case SDL_COPY_ADD:
slouken@2267
   492
        *blendMode = SDL_TEXTUREBLENDMODE_ADD;
slouken@2266
   493
        break;
slouken@2266
   494
    case SDL_COPY_MOD:
slouken@2267
   495
        *blendMode = SDL_TEXTUREBLENDMODE_MOD;
slouken@2266
   496
        break;
slouken@2266
   497
    default:
slouken@2267
   498
        *blendMode = SDL_TEXTUREBLENDMODE_NONE;
slouken@2266
   499
        break;
slouken@2266
   500
    }
slouken@2266
   501
    return 0;
slouken@2266
   502
}
slouken@2266
   503
slouken@2267
   504
int
slouken@2267
   505
SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
slouken@2266
   506
{
slouken@2266
   507
    int flags, status;
slouken@2266
   508
slouken@2266
   509
    if (!surface) {
slouken@2266
   510
        return -1;
slouken@2266
   511
    }
slouken@2266
   512
slouken@2266
   513
    status = 0;
slouken@2266
   514
    flags = surface->map->info.flags;
slouken@2266
   515
    surface->map->info.flags &= ~(SDL_COPY_NEAREST);
slouken@2266
   516
    switch (scaleMode) {
slouken@2266
   517
    case SDL_TEXTURESCALEMODE_NONE:
slouken@2266
   518
        break;
slouken@2266
   519
    case SDL_TEXTURESCALEMODE_FAST:
slouken@2266
   520
        surface->map->info.flags |= SDL_COPY_NEAREST;
slouken@2266
   521
        break;
slouken@2266
   522
    case SDL_TEXTURESCALEMODE_SLOW:
slouken@2266
   523
    case SDL_TEXTURESCALEMODE_BEST:
slouken@2266
   524
        SDL_Unsupported();
slouken@2266
   525
        surface->map->info.flags |= SDL_COPY_NEAREST;
slouken@2266
   526
        status = -1;
slouken@2266
   527
        break;
slouken@2266
   528
    default:
slouken@2266
   529
        SDL_Unsupported();
slouken@2266
   530
        status = -1;
slouken@2266
   531
        break;
slouken@2266
   532
    }
slouken@2266
   533
slouken@2266
   534
    if (surface->map->info.flags != flags) {
slouken@2266
   535
        SDL_InvalidateMap(surface->map);
slouken@2266
   536
    }
slouken@2266
   537
    return status;
slouken@2266
   538
}
slouken@2266
   539
slouken@2267
   540
int
slouken@2267
   541
SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
slouken@2266
   542
{
slouken@2266
   543
    if (!surface) {
slouken@2266
   544
        return -1;
slouken@2266
   545
    }
slouken@2266
   546
slouken@2266
   547
    if (!scaleMode) {
slouken@2266
   548
        return 0;
slouken@2266
   549
    }
slouken@2266
   550
slouken@2267
   551
    switch (surface->map->info.flags & (SDL_COPY_NEAREST)) {
slouken@2267
   552
    case SDL_COPY_NEAREST:
slouken@2267
   553
        *scaleMode = SDL_TEXTURESCALEMODE_FAST;
slouken@2266
   554
        break;
slouken@2266
   555
    default:
slouken@2267
   556
        *scaleMode = SDL_TEXTURESCALEMODE_NONE;
slouken@2266
   557
        break;
slouken@2266
   558
    }
slouken@2266
   559
    return 0;
slouken@2266
   560
}
slouken@2266
   561
slouken@1895
   562
SDL_bool
slouken@1895
   563
SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
slouken@0
   564
{
slouken@1895
   565
    SDL_Rect full_rect;
slouken@0
   566
slouken@1895
   567
    /* Don't do anything if there's no surface to act on */
slouken@1895
   568
    if (!surface) {
slouken@1895
   569
        return SDL_FALSE;
slouken@1895
   570
    }
slouken@0
   571
slouken@1895
   572
    /* Set up the full surface rectangle */
slouken@1895
   573
    full_rect.x = 0;
slouken@1895
   574
    full_rect.y = 0;
slouken@1895
   575
    full_rect.w = surface->w;
slouken@1895
   576
    full_rect.h = surface->h;
slouken@0
   577
slouken@1895
   578
    /* Set the clipping rectangle */
slouken@1895
   579
    if (!rect) {
slouken@1895
   580
        surface->clip_rect = full_rect;
slouken@1895
   581
        return 1;
slouken@1895
   582
    }
slouken@1895
   583
    return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
slouken@0
   584
}
slouken@1895
   585
slouken@1895
   586
void
slouken@1895
   587
SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
slouken@0
   588
{
slouken@1895
   589
    if (surface && rect) {
slouken@1895
   590
        *rect = surface->clip_rect;
slouken@1895
   591
    }
slouken@0
   592
}
slouken@1895
   593
slouken@0
   594
/* 
slouken@0
   595
 * Set up a blit between two surfaces -- split into three parts:
slouken@0
   596
 * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
slouken@0
   597
 * verification.  The lower part is a pointer to a low level
slouken@0
   598
 * accelerated blitting function.
slouken@0
   599
 *
slouken@0
   600
 * These parts are separated out and each used internally by this 
slouken@0
   601
 * library in the optimimum places.  They are exported so that if
slouken@0
   602
 * you know exactly what you are doing, you can optimize your code
slouken@0
   603
 * by calling the one(s) you need.
slouken@0
   604
 */
slouken@1895
   605
int
slouken@1895
   606
SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
slouken@1895
   607
              SDL_Surface * dst, SDL_Rect * dstrect)
slouken@0
   608
{
slouken@1895
   609
    /* Check to make sure the blit mapping is valid */
slouken@1895
   610
    if ((src->map->dst != dst) ||
slouken@1895
   611
        (src->map->dst->format_version != src->map->format_version)) {
slouken@1895
   612
        if (SDL_MapSurface(src, dst) < 0) {
slouken@1895
   613
            return (-1);
slouken@1895
   614
        }
bob@2328
   615
        /* just here for debugging */
bob@2329
   616
/*         printf */
bob@2329
   617
/*             ("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
   618
/*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
bob@2329
   619
/*              dst->map->info.flags, src->map->blit); */
slouken@1895
   620
    }
slouken@2257
   621
    return (src->map->blit(src, srcrect, dst, dstrect));
slouken@0
   622
}
slouken@0
   623
slouken@0
   624
slouken@1895
   625
int
slouken@1895
   626
SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
slouken@1895
   627
              SDL_Surface * dst, SDL_Rect * dstrect)
slouken@0
   628
{
slouken@1895
   629
    SDL_Rect fulldst;
slouken@1895
   630
    int srcx, srcy, w, h;
slouken@0
   631
slouken@1895
   632
    /* Make sure the surfaces aren't locked */
slouken@1895
   633
    if (!src || !dst) {
slouken@1895
   634
        SDL_SetError("SDL_UpperBlit: passed a NULL surface");
slouken@1895
   635
        return (-1);
slouken@1895
   636
    }
slouken@1895
   637
    if (src->locked || dst->locked) {
slouken@1895
   638
        SDL_SetError("Surfaces must not be locked during blit");
slouken@1895
   639
        return (-1);
slouken@1895
   640
    }
slouken@0
   641
slouken@1895
   642
    /* If the destination rectangle is NULL, use the entire dest surface */
slouken@1895
   643
    if (dstrect == NULL) {
slouken@1895
   644
        fulldst.x = fulldst.y = 0;
slouken@1895
   645
        dstrect = &fulldst;
slouken@1895
   646
    }
slouken@0
   647
slouken@1895
   648
    /* clip the source rectangle to the source surface */
slouken@1895
   649
    if (srcrect) {
slouken@1895
   650
        int maxw, maxh;
slouken@0
   651
slouken@1895
   652
        srcx = srcrect->x;
slouken@1895
   653
        w = srcrect->w;
slouken@1895
   654
        if (srcx < 0) {
slouken@1895
   655
            w += srcx;
slouken@1895
   656
            dstrect->x -= srcx;
slouken@1895
   657
            srcx = 0;
slouken@1895
   658
        }
slouken@1895
   659
        maxw = src->w - srcx;
slouken@1895
   660
        if (maxw < w)
slouken@1895
   661
            w = maxw;
slouken@0
   662
slouken@1895
   663
        srcy = srcrect->y;
slouken@1895
   664
        h = srcrect->h;
slouken@1895
   665
        if (srcy < 0) {
slouken@1895
   666
            h += srcy;
slouken@1895
   667
            dstrect->y -= srcy;
slouken@1895
   668
            srcy = 0;
slouken@1895
   669
        }
slouken@1895
   670
        maxh = src->h - srcy;
slouken@1895
   671
        if (maxh < h)
slouken@1895
   672
            h = maxh;
slouken@0
   673
slouken@1895
   674
    } else {
slouken@1895
   675
        srcx = srcy = 0;
slouken@1895
   676
        w = src->w;
slouken@1895
   677
        h = src->h;
slouken@1895
   678
    }
slouken@0
   679
slouken@1895
   680
    /* clip the destination rectangle against the clip rectangle */
slouken@1895
   681
    {
slouken@1895
   682
        SDL_Rect *clip = &dst->clip_rect;
slouken@1895
   683
        int dx, dy;
slouken@0
   684
slouken@1895
   685
        dx = clip->x - dstrect->x;
slouken@1895
   686
        if (dx > 0) {
slouken@1895
   687
            w -= dx;
slouken@1895
   688
            dstrect->x += dx;
slouken@1895
   689
            srcx += dx;
slouken@1895
   690
        }
slouken@1895
   691
        dx = dstrect->x + w - clip->x - clip->w;
slouken@1895
   692
        if (dx > 0)
slouken@1895
   693
            w -= dx;
slouken@1895
   694
slouken@1895
   695
        dy = clip->y - dstrect->y;
slouken@1895
   696
        if (dy > 0) {
slouken@1895
   697
            h -= dy;
slouken@1895
   698
            dstrect->y += dy;
slouken@1895
   699
            srcy += dy;
slouken@1895
   700
        }
slouken@1895
   701
        dy = dstrect->y + h - clip->y - clip->h;
slouken@1895
   702
        if (dy > 0)
slouken@1895
   703
            h -= dy;
slouken@1895
   704
    }
slouken@1895
   705
slouken@1895
   706
    if (w > 0 && h > 0) {
slouken@1895
   707
        SDL_Rect sr;
slouken@1895
   708
        sr.x = srcx;
slouken@1895
   709
        sr.y = srcy;
slouken@1895
   710
        sr.w = dstrect->w = w;
slouken@1895
   711
        sr.h = dstrect->h = h;
slouken@1895
   712
        return SDL_LowerBlit(src, &sr, dst, dstrect);
slouken@1895
   713
    }
slouken@1895
   714
    dstrect->w = dstrect->h = 0;
slouken@1895
   715
    return 0;
slouken@0
   716
}
slouken@0
   717
slouken@0
   718
/*
slouken@0
   719
 * Lock a surface to directly access the pixels
slouken@0
   720
 */
slouken@1895
   721
int
slouken@1895
   722
SDL_LockSurface(SDL_Surface * surface)
slouken@0
   723
{
slouken@1895
   724
    if (!surface->locked) {
slouken@1895
   725
        /* Perform the lock */
slouken@1895
   726
        if (surface->flags & SDL_RLEACCEL) {
slouken@1895
   727
            SDL_UnRLESurface(surface, 1);
slouken@1895
   728
            surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
slouken@1895
   729
        }
slouken@1895
   730
    }
slouken@0
   731
slouken@1895
   732
    /* Increment the surface lock count, for recursive locks */
slouken@1895
   733
    ++surface->locked;
slouken@0
   734
slouken@1895
   735
    /* Ready to go.. */
slouken@1895
   736
    return (0);
slouken@0
   737
}
slouken@1895
   738
slouken@0
   739
/*
slouken@0
   740
 * Unlock a previously locked surface
slouken@0
   741
 */
slouken@1895
   742
void
slouken@1895
   743
SDL_UnlockSurface(SDL_Surface * surface)
slouken@0
   744
{
slouken@1895
   745
    /* Only perform an unlock if we are locked */
slouken@1895
   746
    if (!surface->locked || (--surface->locked > 0)) {
slouken@1895
   747
        return;
slouken@1895
   748
    }
slouken@0
   749
slouken@1895
   750
    /* Update RLE encoded surface with new data */
slouken@1895
   751
    if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
slouken@1895
   752
        surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
slouken@1895
   753
        SDL_RLESurface(surface);
slouken@1895
   754
    }
slouken@0
   755
}
slouken@0
   756
slouken@0
   757
/* 
slouken@0
   758
 * Convert a surface into the specified pixel format.
slouken@0
   759
 */
slouken@1895
   760
SDL_Surface *
slouken@2807
   761
SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
slouken@2807
   762
                   Uint32 flags)
slouken@0
   763
{
slouken@1895
   764
    SDL_Surface *convert;
slouken@2266
   765
    Uint32 copy_flags;
slouken@1895
   766
    SDL_Rect bounds;
slouken@0
   767
slouken@1895
   768
    /* Check for empty destination palette! (results in empty image) */
slouken@1895
   769
    if (format->palette != NULL) {
slouken@1895
   770
        int i;
slouken@1895
   771
        for (i = 0; i < format->palette->ncolors; ++i) {
slouken@1895
   772
            if ((format->palette->colors[i].r != 0xFF) ||
slouken@1895
   773
                (format->palette->colors[i].g != 0xFF) ||
slouken@1895
   774
                (format->palette->colors[i].b != 0xFF))
slouken@1895
   775
                break;
slouken@1895
   776
        }
slouken@1895
   777
        if (i == format->palette->ncolors) {
slouken@1895
   778
            SDL_SetError("Empty destination palette");
slouken@1895
   779
            return (NULL);
slouken@1895
   780
        }
slouken@1895
   781
    }
slouken@0
   782
slouken@1895
   783
    /* Create a new surface with the desired format */
slouken@2807
   784
    convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
slouken@1895
   785
                                   format->BitsPerPixel, format->Rmask,
slouken@1895
   786
                                   format->Gmask, format->Bmask,
slouken@1895
   787
                                   format->Amask);
slouken@1895
   788
    if (convert == NULL) {
slouken@1895
   789
        return (NULL);
slouken@1895
   790
    }
slouken@264
   791
slouken@1895
   792
    /* Copy the palette if any */
slouken@1895
   793
    if (format->palette && convert->format->palette) {
slouken@1895
   794
        SDL_memcpy(convert->format->palette->colors,
slouken@1895
   795
                   format->palette->colors,
slouken@1895
   796
                   format->palette->ncolors * sizeof(SDL_Color));
slouken@1895
   797
        convert->format->palette->ncolors = format->palette->ncolors;
slouken@1895
   798
    }
slouken@0
   799
slouken@2266
   800
    /* Save the original copy flags */
slouken@2266
   801
    copy_flags = surface->map->info.flags;
slouken@2266
   802
    surface->map->info.flags = 0;
slouken@0
   803
slouken@1895
   804
    /* Copy over the image data */
slouken@1895
   805
    bounds.x = 0;
slouken@1895
   806
    bounds.y = 0;
slouken@1895
   807
    bounds.w = surface->w;
slouken@1895
   808
    bounds.h = surface->h;
slouken@1895
   809
    SDL_LowerBlit(surface, &bounds, convert, &bounds);
slouken@0
   810
slouken@1895
   811
    /* Clean up the original surface, and update converted surface */
slouken@2824
   812
    convert->map->info.r = surface->map->info.r;
slouken@2824
   813
    convert->map->info.g = surface->map->info.g;
slouken@2824
   814
    convert->map->info.b = surface->map->info.b;
slouken@2824
   815
    convert->map->info.a = surface->map->info.a;
slouken@2824
   816
    convert->map->info.flags =
slouken@2824
   817
        (copy_flags &
slouken@2824
   818
         ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
slouken@2824
   819
           | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
slouken@2824
   820
           SDL_COPY_RLE_ALPHAKEY));
slouken@2824
   821
    surface->map->info.flags = copy_flags;
slouken@2266
   822
    if (copy_flags & SDL_COPY_COLORKEY) {
slouken@2266
   823
        Uint8 keyR, keyG, keyB, keyA;
slouken@2266
   824
slouken@2267
   825
        SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
slouken@2267
   826
                    &keyG, &keyB, &keyA);
slouken@2266
   827
        SDL_SetColorKey(convert, 1,
slouken@2266
   828
                        SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
slouken@2824
   829
        /* This is needed when converting for 3D texture upload */
slouken@2787
   830
        SDL_ConvertColorkeyToAlpha(convert);
slouken@1895
   831
    }
slouken@2824
   832
    SDL_SetClipRect(convert, &surface->clip_rect);
slouken@0
   833
slouken@2266
   834
    /* Enable alpha blending by default if the new surface has an
slouken@2266
   835
     * alpha channel or alpha modulation */
slouken@2824
   836
    if ((surface->format->Amask && format->Amask) ||
slouken@2824
   837
        (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
slouken@2266
   838
        SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND);
slouken@1895
   839
    }
slouken@2824
   840
    if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
slouken@2824
   841
        SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
slouken@2824
   842
    }
slouken@0
   843
slouken@1895
   844
    /* We're ready to go! */
slouken@1895
   845
    return (convert);
slouken@0
   846
}
slouken@0
   847
slouken@0
   848
/*
slouken@0
   849
 * Free a surface created by the above function.
slouken@0
   850
 */
slouken@1895
   851
void
slouken@1895
   852
SDL_FreeSurface(SDL_Surface * surface)
slouken@0
   853
{
slouken@1895
   854
    if (surface == NULL) {
slouken@1895
   855
        return;
slouken@1895
   856
    }
slouken@1895
   857
    if (--surface->refcount > 0) {
slouken@1895
   858
        return;
slouken@1895
   859
    }
slouken@1895
   860
    while (surface->locked > 0) {
slouken@1895
   861
        SDL_UnlockSurface(surface);
slouken@1895
   862
    }
slouken@1895
   863
    if (surface->flags & SDL_RLEACCEL) {
slouken@1895
   864
        SDL_UnRLESurface(surface, 0);
slouken@1895
   865
    }
slouken@1895
   866
    if (surface->format) {
slouken@1895
   867
        SDL_SetSurfacePalette(surface, NULL);
slouken@1895
   868
        SDL_FreeFormat(surface->format);
slouken@1895
   869
        surface->format = NULL;
slouken@1895
   870
    }
slouken@1895
   871
    if (surface->map != NULL) {
slouken@1895
   872
        SDL_FreeBlitMap(surface->map);
slouken@1895
   873
        surface->map = NULL;
slouken@1895
   874
    }
slouken@1895
   875
    if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
slouken@1895
   876
        SDL_free(surface->pixels);
slouken@1895
   877
    }
slouken@1895
   878
    SDL_free(surface);
slouken@0
   879
#ifdef CHECK_LEAKS
slouken@1895
   880
    --surfaces_allocated;
slouken@0
   881
#endif
slouken@0
   882
}
slouken@1895
   883
slouken@1895
   884
/* vi: set ts=4 sw=4 expandtab: */