src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 06 Oct 2017 16:50:24 -0700
changeset 11574 696d0036f442
parent 11572 7e0f1498ddb5
child 11577 a68ad1ddb897
permissions -rw-r--r--
Fixed bug 3857 - SDL_ConvertPixels misses YUV conversions

Sylvain

Few issues with YUV on SDL2 when using odd dimensions, and missing conversions from/back to YUV formats.

1) The big part is that SDL_ConvertPixels() does not convert to/from YUV in most cases. This now works with any format and also with odd dimensions,
by adding two internal functions SDL_ConvertPixels_YUV_to_ARGB8888 and SDL_ConvertPixels_ARGB8888_to_YUV (could it be XRGB888 ?).
The target format is hard coded to ARGB888 (which is the default in the internal of the software renderer).
In case of different YUV conversion, it will do an intermediate conversion to a ARGB8888 buffer.

SDL_ConvertPixels_YUV_to_ARGB8888 is somehow redundant with all the "Color*Dither*Mod*".
But it allows some completeness of SDL_ConvertPixels to handle all YUV format.
It also works with odd dimensions.

Moreover, I did some benchmark(SDL_ConvertPixel vs Color32DitherYV12Mod1X and Color32DitherYUY2Mod1X).
gcc-6.3 and clang-4.0. gcc performs better than clang. And, with gcc, SDL_ConvertPixels() performs better (20%) than the two C function Color32Dither*().
For instance, to convert 10 times a 3888x2592 image, it takes ~195 ms with SDL_ConvertPixels and ~235 ms with Color32Dither*().
Especially because of gcc vectorize feature that optimises all conversion loops (-ftree-loop-vectorize).

Nb: I put no image pitch for the YUV buffers. because it complexify a little bit the code and the API :
There would be some ambiguity when setting the pitch exactly to image width:
would it a be pitch of image width (for luma and chroma). or just contiguous data ? (could set pitch=0 for the later).


2) Small issues with odd dimensions:
If width "w" is odd, luma plane width is still "w" whereas chroma planes will be "(w + 1)/2". Almost the same for odd h.
Solution is to strategically substitute "w" by "(w+1)/2" at the good places ...

- In the repository, SDL_ConvertPixels() handles YUV only if yuv source format is exactly the same as YUV destination format.
It basically does a memcpy of pixels, but it's done incorrectly when width or height is odd (wrong size of chroma planes). This is fixed.

- SDL Renderers don't support odd width/height for YUV textures.
This is fixed for software, opengl, opengles2. (opengles 1 does not support it and fallback to software rendering).
This is *not* fixed for D3D and D3D11 ... (and others, psp ?)
Only *two* Dither function are fixed ... not sure if others are really used.

- This is not possible to create a NV12/NV12 texture with the software renderer, whereas other renderers allow it.
This is fixed, by using SDL_ConvertPixels underneath.

- It was not possible to SDL_UpdateTexture() of format NV12/NV21 with the software renderer. this is fixed.

Here's also two testcases:
- that do all combination of conversion.
- to test partial UpdateTexture
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@0
    22
slouken@0
    23
#include "SDL_video.h"
slouken@0
    24
#include "SDL_sysvideo.h"
slouken@0
    25
#include "SDL_blit.h"
slouken@0
    26
#include "SDL_RLEaccel_c.h"
slouken@0
    27
#include "SDL_pixels_c.h"
slouken@0
    28
slouken@11574
    29
/* Private routines */
slouken@11574
    30
static int
slouken@11574
    31
SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
slouken@11574
    32
        Uint32 src_format, const void *src, 
slouken@11574
    33
        void *dst, int dst_pitch);
slouken@11574
    34
slouken@11574
    35
static int 
slouken@11574
    36
SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, 
slouken@11574
    37
        const void *src, int src_pitch,
slouken@11574
    38
        Uint32 dst_format, void *dst);
slouken@11574
    39
slouken@0
    40
/* Public routines */
slouken@10482
    41
slouken@0
    42
/*
slouken@10482
    43
 * Create an empty RGB surface of the appropriate depth using the given
slouken@10482
    44
 * enum SDL_PIXELFORMAT_* format
slouken@0
    45
 */
slouken@1895
    46
SDL_Surface *
slouken@10482
    47
SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
slouken@10482
    48
                               Uint32 format)
slouken@0
    49
{
slouken@1895
    50
    SDL_Surface *surface;
slouken@0
    51
slouken@2807
    52
    /* The flags are no longer used, make the compiler happy */
slouken@4461
    53
    (void)flags;
slouken@2807
    54
slouken@1895
    55
    /* Allocate the surface */
slouken@1920
    56
    surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
slouken@1895
    57
    if (surface == NULL) {
slouken@1895
    58
        SDL_OutOfMemory();
slouken@1895
    59
        return NULL;
slouken@1895
    60
    }
slouken@940
    61
slouken@5288
    62
    surface->format = SDL_AllocFormat(format);
slouken@1895
    63
    if (!surface->format) {
slouken@1895
    64
        SDL_FreeSurface(surface);
slouken@1895
    65
        return NULL;
slouken@1895
    66
    }
slouken@1895
    67
    surface->w = width;
slouken@1895
    68
    surface->h = height;
slouken@1895
    69
    surface->pitch = SDL_CalculatePitch(surface);
slouken@1895
    70
    SDL_SetClipRect(surface, NULL);
slouken@0
    71
slouken@5288
    72
    if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
slouken@1895
    73
        SDL_Palette *palette =
slouken@1895
    74
            SDL_AllocPalette((1 << surface->format->BitsPerPixel));
slouken@1895
    75
        if (!palette) {
slouken@1895
    76
            SDL_FreeSurface(surface);
slouken@1895
    77
            return NULL;
slouken@1895
    78
        }
slouken@5438
    79
        if (palette->ncolors == 2) {
slouken@1895
    80
            /* Create a black and white bitmap palette */
slouken@1895
    81
            palette->colors[0].r = 0xFF;
slouken@1895
    82
            palette->colors[0].g = 0xFF;
slouken@1895
    83
            palette->colors[0].b = 0xFF;
slouken@1895
    84
            palette->colors[1].r = 0x00;
slouken@1895
    85
            palette->colors[1].g = 0x00;
slouken@1895
    86
            palette->colors[1].b = 0x00;
slouken@1895
    87
        }
slouken@1895
    88
        SDL_SetSurfacePalette(surface, palette);
slouken@1895
    89
        SDL_FreePalette(palette);
slouken@1895
    90
    }
slouken@1895
    91
slouken@1895
    92
    /* Get the pixels */
slouken@1895
    93
    if (surface->w && surface->h) {
slouken@11572
    94
        int size = (surface->h * surface->pitch);
slouken@11572
    95
        if (size < 0 || (size / surface->pitch) != surface->h) {
slouken@11572
    96
            /* Overflow... */
slouken@11572
    97
            SDL_FreeSurface(surface);
slouken@11572
    98
            SDL_OutOfMemory();
slouken@11572
    99
            return NULL;
slouken@11572
   100
        }
slouken@11572
   101
slouken@11572
   102
        surface->pixels = SDL_malloc(size);
slouken@1895
   103
        if (!surface->pixels) {
slouken@1895
   104
            SDL_FreeSurface(surface);
slouken@1895
   105
            SDL_OutOfMemory();
slouken@1895
   106
            return NULL;
slouken@1895
   107
        }
slouken@1895
   108
        /* This is important for bitmaps */
slouken@1895
   109
        SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
slouken@1895
   110
    }
slouken@1895
   111
slouken@1895
   112
    /* Allocate an empty mapping */
slouken@1895
   113
    surface->map = SDL_AllocBlitMap();
slouken@1895
   114
    if (!surface->map) {
slouken@1895
   115
        SDL_FreeSurface(surface);
slouken@1895
   116
        return NULL;
slouken@1895
   117
    }
slouken@1895
   118
slouken@2267
   119
    /* By default surface with an alpha mask are set up for blending */
slouken@10482
   120
    if (surface->format->Amask) {
slouken@2884
   121
        SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
slouken@2267
   122
    }
slouken@2267
   123
slouken@1895
   124
    /* The surface is ready to go */
slouken@1895
   125
    surface->refcount = 1;
slouken@1895
   126
    return surface;
slouken@0
   127
}
slouken@1895
   128
slouken@0
   129
/*
slouken@10482
   130
 * Create an empty RGB surface of the appropriate depth
slouken@10482
   131
 */
slouken@10482
   132
SDL_Surface *
slouken@10482
   133
SDL_CreateRGBSurface(Uint32 flags,
slouken@10482
   134
                     int width, int height, int depth,
slouken@10482
   135
                     Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
slouken@10482
   136
{
slouken@10482
   137
    Uint32 format;
slouken@10482
   138
slouken@10482
   139
    /* Get the pixel format */
slouken@10482
   140
    format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
slouken@10482
   141
    if (format == SDL_PIXELFORMAT_UNKNOWN) {
slouken@10482
   142
        SDL_SetError("Unknown pixel format");
slouken@10482
   143
        return NULL;
slouken@10482
   144
    }
slouken@10482
   145
slouken@10482
   146
    return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
slouken@10482
   147
}
slouken@10482
   148
slouken@10482
   149
/*
slouken@0
   150
 * Create an RGB surface from an existing memory buffer
slouken@0
   151
 */
slouken@1895
   152
SDL_Surface *
slouken@1895
   153
SDL_CreateRGBSurfaceFrom(void *pixels,
slouken@1895
   154
                         int width, int height, int depth, int pitch,
slouken@1895
   155
                         Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
slouken@1895
   156
                         Uint32 Amask)
slouken@0
   157
{
slouken@1895
   158
    SDL_Surface *surface;
slouken@0
   159
slouken@10482
   160
    surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
slouken@10482
   161
    if (surface != NULL) {
slouken@10482
   162
        surface->flags |= SDL_PREALLOC;
slouken@10482
   163
        surface->pixels = pixels;
slouken@10482
   164
        surface->w = width;
slouken@10482
   165
        surface->h = height;
slouken@10482
   166
        surface->pitch = pitch;
slouken@10482
   167
        SDL_SetClipRect(surface, NULL);
slouken@10482
   168
    }
slouken@10482
   169
    return surface;
slouken@10482
   170
}
slouken@10482
   171
slouken@10482
   172
/*
slouken@10482
   173
 * Create an RGB surface from an existing memory buffer using the given given
slouken@10482
   174
 * enum SDL_PIXELFORMAT_* format
slouken@10482
   175
 */
slouken@10482
   176
SDL_Surface *
slouken@10482
   177
SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
slouken@10482
   178
                         int width, int height, int depth, int pitch,
slouken@10482
   179
                         Uint32 format)
slouken@10482
   180
{
slouken@10482
   181
    SDL_Surface *surface;
slouken@10482
   182
slouken@10482
   183
    surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
slouken@1895
   184
    if (surface != NULL) {
slouken@1895
   185
        surface->flags |= SDL_PREALLOC;
slouken@1895
   186
        surface->pixels = pixels;
slouken@1895
   187
        surface->w = width;
slouken@1895
   188
        surface->h = height;
slouken@1895
   189
        surface->pitch = pitch;
slouken@1895
   190
        SDL_SetClipRect(surface, NULL);
slouken@1895
   191
    }
slouken@1895
   192
    return surface;
slouken@0
   193
}
slouken@1895
   194
slouken@1895
   195
int
slouken@1895
   196
SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
slouken@1895
   197
{
slouken@5288
   198
    if (!surface) {
icculus@7037
   199
        return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
slouken@1895
   200
    }
slouken@8990
   201
    if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
slouken@8990
   202
        return -1;
slouken@8990
   203
    }
slouken@8990
   204
    SDL_InvalidateMap(surface->map);
slouken@8990
   205
slouken@8990
   206
    return 0;
slouken@1895
   207
}
slouken@1895
   208
slouken@2267
   209
int
slouken@2267
   210
SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
slouken@0
   211
{
slouken@2267
   212
    int flags;
slouken@0
   213
slouken@2266
   214
    if (!surface) {
slouken@2266
   215
        return -1;
slouken@1895
   216
    }
slouken@0
   217
slouken@2267
   218
    flags = surface->map->info.flags;
slouken@1895
   219
    if (flag) {
slouken@2267
   220
        surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
slouken@1895
   221
    } else {
slouken@2267
   222
        surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
slouken@1895
   223
    }
slouken@2267
   224
    if (surface->map->info.flags != flags) {
slouken@1895
   225
        SDL_InvalidateMap(surface->map);
slouken@1895
   226
    }
slouken@1895
   227
    return 0;
slouken@431
   228
}
slouken@0
   229
slouken@2267
   230
int
slouken@3560
   231
SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
slouken@2266
   232
{
slouken@2266
   233
    int flags;
slouken@2266
   234
slouken@2266
   235
    if (!surface) {
slouken@7363
   236
        return SDL_InvalidParamError("surface");
slouken@7363
   237
    }
slouken@7363
   238
icculus@7482
   239
    if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
slouken@7363
   240
        return SDL_InvalidParamError("key");
slouken@2266
   241
    }
slouken@2266
   242
slouken@2266
   243
    if (flag & SDL_RLEACCEL) {
slouken@2266
   244
        SDL_SetSurfaceRLE(surface, 1);
slouken@2266
   245
    }
slouken@2266
   246
slouken@2266
   247
    flags = surface->map->info.flags;
slouken@2266
   248
    if (flag) {
slouken@2266
   249
        surface->map->info.flags |= SDL_COPY_COLORKEY;
slouken@2266
   250
        surface->map->info.colorkey = key;
slouken@7023
   251
        if (surface->format->palette) {
slouken@7024
   252
            surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
slouken@7025
   253
            ++surface->format->palette->version;
slouken@7025
   254
            if (!surface->format->palette->version) {
slouken@7025
   255
                surface->format->palette->version = 1;
slouken@7025
   256
            }
slouken@7023
   257
        }
slouken@2266
   258
    } else {
slouken@7023
   259
        if (surface->format->palette) {
slouken@7024
   260
            surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE;
slouken@7025
   261
            ++surface->format->palette->version;
slouken@7025
   262
            if (!surface->format->palette->version) {
slouken@7025
   263
                surface->format->palette->version = 1;
slouken@7025
   264
            }
slouken@7023
   265
        }
slouken@2266
   266
        surface->map->info.flags &= ~SDL_COPY_COLORKEY;
slouken@2266
   267
    }
slouken@2266
   268
    if (surface->map->info.flags != flags) {
slouken@2266
   269
        SDL_InvalidateMap(surface->map);
slouken@2266
   270
    }
slouken@2267
   271
slouken@2266
   272
    return 0;
slouken@2266
   273
}
slouken@2266
   274
slouken@3103
   275
int
slouken@3103
   276
SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
slouken@3103
   277
{
slouken@3103
   278
    if (!surface) {
slouken@3103
   279
        return -1;
slouken@3103
   280
    }
slouken@3103
   281
slouken@3103
   282
    if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
slouken@3103
   283
        return -1;
slouken@3103
   284
    }
slouken@3103
   285
slouken@3103
   286
    if (key) {
slouken@3103
   287
        *key = surface->map->info.colorkey;
slouken@3103
   288
    }
slouken@3103
   289
    return 0;
slouken@3103
   290
}
slouken@3103
   291
slouken@2785
   292
/* This is a fairly slow function to switch from colorkey to alpha */
slouken@2787
   293
static void
slouken@2786
   294
SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
slouken@2785
   295
{
slouken@2786
   296
    int x, y;
slouken@2785
   297
slouken@2786
   298
    if (!surface) {
slouken@2786
   299
        return;
slouken@2786
   300
    }
slouken@2785
   301
slouken@2786
   302
    if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
slouken@2786
   303
        !surface->format->Amask) {
slouken@2786
   304
        return;
slouken@2786
   305
    }
slouken@2785
   306
slouken@2786
   307
    SDL_LockSurface(surface);
slouken@2785
   308
slouken@2786
   309
    switch (surface->format->BytesPerPixel) {
slouken@2786
   310
    case 2:
slouken@2786
   311
        {
slouken@2786
   312
            Uint16 *row, *spot;
slouken@2786
   313
            Uint16 ckey = (Uint16) surface->map->info.colorkey;
slouken@2786
   314
            Uint16 mask = (Uint16) (~surface->format->Amask);
slouken@2785
   315
slouken@7601
   316
            /* Ignore alpha in colorkey comparison */
slouken@7601
   317
            ckey &= mask;
slouken@2786
   318
            row = (Uint16 *) surface->pixels;
slouken@2786
   319
            for (y = surface->h; y--;) {
slouken@2786
   320
                spot = row;
slouken@2786
   321
                for (x = surface->w; x--;) {
slouken@7601
   322
                    if ((*spot & mask) == ckey) {
slouken@2786
   323
                        *spot &= mask;
slouken@2786
   324
                    }
slouken@2786
   325
                    ++spot;
slouken@2786
   326
                }
slouken@2786
   327
                row += surface->pitch / 2;
slouken@2786
   328
            }
slouken@2786
   329
        }
slouken@2786
   330
        break;
slouken@2786
   331
    case 3:
slouken@2786
   332
        /* FIXME */
slouken@2786
   333
        break;
slouken@2786
   334
    case 4:
slouken@2786
   335
        {
slouken@2786
   336
            Uint32 *row, *spot;
slouken@2786
   337
            Uint32 ckey = surface->map->info.colorkey;
slouken@2786
   338
            Uint32 mask = ~surface->format->Amask;
slouken@2785
   339
slouken@7601
   340
            /* Ignore alpha in colorkey comparison */
slouken@7601
   341
            ckey &= mask;
slouken@2786
   342
            row = (Uint32 *) surface->pixels;
slouken@2786
   343
            for (y = surface->h; y--;) {
slouken@2786
   344
                spot = row;
slouken@2786
   345
                for (x = surface->w; x--;) {
slouken@7601
   346
                    if ((*spot & mask) == ckey) {
slouken@2786
   347
                        *spot &= mask;
slouken@2786
   348
                    }
slouken@2786
   349
                    ++spot;
slouken@2786
   350
                }
slouken@2786
   351
                row += surface->pitch / 4;
slouken@2786
   352
            }
slouken@2786
   353
        }
slouken@2786
   354
        break;
slouken@2786
   355
    }
slouken@2785
   356
slouken@2786
   357
    SDL_UnlockSurface(surface);
slouken@2785
   358
slouken@2786
   359
    SDL_SetColorKey(surface, 0, 0);
slouken@2884
   360
    SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
slouken@2785
   361
}
slouken@2785
   362
slouken@2267
   363
int
slouken@2267
   364
SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
slouken@2266
   365
{
slouken@2266
   366
    int flags;
slouken@2266
   367
slouken@2266
   368
    if (!surface) {
slouken@2266
   369
        return -1;
slouken@2266
   370
    }
slouken@2266
   371
slouken@2266
   372
    surface->map->info.r = r;
slouken@2266
   373
    surface->map->info.g = g;
slouken@2266
   374
    surface->map->info.b = b;
slouken@2266
   375
slouken@2266
   376
    flags = surface->map->info.flags;
slouken@2266
   377
    if (r != 0xFF || g != 0xFF || b != 0xFF) {
slouken@2266
   378
        surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
slouken@2266
   379
    } else {
slouken@2266
   380
        surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
slouken@2266
   381
    }
slouken@2266
   382
    if (surface->map->info.flags != flags) {
slouken@2266
   383
        SDL_InvalidateMap(surface->map);
slouken@2266
   384
    }
slouken@2266
   385
    return 0;
slouken@2266
   386
}
slouken@2266
   387
slouken@2266
   388
slouken@2267
   389
int
slouken@2267
   390
SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
slouken@2266
   391
{
slouken@2266
   392
    if (!surface) {
slouken@2266
   393
        return -1;
slouken@2266
   394
    }
slouken@2266
   395
slouken@2266
   396
    if (r) {
slouken@2266
   397
        *r = surface->map->info.r;
slouken@2266
   398
    }
slouken@2266
   399
    if (g) {
slouken@2266
   400
        *g = surface->map->info.g;
slouken@2266
   401
    }
slouken@2266
   402
    if (b) {
slouken@2266
   403
        *b = surface->map->info.b;
slouken@2266
   404
    }
slouken@2266
   405
    return 0;
slouken@2266
   406
}
slouken@2266
   407
slouken@2267
   408
int
slouken@2267
   409
SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
slouken@2266
   410
{
slouken@2266
   411
    int flags;
slouken@2266
   412
slouken@2266
   413
    if (!surface) {
slouken@2266
   414
        return -1;
slouken@2266
   415
    }
slouken@2266
   416
slouken@2266
   417
    surface->map->info.a = alpha;
slouken@2266
   418
slouken@2266
   419
    flags = surface->map->info.flags;
slouken@2266
   420
    if (alpha != 0xFF) {
slouken@2266
   421
        surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
slouken@2266
   422
    } else {
slouken@2266
   423
        surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
slouken@2266
   424
    }
slouken@2266
   425
    if (surface->map->info.flags != flags) {
slouken@2266
   426
        SDL_InvalidateMap(surface->map);
slouken@2266
   427
    }
slouken@2266
   428
    return 0;
slouken@2266
   429
}
slouken@2266
   430
slouken@2267
   431
int
slouken@2267
   432
SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
slouken@2266
   433
{
slouken@2266
   434
    if (!surface) {
slouken@2266
   435
        return -1;
slouken@2266
   436
    }
slouken@2266
   437
slouken@2266
   438
    if (alpha) {
slouken@2266
   439
        *alpha = surface->map->info.a;
slouken@2266
   440
    }
slouken@2266
   441
    return 0;
slouken@2266
   442
}
slouken@2266
   443
slouken@2267
   444
int
slouken@4929
   445
SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
slouken@2266
   446
{
slouken@2266
   447
    int flags, status;
slouken@2266
   448
slouken@2266
   449
    if (!surface) {
slouken@2266
   450
        return -1;
slouken@2266
   451
    }
slouken@2266
   452
slouken@2266
   453
    status = 0;
slouken@2266
   454
    flags = surface->map->info.flags;
slouken@5184
   455
    surface->map->info.flags &=
slouken@5184
   456
        ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
slouken@2266
   457
    switch (blendMode) {
slouken@2884
   458
    case SDL_BLENDMODE_NONE:
slouken@2266
   459
        break;
slouken@2884
   460
    case SDL_BLENDMODE_BLEND:
slouken@2266
   461
        surface->map->info.flags |= SDL_COPY_BLEND;
slouken@2266
   462
        break;
slouken@2884
   463
    case SDL_BLENDMODE_ADD:
slouken@2266
   464
        surface->map->info.flags |= SDL_COPY_ADD;
slouken@2266
   465
        break;
slouken@5184
   466
    case SDL_BLENDMODE_MOD:
slouken@5184
   467
        surface->map->info.flags |= SDL_COPY_MOD;
slouken@5184
   468
        break;
slouken@2266
   469
    default:
icculus@7037
   470
        status = SDL_Unsupported();
slouken@2266
   471
        break;
slouken@2266
   472
    }
slouken@2266
   473
slouken@2266
   474
    if (surface->map->info.flags != flags) {
slouken@2266
   475
        SDL_InvalidateMap(surface->map);
slouken@2266
   476
    }
slouken@2267
   477
slouken@2266
   478
    return status;
slouken@2266
   479
}
slouken@2266
   480
slouken@2267
   481
int
slouken@4929
   482
SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
slouken@2266
   483
{
slouken@2266
   484
    if (!surface) {
slouken@2266
   485
        return -1;
slouken@2266
   486
    }
slouken@2266
   487
slouken@2266
   488
    if (!blendMode) {
slouken@2266
   489
        return 0;
slouken@2266
   490
    }
slouken@2266
   491
slouken@5184
   492
    switch (surface->map->
slouken@5184
   493
            info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
slouken@2266
   494
    case SDL_COPY_BLEND:
slouken@2884
   495
        *blendMode = SDL_BLENDMODE_BLEND;
slouken@2266
   496
        break;
slouken@2266
   497
    case SDL_COPY_ADD:
slouken@2884
   498
        *blendMode = SDL_BLENDMODE_ADD;
slouken@2266
   499
        break;
slouken@5184
   500
    case SDL_COPY_MOD:
slouken@5184
   501
        *blendMode = SDL_BLENDMODE_MOD;
slouken@5184
   502
        break;
slouken@2266
   503
    default:
slouken@2884
   504
        *blendMode = SDL_BLENDMODE_NONE;
slouken@2266
   505
        break;
slouken@2266
   506
    }
slouken@2266
   507
    return 0;
slouken@2266
   508
}
slouken@2266
   509
slouken@1895
   510
SDL_bool
slouken@1895
   511
SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
slouken@0
   512
{
slouken@1895
   513
    SDL_Rect full_rect;
slouken@0
   514
slouken@1895
   515
    /* Don't do anything if there's no surface to act on */
slouken@1895
   516
    if (!surface) {
slouken@1895
   517
        return SDL_FALSE;
slouken@1895
   518
    }
slouken@0
   519
slouken@1895
   520
    /* Set up the full surface rectangle */
slouken@1895
   521
    full_rect.x = 0;
slouken@1895
   522
    full_rect.y = 0;
slouken@1895
   523
    full_rect.w = surface->w;
slouken@1895
   524
    full_rect.h = surface->h;
slouken@0
   525
slouken@1895
   526
    /* Set the clipping rectangle */
slouken@1895
   527
    if (!rect) {
slouken@1895
   528
        surface->clip_rect = full_rect;
slouken@4966
   529
        return SDL_TRUE;
slouken@1895
   530
    }
slouken@1895
   531
    return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
slouken@0
   532
}
slouken@1895
   533
slouken@1895
   534
void
slouken@1895
   535
SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
slouken@0
   536
{
slouken@1895
   537
    if (surface && rect) {
slouken@1895
   538
        *rect = surface->clip_rect;
slouken@1895
   539
    }
slouken@0
   540
}
slouken@1895
   541
slouken@7191
   542
/*
slouken@0
   543
 * Set up a blit between two surfaces -- split into three parts:
slouken@7191
   544
 * The upper part, SDL_UpperBlit(), performs clipping and rectangle
slouken@0
   545
 * verification.  The lower part is a pointer to a low level
slouken@0
   546
 * accelerated blitting function.
slouken@0
   547
 *
slouken@7191
   548
 * These parts are separated out and each used internally by this
slouken@0
   549
 * library in the optimimum places.  They are exported so that if
slouken@0
   550
 * you know exactly what you are doing, you can optimize your code
slouken@0
   551
 * by calling the one(s) you need.
slouken@0
   552
 */
slouken@1895
   553
int
slouken@1895
   554
SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
slouken@1895
   555
              SDL_Surface * dst, SDL_Rect * dstrect)
slouken@0
   556
{
slouken@1895
   557
    /* Check to make sure the blit mapping is valid */
slouken@1895
   558
    if ((src->map->dst != dst) ||
slouken@5288
   559
        (dst->format->palette &&
slouken@6166
   560
         src->map->dst_palette_version != dst->format->palette->version) ||
slouken@6166
   561
        (src->format->palette &&
slouken@6166
   562
         src->map->src_palette_version != src->format->palette->version)) {
slouken@1895
   563
        if (SDL_MapSurface(src, dst) < 0) {
slouken@1895
   564
            return (-1);
slouken@1895
   565
        }
bob@2328
   566
        /* just here for debugging */
bob@2329
   567
/*         printf */
bob@2329
   568
/*             ("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
   569
/*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
bob@2329
   570
/*              dst->map->info.flags, src->map->blit); */
slouken@1895
   571
    }
slouken@2257
   572
    return (src->map->blit(src, srcrect, dst, dstrect));
slouken@0
   573
}
slouken@0
   574
slouken@0
   575
slouken@1895
   576
int
slouken@4949
   577
SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
slouken@1895
   578
              SDL_Surface * dst, SDL_Rect * dstrect)
slouken@0
   579
{
slouken@1895
   580
    SDL_Rect fulldst;
slouken@1895
   581
    int srcx, srcy, w, h;
slouken@0
   582
slouken@1895
   583
    /* Make sure the surfaces aren't locked */
slouken@1895
   584
    if (!src || !dst) {
icculus@7037
   585
        return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
slouken@1895
   586
    }
slouken@1895
   587
    if (src->locked || dst->locked) {
icculus@7037
   588
        return SDL_SetError("Surfaces must not be locked during blit");
slouken@1895
   589
    }
slouken@0
   590
slouken@1895
   591
    /* If the destination rectangle is NULL, use the entire dest surface */
slouken@1895
   592
    if (dstrect == NULL) {
slouken@1895
   593
        fulldst.x = fulldst.y = 0;
slouken@7511
   594
        fulldst.w = dst->w;
slouken@7511
   595
        fulldst.h = dst->h;
slouken@1895
   596
        dstrect = &fulldst;
slouken@1895
   597
    }
slouken@0
   598
slouken@1895
   599
    /* clip the source rectangle to the source surface */
slouken@1895
   600
    if (srcrect) {
slouken@1895
   601
        int maxw, maxh;
slouken@0
   602
slouken@1895
   603
        srcx = srcrect->x;
slouken@1895
   604
        w = srcrect->w;
slouken@1895
   605
        if (srcx < 0) {
slouken@1895
   606
            w += srcx;
slouken@1895
   607
            dstrect->x -= srcx;
slouken@1895
   608
            srcx = 0;
slouken@1895
   609
        }
slouken@1895
   610
        maxw = src->w - srcx;
slouken@1895
   611
        if (maxw < w)
slouken@1895
   612
            w = maxw;
slouken@0
   613
slouken@1895
   614
        srcy = srcrect->y;
slouken@1895
   615
        h = srcrect->h;
slouken@1895
   616
        if (srcy < 0) {
slouken@1895
   617
            h += srcy;
slouken@1895
   618
            dstrect->y -= srcy;
slouken@1895
   619
            srcy = 0;
slouken@1895
   620
        }
slouken@1895
   621
        maxh = src->h - srcy;
slouken@1895
   622
        if (maxh < h)
slouken@1895
   623
            h = maxh;
slouken@0
   624
slouken@1895
   625
    } else {
slouken@1895
   626
        srcx = srcy = 0;
slouken@1895
   627
        w = src->w;
slouken@1895
   628
        h = src->h;
slouken@1895
   629
    }
slouken@0
   630
slouken@1895
   631
    /* clip the destination rectangle against the clip rectangle */
slouken@1895
   632
    {
slouken@1895
   633
        SDL_Rect *clip = &dst->clip_rect;
slouken@1895
   634
        int dx, dy;
slouken@0
   635
slouken@1895
   636
        dx = clip->x - dstrect->x;
slouken@1895
   637
        if (dx > 0) {
slouken@1895
   638
            w -= dx;
slouken@1895
   639
            dstrect->x += dx;
slouken@1895
   640
            srcx += dx;
slouken@1895
   641
        }
slouken@1895
   642
        dx = dstrect->x + w - clip->x - clip->w;
slouken@1895
   643
        if (dx > 0)
slouken@1895
   644
            w -= dx;
slouken@1895
   645
slouken@1895
   646
        dy = clip->y - dstrect->y;
slouken@1895
   647
        if (dy > 0) {
slouken@1895
   648
            h -= dy;
slouken@1895
   649
            dstrect->y += dy;
slouken@1895
   650
            srcy += dy;
slouken@1895
   651
        }
slouken@1895
   652
        dy = dstrect->y + h - clip->y - clip->h;
slouken@1895
   653
        if (dy > 0)
slouken@1895
   654
            h -= dy;
slouken@1895
   655
    }
slouken@1895
   656
slouken@7834
   657
    /* Switch back to a fast blit if we were previously stretching */
slouken@7834
   658
    if (src->map->info.flags & SDL_COPY_NEAREST) {
slouken@7834
   659
        src->map->info.flags &= ~SDL_COPY_NEAREST;
slouken@7834
   660
        SDL_InvalidateMap(src->map);
slouken@7834
   661
    }
slouken@7834
   662
slouken@1895
   663
    if (w > 0 && h > 0) {
slouken@1895
   664
        SDL_Rect sr;
slouken@1895
   665
        sr.x = srcx;
slouken@1895
   666
        sr.y = srcy;
slouken@1895
   667
        sr.w = dstrect->w = w;
slouken@1895
   668
        sr.h = dstrect->h = h;
slouken@1895
   669
        return SDL_LowerBlit(src, &sr, dst, dstrect);
slouken@1895
   670
    }
slouken@1895
   671
    dstrect->w = dstrect->h = 0;
slouken@1895
   672
    return 0;
slouken@0
   673
}
slouken@0
   674
ken@5296
   675
int
ken@5499
   676
SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
ken@5499
   677
              SDL_Surface * dst, SDL_Rect * dstrect)
ken@5499
   678
{
slouken@9076
   679
    double src_x0, src_y0, src_x1, src_y1;
slouken@9076
   680
    double dst_x0, dst_y0, dst_x1, dst_y1;
slouken@9076
   681
    SDL_Rect final_src, final_dst;
slouken@9076
   682
    double scaling_w, scaling_h;
slouken@9076
   683
    int src_w, src_h;
slouken@9076
   684
    int dst_w, dst_h;
ken@5499
   685
ken@5499
   686
    /* Make sure the surfaces aren't locked */
ken@5499
   687
    if (!src || !dst) {
icculus@7037
   688
        return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
ken@5499
   689
    }
ken@5499
   690
    if (src->locked || dst->locked) {
icculus@7037
   691
        return SDL_SetError("Surfaces must not be locked during blit");
ken@5499
   692
    }
ken@5499
   693
slouken@9076
   694
    if (NULL == srcrect) {
slouken@9076
   695
        src_w = src->w;
slouken@9076
   696
        src_h = src->h;
slouken@9076
   697
    } else {
slouken@9076
   698
        src_w = srcrect->w;
slouken@9076
   699
        src_h = srcrect->h;
ken@5499
   700
    }
ken@5499
   701
slouken@9076
   702
    if (NULL == dstrect) {
slouken@9076
   703
        dst_w = dst->w;
slouken@9076
   704
        dst_h = dst->h;
ken@5499
   705
    } else {
slouken@9076
   706
        dst_w = dstrect->w;
slouken@9076
   707
        dst_h = dstrect->h;
ken@5499
   708
    }
ken@5499
   709
slouken@9076
   710
    if (dst_w == src_w && dst_h == src_h) {
slouken@9076
   711
        /* No scaling, defer to regular blit */
slouken@9076
   712
        return SDL_BlitSurface(src, srcrect, dst, dstrect);
ken@5499
   713
    }
ken@5499
   714
slouken@9076
   715
    scaling_w = (double)dst_w / src_w;
slouken@9076
   716
    scaling_h = (double)dst_h / src_h;
slouken@9076
   717
slouken@9076
   718
    if (NULL == dstrect) {
slouken@9076
   719
        dst_x0 = 0;
slouken@9076
   720
        dst_y0 = 0;
slouken@9076
   721
        dst_x1 = dst_w - 1;
slouken@9076
   722
        dst_y1 = dst_h - 1;
slouken@9076
   723
    } else {
slouken@9076
   724
        dst_x0 = dstrect->x;
slouken@9076
   725
        dst_y0 = dstrect->y;
slouken@9076
   726
        dst_x1 = dst_x0 + dst_w - 1;
slouken@9076
   727
        dst_y1 = dst_y0 + dst_h - 1;
ken@5499
   728
    }
ken@5499
   729
slouken@9076
   730
    if (NULL == srcrect) {
slouken@9076
   731
        src_x0 = 0;
slouken@9076
   732
        src_y0 = 0;
slouken@9076
   733
        src_x1 = src_w - 1;
slouken@9076
   734
        src_y1 = src_h - 1;
slouken@9076
   735
    } else {
slouken@9076
   736
        src_x0 = srcrect->x;
slouken@9076
   737
        src_y0 = srcrect->y;
slouken@9076
   738
        src_x1 = src_x0 + src_w - 1;
slouken@9076
   739
        src_y1 = src_y0 + src_h - 1;
slouken@9076
   740
slouken@9076
   741
        /* Clip source rectangle to the source surface */
slouken@9076
   742
slouken@9076
   743
        if (src_x0 < 0) {
slouken@9076
   744
            dst_x0 -= src_x0 * scaling_w;
slouken@9076
   745
            src_x0 = 0;
slouken@9076
   746
        }
slouken@9076
   747
slouken@9076
   748
        if (src_x1 >= src->w) {
slouken@9076
   749
            dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
slouken@9076
   750
            src_x1 = src->w - 1;
slouken@9076
   751
        }
slouken@9076
   752
slouken@9076
   753
        if (src_y0 < 0) {
slouken@9076
   754
            dst_y0 -= src_y0 * scaling_h;
slouken@9076
   755
            src_y0 = 0;
slouken@9076
   756
        }
slouken@9076
   757
slouken@9076
   758
        if (src_y1 >= src->h) {
slouken@9076
   759
            dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
slouken@9076
   760
            src_y1 = src->h - 1;
slouken@9076
   761
        }
slouken@9076
   762
    }
slouken@9076
   763
slouken@9076
   764
    /* Clip destination rectangle to the clip rectangle */
slouken@9076
   765
slouken@9076
   766
    /* Translate to clip space for easier calculations */
slouken@9076
   767
    dst_x0 -= dst->clip_rect.x;
slouken@9076
   768
    dst_x1 -= dst->clip_rect.x;
slouken@9076
   769
    dst_y0 -= dst->clip_rect.y;
slouken@9076
   770
    dst_y1 -= dst->clip_rect.y;
slouken@9076
   771
slouken@9076
   772
    if (dst_x0 < 0) {
slouken@9076
   773
        src_x0 -= dst_x0 / scaling_w;
slouken@9076
   774
        dst_x0 = 0;
slouken@9076
   775
    }
slouken@9076
   776
slouken@9076
   777
    if (dst_x1 >= dst->clip_rect.w) {
slouken@9076
   778
        src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
slouken@9076
   779
        dst_x1 = dst->clip_rect.w - 1;
slouken@9076
   780
    }
slouken@9076
   781
slouken@9076
   782
    if (dst_y0 < 0) {
slouken@9076
   783
        src_y0 -= dst_y0 / scaling_h;
slouken@9076
   784
        dst_y0 = 0;
slouken@9076
   785
    }
slouken@9076
   786
slouken@9076
   787
    if (dst_y1 >= dst->clip_rect.h) {
slouken@9076
   788
        src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
slouken@9076
   789
        dst_y1 = dst->clip_rect.h - 1;
slouken@9076
   790
    }
slouken@9076
   791
slouken@9076
   792
    /* Translate back to surface coordinates */
slouken@9076
   793
    dst_x0 += dst->clip_rect.x;
slouken@9076
   794
    dst_x1 += dst->clip_rect.x;
slouken@9076
   795
    dst_y0 += dst->clip_rect.y;
slouken@9076
   796
    dst_y1 += dst->clip_rect.y;
slouken@9076
   797
philipp@9267
   798
    final_src.x = (int)SDL_floor(src_x0 + 0.5);
philipp@9267
   799
    final_src.y = (int)SDL_floor(src_y0 + 0.5);
slouken@10668
   800
    final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
slouken@10668
   801
    final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
slouken@9076
   802
philipp@9267
   803
    final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
philipp@9267
   804
    final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
philipp@9267
   805
    final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
philipp@9267
   806
    final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
slouken@9076
   807
slouken@9076
   808
    if (final_dst.w < 0)
slouken@9076
   809
        final_dst.w = 0;
slouken@9076
   810
    if (final_dst.h < 0)
slouken@9076
   811
        final_dst.h = 0;
slouken@9076
   812
slouken@9076
   813
    if (dstrect)
slouken@9076
   814
        *dstrect = final_dst;
slouken@9076
   815
slouken@9076
   816
    if (final_dst.w == 0 || final_dst.h == 0 ||
slouken@9076
   817
        final_src.w <= 0 || final_src.h <= 0) {
slouken@9076
   818
        /* No-op. */
slouken@9076
   819
        return 0;
slouken@9076
   820
    }
slouken@9076
   821
slouken@9076
   822
    return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
ken@5499
   823
}
ken@5499
   824
ken@5499
   825
/**
ken@5499
   826
 *  This is a semi-private blit function and it performs low-level surface
ken@5499
   827
 *  scaled blitting only.
ken@5499
   828
 */
ken@5499
   829
int
ken@5499
   830
SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
ken@5499
   831
                SDL_Surface * dst, SDL_Rect * dstrect)
ken@5296
   832
{
slouken@6526
   833
    static const Uint32 complex_copy_flags = (
slouken@6526
   834
        SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
slouken@6526
   835
        SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD |
slouken@6526
   836
        SDL_COPY_COLORKEY
slouken@6526
   837
    );
slouken@6526
   838
slouken@7834
   839
    if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
slouken@7834
   840
        src->map->info.flags |= SDL_COPY_NEAREST;
slouken@7834
   841
        SDL_InvalidateMap(src->map);
slouken@7834
   842
    }
ken@5296
   843
slouken@6526
   844
    if ( !(src->map->info.flags & complex_copy_flags) &&
slouken@7191
   845
         src->format->format == dst->format->format &&
slouken@6526
   846
         !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
slouken@9076
   847
        return SDL_SoftStretch( src, srcrect, dst, dstrect );
ken@5296
   848
    } else {
slouken@9076
   849
        return SDL_LowerBlit( src, srcrect, dst, dstrect );
ken@5296
   850
    }
ken@5296
   851
}
ken@5296
   852
ken@5296
   853
/*
slouken@0
   854
 * Lock a surface to directly access the pixels
slouken@0
   855
 */
slouken@1895
   856
int
slouken@1895
   857
SDL_LockSurface(SDL_Surface * surface)
slouken@0
   858
{
slouken@1895
   859
    if (!surface->locked) {
slouken@1895
   860
        /* Perform the lock */
slouken@1895
   861
        if (surface->flags & SDL_RLEACCEL) {
slouken@1895
   862
            SDL_UnRLESurface(surface, 1);
slouken@1895
   863
            surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
slouken@1895
   864
        }
slouken@1895
   865
    }
slouken@0
   866
slouken@1895
   867
    /* Increment the surface lock count, for recursive locks */
slouken@1895
   868
    ++surface->locked;
slouken@0
   869
slouken@1895
   870
    /* Ready to go.. */
slouken@1895
   871
    return (0);
slouken@0
   872
}
slouken@1895
   873
slouken@0
   874
/*
slouken@0
   875
 * Unlock a previously locked surface
slouken@0
   876
 */
slouken@1895
   877
void
slouken@1895
   878
SDL_UnlockSurface(SDL_Surface * surface)
slouken@0
   879
{
slouken@1895
   880
    /* Only perform an unlock if we are locked */
slouken@1895
   881
    if (!surface->locked || (--surface->locked > 0)) {
slouken@1895
   882
        return;
slouken@1895
   883
    }
slouken@0
   884
slouken@1895
   885
    /* Update RLE encoded surface with new data */
slouken@1895
   886
    if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
slouken@1895
   887
        surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
slouken@1895
   888
        SDL_RLESurface(surface);
slouken@1895
   889
    }
slouken@0
   890
}
slouken@0
   891
slouken@7191
   892
/*
slouken@11289
   893
 * Creates a new surface identical to the existing surface
slouken@11289
   894
 */
slouken@11289
   895
SDL_Surface *
slouken@11289
   896
SDL_DuplicateSurface(SDL_Surface * surface)
slouken@11289
   897
{
slouken@11289
   898
    return SDL_ConvertSurface(surface, surface->format, surface->flags);
slouken@11289
   899
}
slouken@11289
   900
slouken@11289
   901
/*
slouken@0
   902
 * Convert a surface into the specified pixel format.
slouken@0
   903
 */
slouken@1895
   904
SDL_Surface *
icculus@7725
   905
SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
slouken@2807
   906
                   Uint32 flags)
slouken@0
   907
{
slouken@1895
   908
    SDL_Surface *convert;
slouken@2266
   909
    Uint32 copy_flags;
slouken@7601
   910
    SDL_Color copy_color;
slouken@1895
   911
    SDL_Rect bounds;
slouken@0
   912
slouken@11289
   913
    if (!surface) {
slouken@11289
   914
        SDL_InvalidParamError("surface");
slouken@11289
   915
        return NULL;
slouken@11289
   916
    }
slouken@11289
   917
    if (!format) {
slouken@11289
   918
        SDL_InvalidParamError("format");
slouken@11289
   919
        return NULL;
slouken@11289
   920
    }
slouken@11289
   921
slouken@1895
   922
    /* Check for empty destination palette! (results in empty image) */
slouken@1895
   923
    if (format->palette != NULL) {
slouken@1895
   924
        int i;
slouken@1895
   925
        for (i = 0; i < format->palette->ncolors; ++i) {
slouken@1895
   926
            if ((format->palette->colors[i].r != 0xFF) ||
slouken@1895
   927
                (format->palette->colors[i].g != 0xFF) ||
slouken@1895
   928
                (format->palette->colors[i].b != 0xFF))
slouken@1895
   929
                break;
slouken@1895
   930
        }
slouken@1895
   931
        if (i == format->palette->ncolors) {
slouken@1895
   932
            SDL_SetError("Empty destination palette");
slouken@1895
   933
            return (NULL);
slouken@1895
   934
        }
slouken@1895
   935
    }
slouken@0
   936
slouken@1895
   937
    /* Create a new surface with the desired format */
slouken@2807
   938
    convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
slouken@1895
   939
                                   format->BitsPerPixel, format->Rmask,
slouken@1895
   940
                                   format->Gmask, format->Bmask,
slouken@1895
   941
                                   format->Amask);
slouken@1895
   942
    if (convert == NULL) {
slouken@1895
   943
        return (NULL);
slouken@1895
   944
    }
slouken@264
   945
slouken@1895
   946
    /* Copy the palette if any */
slouken@1895
   947
    if (format->palette && convert->format->palette) {
slouken@1895
   948
        SDL_memcpy(convert->format->palette->colors,
slouken@1895
   949
                   format->palette->colors,
slouken@1895
   950
                   format->palette->ncolors * sizeof(SDL_Color));
slouken@1895
   951
        convert->format->palette->ncolors = format->palette->ncolors;
slouken@1895
   952
    }
slouken@0
   953
slouken@2266
   954
    /* Save the original copy flags */
slouken@2266
   955
    copy_flags = surface->map->info.flags;
slouken@7601
   956
    copy_color.r = surface->map->info.r;
slouken@7601
   957
    copy_color.g = surface->map->info.g;
slouken@7601
   958
    copy_color.b = surface->map->info.b;
slouken@7601
   959
    copy_color.a = surface->map->info.a;
slouken@7601
   960
    surface->map->info.r = 0xFF;
slouken@7601
   961
    surface->map->info.g = 0xFF;
slouken@7601
   962
    surface->map->info.b = 0xFF;
slouken@7601
   963
    surface->map->info.a = 0xFF;
slouken@2266
   964
    surface->map->info.flags = 0;
slouken@7601
   965
    SDL_InvalidateMap(surface->map);
slouken@0
   966
slouken@1895
   967
    /* Copy over the image data */
slouken@1895
   968
    bounds.x = 0;
slouken@1895
   969
    bounds.y = 0;
slouken@1895
   970
    bounds.w = surface->w;
slouken@1895
   971
    bounds.h = surface->h;
slouken@1895
   972
    SDL_LowerBlit(surface, &bounds, convert, &bounds);
slouken@0
   973
slouken@1895
   974
    /* Clean up the original surface, and update converted surface */
slouken@7601
   975
    convert->map->info.r = copy_color.r;
slouken@7601
   976
    convert->map->info.g = copy_color.g;
slouken@7601
   977
    convert->map->info.b = copy_color.b;
slouken@7601
   978
    convert->map->info.a = copy_color.a;
slouken@2824
   979
    convert->map->info.flags =
slouken@2824
   980
        (copy_flags &
slouken@2824
   981
         ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
slouken@2824
   982
           | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
slouken@2824
   983
           SDL_COPY_RLE_ALPHAKEY));
slouken@7601
   984
    surface->map->info.r = copy_color.r;
slouken@7601
   985
    surface->map->info.g = copy_color.g;
slouken@7601
   986
    surface->map->info.b = copy_color.b;
slouken@7601
   987
    surface->map->info.a = copy_color.a;
slouken@2824
   988
    surface->map->info.flags = copy_flags;
slouken@7601
   989
    SDL_InvalidateMap(surface->map);
slouken@2266
   990
    if (copy_flags & SDL_COPY_COLORKEY) {
slouken@7023
   991
        SDL_bool set_colorkey_by_color = SDL_FALSE;
slouken@2266
   992
slouken@7023
   993
        if (surface->format->palette) {
slouken@7191
   994
            if (format->palette &&
slouken@7023
   995
                surface->format->palette->ncolors <= format->palette->ncolors &&
slouken@7023
   996
                (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
slouken@7023
   997
                  surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
slouken@7023
   998
                /* The palette is identical, just set the same colorkey */
slouken@7023
   999
                SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
slouken@7023
  1000
            } else if (format->Amask) {
slouken@7023
  1001
                /* The alpha was set in the destination from the palette */
slouken@7023
  1002
            } else {
slouken@7023
  1003
                set_colorkey_by_color = SDL_TRUE;
slouken@7023
  1004
            }
slouken@7023
  1005
        } else {
slouken@7023
  1006
            set_colorkey_by_color = SDL_TRUE;
slouken@7023
  1007
        }
slouken@7023
  1008
slouken@7023
  1009
        if (set_colorkey_by_color) {
slouken@11253
  1010
            SDL_Surface *tmp;
slouken@11253
  1011
            SDL_Surface *tmp2;
slouken@11253
  1012
            int converted_colorkey = 0;
slouken@7023
  1013
slouken@11253
  1014
            /* Create a dummy surface to get the colorkey converted */
slouken@11253
  1015
            tmp = SDL_CreateRGBSurface(0, 1, 1,
slouken@11253
  1016
                                   surface->format->BitsPerPixel, surface->format->Rmask,
slouken@11253
  1017
                                   surface->format->Gmask, surface->format->Bmask,
slouken@11253
  1018
                                   surface->format->Amask);
slouken@11253
  1019
icculus@11496
  1020
            /* Share the palette, if any */
icculus@11496
  1021
            if (surface->format->palette) {
icculus@11496
  1022
                SDL_SetSurfacePalette(tmp, surface->format->palette);
icculus@11496
  1023
            }
icculus@11496
  1024
            
slouken@11253
  1025
            SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
slouken@11253
  1026
slouken@11253
  1027
            tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
slouken@11253
  1028
slouken@11253
  1029
            /* Convertion of the colorkey */
slouken@11253
  1030
            tmp2 = SDL_ConvertSurface(tmp, format, 0);
slouken@11253
  1031
slouken@11253
  1032
            /* Get the converted colorkey */
slouken@11254
  1033
            SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
slouken@11253
  1034
slouken@11253
  1035
            SDL_FreeSurface(tmp);
slouken@11253
  1036
            SDL_FreeSurface(tmp2);
slouken@11253
  1037
slouken@11253
  1038
            /* Set the converted colorkey on the new surface */
slouken@11253
  1039
            SDL_SetColorKey(convert, 1, converted_colorkey);
slouken@11253
  1040
slouken@7023
  1041
            /* This is needed when converting for 3D texture upload */
slouken@7023
  1042
            SDL_ConvertColorkeyToAlpha(convert);
slouken@7023
  1043
        }
slouken@1895
  1044
    }
slouken@2824
  1045
    SDL_SetClipRect(convert, &surface->clip_rect);
slouken@0
  1046
slouken@2266
  1047
    /* Enable alpha blending by default if the new surface has an
slouken@2266
  1048
     * alpha channel or alpha modulation */
slouken@2824
  1049
    if ((surface->format->Amask && format->Amask) ||
slouken@11246
  1050
        (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
slouken@2884
  1051
        SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
slouken@1895
  1052
    }
slouken@2824
  1053
    if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
slouken@2824
  1054
        SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
slouken@2824
  1055
    }
slouken@0
  1056
slouken@1895
  1057
    /* We're ready to go! */
slouken@1895
  1058
    return (convert);
slouken@0
  1059
}
slouken@0
  1060
slouken@5375
  1061
SDL_Surface *
slouken@5375
  1062
SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
slouken@5375
  1063
                         Uint32 flags)
slouken@5375
  1064
{
slouken@5375
  1065
    SDL_PixelFormat *fmt;
slouken@5515
  1066
    SDL_Surface *convert = NULL;
slouken@5375
  1067
slouken@5375
  1068
    fmt = SDL_AllocFormat(pixel_format);
slouken@5375
  1069
    if (fmt) {
slouken@5375
  1070
        convert = SDL_ConvertSurface(surface, fmt, flags);
slouken@5375
  1071
        SDL_FreeFormat(fmt);
slouken@5375
  1072
    }
slouken@5375
  1073
    return convert;
slouken@5375
  1074
}
slouken@5375
  1075
slouken@0
  1076
/*
slouken@3434
  1077
 * Create a surface on the stack for quick blit operations
slouken@3434
  1078
 */
slouken@7860
  1079
static SDL_INLINE SDL_bool
slouken@3434
  1080
SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
slouken@7191
  1081
                         void * pixels, int pitch, SDL_Surface * surface,
slouken@3434
  1082
                         SDL_PixelFormat * format, SDL_BlitMap * blitmap)
slouken@3434
  1083
{
slouken@5288
  1084
    if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
slouken@5288
  1085
        SDL_SetError("Indexed pixel formats not supported");
slouken@3434
  1086
        return SDL_FALSE;
slouken@3434
  1087
    }
slouken@5288
  1088
    if (SDL_InitFormat(format, pixel_format) < 0) {
slouken@3434
  1089
        return SDL_FALSE;
slouken@3434
  1090
    }
slouken@3434
  1091
slouken@3434
  1092
    SDL_zerop(surface);
slouken@3434
  1093
    surface->flags = SDL_PREALLOC;
slouken@5288
  1094
    surface->format = format;
slouken@3434
  1095
    surface->pixels = pixels;
slouken@3434
  1096
    surface->w = width;
slouken@3434
  1097
    surface->h = height;
slouken@3434
  1098
    surface->pitch = pitch;
slouken@3434
  1099
    /* We don't actually need to set up the clip rect for our purposes */
gabomdq@7678
  1100
    /* SDL_SetClipRect(surface, NULL); */
slouken@3434
  1101
slouken@3434
  1102
    /* Allocate an empty mapping */
slouken@3434
  1103
    SDL_zerop(blitmap);
slouken@3434
  1104
    blitmap->info.r = 0xFF;
slouken@3434
  1105
    blitmap->info.g = 0xFF;
slouken@3434
  1106
    blitmap->info.b = 0xFF;
slouken@3434
  1107
    blitmap->info.a = 0xFF;
slouken@3434
  1108
    surface->map = blitmap;
slouken@3434
  1109
slouken@3434
  1110
    /* The surface is ready to go */
slouken@3434
  1111
    surface->refcount = 1;
slouken@3434
  1112
    return SDL_TRUE;
slouken@3434
  1113
}
slouken@3434
  1114
slouken@3434
  1115
/*
slouken@3434
  1116
 * Copy a block of pixels of one format to another format
slouken@3434
  1117
 */
slouken@3434
  1118
int SDL_ConvertPixels(int width, int height,
slouken@3434
  1119
                      Uint32 src_format, const void * src, int src_pitch,
slouken@3434
  1120
                      Uint32 dst_format, void * dst, int dst_pitch)
slouken@3434
  1121
{
slouken@3434
  1122
    SDL_Surface src_surface, dst_surface;
slouken@3434
  1123
    SDL_PixelFormat src_fmt, dst_fmt;
slouken@3434
  1124
    SDL_BlitMap src_blitmap, dst_blitmap;
slouken@3434
  1125
    SDL_Rect rect;
icculus@6407
  1126
    void *nonconst_src = (void *) src;
slouken@3434
  1127
slouken@9046
  1128
    /* Check to make sure we are blitting somewhere, so we don't crash */
slouken@6920
  1129
    if (!dst) {
icculus@7037
  1130
        return SDL_InvalidParamError("dst");
slouken@6920
  1131
    }
slouken@6920
  1132
    if (!dst_pitch) {
icculus@7037
  1133
        return SDL_InvalidParamError("dst_pitch");
slouken@6920
  1134
    }
slouken@6920
  1135
slouken@3434
  1136
    /* Fast path for same format copy */
slouken@3434
  1137
    if (src_format == dst_format) {
slouken@11574
  1138
        int i;
slouken@3434
  1139
slouken@3434
  1140
        if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
slouken@3434
  1141
            switch (src_format) {
slouken@3434
  1142
            case SDL_PIXELFORMAT_YUY2:
slouken@3434
  1143
            case SDL_PIXELFORMAT_UYVY:
slouken@3434
  1144
            case SDL_PIXELFORMAT_YVYU:
slouken@11574
  1145
                /* Packed planes */
slouken@11574
  1146
                width = 4 * ((width + 1) / 2);
slouken@11574
  1147
                for (i = height; i--;) {
slouken@11574
  1148
                    SDL_memcpy(dst, src, width);
slouken@11574
  1149
                    src = (const Uint8*)src + src_pitch;
slouken@11574
  1150
                    dst = (Uint8*)dst + dst_pitch;
slouken@11574
  1151
                }
slouken@6663
  1152
                break;
slouken@9046
  1153
            case SDL_PIXELFORMAT_YV12:
slouken@9046
  1154
            case SDL_PIXELFORMAT_IYUV:
slouken@9046
  1155
            case SDL_PIXELFORMAT_NV12:
slouken@9046
  1156
            case SDL_PIXELFORMAT_NV21:
slouken@11574
  1157
                {
slouken@11574
  1158
                    /* Y plane */
slouken@11574
  1159
                    for (i = height; i--;) {
slouken@11574
  1160
                        SDL_memcpy(dst, src, width);
slouken@11574
  1161
                        src = (const Uint8*)src + src_pitch;
slouken@11574
  1162
                        dst = (Uint8*)dst + dst_pitch;
slouken@11574
  1163
                    }
slouken@11574
  1164
slouken@11574
  1165
                    /* not sure the pitch is relevant here.
slouken@11574
  1166
                       this also works to add the size of two chroma planes */
slouken@11574
  1167
#if 0
slouken@11574
  1168
                    SDL_memcpy(dst, src, 2 * ((width + 1)/2) * ((height+1)/2));
slouken@11574
  1169
#else
slouken@11574
  1170
slouken@11574
  1171
                    if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
slouken@11574
  1172
                        /* U and V planes are a quarter the size of the Y plane */
slouken@11574
  1173
                        width = (width + 1) / 2;
slouken@11574
  1174
                        height = (height + 1) / 2;
slouken@11574
  1175
                        src_pitch = (src_pitch + 1) / 2;
slouken@11574
  1176
                        dst_pitch = (dst_pitch + 1) / 2;
slouken@11574
  1177
                        for (i = height * 2; i--;) {
slouken@11574
  1178
                            SDL_memcpy(dst, src, width);
slouken@11574
  1179
                            src = (Uint8*)src + src_pitch;
slouken@11574
  1180
                            dst = (Uint8*)dst + dst_pitch;
slouken@11574
  1181
                        }
slouken@11574
  1182
                    } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
slouken@11574
  1183
                        /* U/V plane is half the height of the Y plane */
slouken@11574
  1184
                        height = (height + 1) / 2;
slouken@11574
  1185
                        width = (width + 1) / 2;
slouken@11574
  1186
                        src_pitch = (src_pitch + 1) / 2;
slouken@11574
  1187
                        dst_pitch = (dst_pitch + 1) / 2;
slouken@11574
  1188
                        for (i = height; i--;) {
slouken@11574
  1189
                            SDL_memcpy(dst, src, 2 * width);
slouken@11574
  1190
                            src = (Uint8*)src + 2 * src_pitch;
slouken@11574
  1191
                            dst = (Uint8*)dst + 2 * dst_pitch;
slouken@11574
  1192
                        }
slouken@11574
  1193
                    }
slouken@11574
  1194
#endif
slouken@11574
  1195
                }
slouken@9046
  1196
                break;
slouken@3434
  1197
            default:
icculus@7037
  1198
                return SDL_SetError("Unknown FOURCC pixel format");
slouken@3434
  1199
            }
slouken@3434
  1200
        } else {
slouken@11574
  1201
            const int bpp = SDL_BYTESPERPIXEL(src_format);
slouken@11574
  1202
            width *= bpp;
slouken@9046
  1203
            for (i = height; i--;) {
slouken@9046
  1204
                SDL_memcpy(dst, src, width);
slouken@11574
  1205
                src = (const Uint8*)src + src_pitch;
slouken@9046
  1206
                dst = (Uint8*)dst + dst_pitch;
slouken@9046
  1207
            }
slouken@9046
  1208
        }
slouken@6041
  1209
        return 0;
slouken@3434
  1210
    }
slouken@3434
  1211
slouken@11574
  1212
    /* FOURCC to Any */
slouken@11574
  1213
    if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
slouken@11574
  1214
        /* FOURCC to ARGB8888 */
slouken@11574
  1215
        if (dst_format == SDL_PIXELFORMAT_ARGB8888) {
slouken@11574
  1216
            SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, dst, dst_pitch);
slouken@11574
  1217
            return 0;
slouken@11574
  1218
        }
slouken@11574
  1219
        else /* FOURCC to not(ARGB8888) : need an intermediate conversion */
slouken@11574
  1220
        {
slouken@11574
  1221
            int ret;
slouken@11574
  1222
            void *tmp = SDL_malloc(width * height * 4);
slouken@11574
  1223
            if (tmp == NULL) {
slouken@11574
  1224
                return -1;
slouken@11574
  1225
            }
slouken@11574
  1226
slouken@11574
  1227
            /* convert src/FOURCC to tmp/ARGB8888 */
slouken@11574
  1228
            SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, tmp, width * 4);
slouken@11574
  1229
            
slouken@11574
  1230
            /* convert tmp/ARGB8888 to dst/dst_format */
slouken@11574
  1231
            ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4, dst_format, dst, dst_pitch);
slouken@11574
  1232
            SDL_free(tmp);
slouken@11574
  1233
            return ret;
slouken@11574
  1234
        }
slouken@11574
  1235
    }
slouken@11574
  1236
slouken@11574
  1237
    /* Any to FOURCC */
slouken@11574
  1238
    if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
slouken@11574
  1239
        /* ARGB8888 to FOURCC */
slouken@11574
  1240
        if (src_format == SDL_PIXELFORMAT_ARGB8888) {
slouken@11574
  1241
            SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst);
slouken@11574
  1242
            return 0;
slouken@11574
  1243
        }
slouken@11574
  1244
        else /* not(ARGB8888) to FOURCC : need an intermediate conversion */
slouken@11574
  1245
        {
slouken@11574
  1246
            int ret;
slouken@11574
  1247
            void *tmp = SDL_malloc(width * height * 4);
slouken@11574
  1248
            if (tmp == NULL) {
slouken@11574
  1249
                return -1;
slouken@11574
  1250
            }
slouken@11574
  1251
            /* convert src/src_format to tmp/ARGB8888 */
slouken@11574
  1252
            ret = SDL_ConvertPixels(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4);
slouken@11574
  1253
            if (ret == -1) {
slouken@11574
  1254
                SDL_free(tmp);
slouken@11574
  1255
                return ret;
slouken@11574
  1256
            }
slouken@11574
  1257
            /* convert tmp/ARGB8888 to dst/FOURCC */
slouken@11574
  1258
            SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, width * 4, dst_format, dst);
slouken@11574
  1259
slouken@11574
  1260
            SDL_free(tmp);
slouken@11574
  1261
            return 0;
slouken@11574
  1262
        }
slouken@11574
  1263
    }
slouken@11574
  1264
icculus@6407
  1265
    if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
slouken@3434
  1266
                                  src_pitch,
slouken@3434
  1267
                                  &src_surface, &src_fmt, &src_blitmap)) {
slouken@3434
  1268
        return -1;
slouken@3434
  1269
    }
slouken@3434
  1270
    if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
slouken@3434
  1271
                                  &dst_surface, &dst_fmt, &dst_blitmap)) {
slouken@3434
  1272
        return -1;
slouken@3434
  1273
    }
slouken@3434
  1274
slouken@3434
  1275
    /* Set up the rect and go! */
slouken@3434
  1276
    rect.x = 0;
slouken@3434
  1277
    rect.y = 0;
slouken@3434
  1278
    rect.w = width;
slouken@3436
  1279
    rect.h = height;
slouken@3434
  1280
    return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
slouken@3434
  1281
}
slouken@3434
  1282
slouken@3434
  1283
/*
slouken@0
  1284
 * Free a surface created by the above function.
slouken@0
  1285
 */
slouken@1895
  1286
void
slouken@1895
  1287
SDL_FreeSurface(SDL_Surface * surface)
slouken@0
  1288
{
slouken@1895
  1289
    if (surface == NULL) {
slouken@1895
  1290
        return;
slouken@1895
  1291
    }
slouken@5288
  1292
    if (surface->flags & SDL_DONTFREE) {
slouken@5288
  1293
        return;
slouken@5288
  1294
    }
slouken@11551
  1295
    SDL_InvalidateMap(surface->map);
slouken@11551
  1296
slouken@1895
  1297
    if (--surface->refcount > 0) {
slouken@1895
  1298
        return;
slouken@1895
  1299
    }
slouken@1895
  1300
    while (surface->locked > 0) {
slouken@1895
  1301
        SDL_UnlockSurface(surface);
slouken@1895
  1302
    }
slouken@1895
  1303
    if (surface->flags & SDL_RLEACCEL) {
slouken@1895
  1304
        SDL_UnRLESurface(surface, 0);
slouken@1895
  1305
    }
slouken@1895
  1306
    if (surface->format) {
slouken@1895
  1307
        SDL_SetSurfacePalette(surface, NULL);
slouken@1895
  1308
        SDL_FreeFormat(surface->format);
slouken@1895
  1309
        surface->format = NULL;
slouken@1895
  1310
    }
slouken@7719
  1311
    if (!(surface->flags & SDL_PREALLOC)) {
slouken@1895
  1312
        SDL_free(surface->pixels);
slouken@1895
  1313
    }
brandon@11563
  1314
    if (surface->map) {
brandon@11563
  1315
        SDL_FreeBlitMap(surface->map);
brandon@11563
  1316
    }
slouken@1895
  1317
    SDL_free(surface);
slouken@0
  1318
}
slouken@1895
  1319
slouken@11574
  1320
slouken@11574
  1321
/* YUV-RGB conversion */
slouken@11574
  1322
#define CLAMP(val) ((val) > 0 ? ((val) < 255 ? (val) : 255) : 0)
slouken@11574
  1323
slouken@11574
  1324
#define MAKE_Y(r, g, b) (((  66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
slouken@11574
  1325
#define MAKE_U(r, g, b) ((( -38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
slouken@11574
  1326
#define MAKE_V(r, g, b) ((( 112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
slouken@11574
  1327
slouken@11574
  1328
slouken@11574
  1329
#define MAKE_R(y, u, v) CLAMP(( 298 * ((y) - 16)                     + 409 * ((v) - 128) + 128) >> 8) 
slouken@11574
  1330
#define MAKE_G(y, u, v) CLAMP(( 298 * ((y) - 16) - 100 * ((u) - 128) - 208 * ((v) - 128) + 128) >> 8)
slouken@11574
  1331
#define MAKE_B(y, u, v) CLAMP(( 298 * ((y) - 16) + 516 * ((u) - 128)                     + 128) >> 8)
slouken@11574
  1332
slouken@11574
  1333
static int
slouken@11574
  1334
SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
slouken@11574
  1335
         Uint32 src_format, const void *src, 
slouken@11574
  1336
         void *dst, int dst_pitch)
slouken@11574
  1337
{   
slouken@11574
  1338
    const int sz_plane         = width * height;
slouken@11574
  1339
    const int sz_plane_chroma  = ((width + 1) / 2) * ((height + 1) / 2);
slouken@11574
  1340
    const int width_remainder  = (width &  0x1);
slouken@11574
  1341
    const int width_half       = width / 2;
slouken@11574
  1342
    const int curr_row_padding = dst_pitch - 4 * width;
slouken@11574
  1343
    int i, j;
slouken@11574
  1344
    Uint8 *curr_row = (Uint8*)dst;
slouken@11574
  1345
slouken@11574
  1346
    // SDL_Log("SDL_ConvertPixels_YUV_to_ARGB8888 (from %s)", SDL_GetPixelFormatName(src_format));
slouken@11574
  1347
slouken@11574
  1348
#define WRITE_RGB_PIXEL(y, u, v)            \
slouken@11574
  1349
    *((Uint32*)curr_row) =                  \
slouken@11574
  1350
           (MAKE_B((y), (u), (v))           \
slouken@11574
  1351
         | (MAKE_G((y), (u), (v)) << 8)     \
slouken@11574
  1352
         | (MAKE_R((y), (u), (v)) << 16)    \
slouken@11574
  1353
         | 0xff000000);                     \
slouken@11574
  1354
    curr_row += 4;                          \
slouken@11574
  1355
slouken@11574
  1356
    switch (src_format) 
slouken@11574
  1357
    {
slouken@11574
  1358
        case SDL_PIXELFORMAT_YV12:
slouken@11574
  1359
        case SDL_PIXELFORMAT_IYUV:
slouken@11574
  1360
        case SDL_PIXELFORMAT_NV12:
slouken@11574
  1361
        case SDL_PIXELFORMAT_NV21:
slouken@11574
  1362
            {
slouken@11574
  1363
                const Uint8 *plane_y = (const Uint8*)src;
slouken@11574
  1364
slouken@11574
  1365
                if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV)
slouken@11574
  1366
                {
slouken@11574
  1367
                    const Uint8 *plane_u = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
slouken@11574
  1368
                    const Uint8 *plane_v = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
slouken@11574
  1369
slouken@11574
  1370
                    for (j = 0; j < height; j++) {
slouken@11574
  1371
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1372
                            const Uint8 u = *plane_u++;
slouken@11574
  1373
                            const Uint8 v = *plane_v++;
slouken@11574
  1374
                            const Uint8 y = *plane_y++;
slouken@11574
  1375
                            const Uint8 y1 = *plane_y++;
slouken@11574
  1376
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1377
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1378
                        }
slouken@11574
  1379
                        if (width_remainder) {
slouken@11574
  1380
                            const Uint8 u = *plane_u++;
slouken@11574
  1381
                            const Uint8 v = *plane_v++;
slouken@11574
  1382
                            const Uint8 y = *plane_y++;
slouken@11574
  1383
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1384
                        }
slouken@11574
  1385
                        /* Re-use the same line of chroma planes */
slouken@11574
  1386
                        if ((j & 0x1) == 0x0) {
slouken@11574
  1387
                            plane_u -= width_half + width_remainder;
slouken@11574
  1388
                            plane_v -= width_half + width_remainder;
slouken@11574
  1389
                        }
slouken@11574
  1390
                        curr_row += curr_row_padding;
slouken@11574
  1391
                    }
slouken@11574
  1392
                }
slouken@11574
  1393
                else if (src_format == SDL_PIXELFORMAT_NV12)
slouken@11574
  1394
                {
slouken@11574
  1395
                    const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
slouken@11574
  1396
                    for (j = 0; j < height; j++) {
slouken@11574
  1397
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1398
                            const Uint8 y = *plane_y++;
slouken@11574
  1399
                            const Uint8 y1 = *plane_y++;
slouken@11574
  1400
                            const Uint8 u = *plane_interleaved_uv++;
slouken@11574
  1401
                            const Uint8 v = *plane_interleaved_uv++;
slouken@11574
  1402
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1403
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1404
                        }
slouken@11574
  1405
                        if (width_remainder) {
slouken@11574
  1406
                            const Uint8 y = *plane_y++;
slouken@11574
  1407
                            const Uint8 u = *plane_interleaved_uv++;
slouken@11574
  1408
                            const Uint8 v = *plane_interleaved_uv++;
slouken@11574
  1409
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1410
                        }
slouken@11574
  1411
                        /* Re-use the same line of chroma planes */
slouken@11574
  1412
                        if ((j & 0x1) == 0x0) {
slouken@11574
  1413
                            plane_interleaved_uv -= 2 * (width_half + width_remainder);
slouken@11574
  1414
                        }
slouken@11574
  1415
                        curr_row += curr_row_padding;
slouken@11574
  1416
                    }
slouken@11574
  1417
                } 
slouken@11574
  1418
                else /* src_format == SDL_PIXELFORMAT_NV21 */
slouken@11574
  1419
                {
slouken@11574
  1420
                    const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
slouken@11574
  1421
                    for (j = 0; j < height; j++) {
slouken@11574
  1422
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1423
                            const Uint8 y = *plane_y++;
slouken@11574
  1424
                            const Uint8 y1 = *plane_y++;
slouken@11574
  1425
                            const Uint8 v = *plane_interleaved_uv++;
slouken@11574
  1426
                            const Uint8 u = *plane_interleaved_uv++;
slouken@11574
  1427
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1428
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1429
                        }
slouken@11574
  1430
                        if (width_remainder) {
slouken@11574
  1431
                            const Uint8 y = *plane_y++;
slouken@11574
  1432
                            const Uint8 v = *plane_interleaved_uv++;
slouken@11574
  1433
                            const Uint8 u = *plane_interleaved_uv++;
slouken@11574
  1434
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1435
                        }
slouken@11574
  1436
                        /* Re-use the same line of chroma planes */
slouken@11574
  1437
                        if ((j & 0x1) == 0x0) {
slouken@11574
  1438
                            plane_interleaved_uv -= 2 * (width_half + width_remainder);
slouken@11574
  1439
                        }
slouken@11574
  1440
                        curr_row += curr_row_padding;
slouken@11574
  1441
                    }
slouken@11574
  1442
                }
slouken@11574
  1443
            }
slouken@11574
  1444
            break;
slouken@11574
  1445
slouken@11574
  1446
        case SDL_PIXELFORMAT_YUY2:
slouken@11574
  1447
        case SDL_PIXELFORMAT_UYVY:
slouken@11574
  1448
        case SDL_PIXELFORMAT_YVYU:
slouken@11574
  1449
            {
slouken@11574
  1450
                const Uint8 *plane = (const Uint8 *)src;
slouken@11574
  1451
slouken@11574
  1452
#define READ_PACKED_YUV(var1, var2, var3, var4) \
slouken@11574
  1453
                const Uint8 var1 = plane[0];    \
slouken@11574
  1454
                const Uint8 var2 = plane[1];    \
slouken@11574
  1455
                const Uint8 var3 = plane[2];    \
slouken@11574
  1456
                const Uint8 var4 = plane[3];    \
slouken@11574
  1457
                plane += 4;                     \
slouken@11574
  1458
slouken@11574
  1459
                if (src_format == SDL_PIXELFORMAT_YUY2) /* Y U Y1 V */
slouken@11574
  1460
                {
slouken@11574
  1461
                    for (j = 0; j < height; j++) {
slouken@11574
  1462
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1463
                            READ_PACKED_YUV(y, u, y1, v);
slouken@11574
  1464
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1465
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1466
                        }
slouken@11574
  1467
                        if (width_remainder) {
slouken@11574
  1468
                            READ_PACKED_YUV(y, u, y1, v); /* y1 unused */
slouken@11574
  1469
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1470
                        }
slouken@11574
  1471
                        curr_row += curr_row_padding;
slouken@11574
  1472
                    }
slouken@11574
  1473
                } 
slouken@11574
  1474
                else if (src_format == SDL_PIXELFORMAT_UYVY) /* U Y V Y1 */
slouken@11574
  1475
                {
slouken@11574
  1476
                    for (j = 0; j < height; j++) {
slouken@11574
  1477
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1478
                            READ_PACKED_YUV(u, y, v, y1);
slouken@11574
  1479
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1480
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1481
                        }
slouken@11574
  1482
                        if (width_remainder) {
slouken@11574
  1483
                            READ_PACKED_YUV(u, y, v, y1); /* y1 unused */
slouken@11574
  1484
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1485
                        }
slouken@11574
  1486
                        curr_row += curr_row_padding;
slouken@11574
  1487
                    }
slouken@11574
  1488
                }
slouken@11574
  1489
                else if (src_format == SDL_PIXELFORMAT_YVYU) /* Y V Y1 U */
slouken@11574
  1490
                {
slouken@11574
  1491
                    for (j = 0; j < height; j++) {
slouken@11574
  1492
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1493
                            READ_PACKED_YUV(y, v, y1, u);
slouken@11574
  1494
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1495
                            WRITE_RGB_PIXEL(y1, u, v);
slouken@11574
  1496
                        }
slouken@11574
  1497
                        if (width_remainder) {
slouken@11574
  1498
                            READ_PACKED_YUV(y, v, y1, u); /* y1 unused */
slouken@11574
  1499
                            WRITE_RGB_PIXEL(y, u, v);
slouken@11574
  1500
                        }
slouken@11574
  1501
                        curr_row += curr_row_padding;
slouken@11574
  1502
                    }
slouken@11574
  1503
                } 
slouken@11574
  1504
#undef READ_PACKED_YUV
slouken@11574
  1505
            }
slouken@11574
  1506
            break;
slouken@11574
  1507
    }
slouken@11574
  1508
#undef WRITE_RGB_PIXEL
slouken@11574
  1509
    return 0;
slouken@11574
  1510
}
slouken@11574
  1511
slouken@11574
  1512
static int
slouken@11574
  1513
SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, void *dst)
slouken@11574
  1514
{
slouken@11574
  1515
    const int src_pitch_x_2    = src_pitch * 2;
slouken@11574
  1516
    const int sz_plane         = width * height;
slouken@11574
  1517
    const int sz_plane_chroma  = ((width + 1) / 2) * ((height + 1) / 2);
slouken@11574
  1518
    const int height_half      = height / 2;
slouken@11574
  1519
    const int height_remainder = (height &  0x1);
slouken@11574
  1520
    const int width_half       = width / 2;
slouken@11574
  1521
    const int width_remainder  = (width  &  0x1);
slouken@11574
  1522
    int i, j;
slouken@11574
  1523
    
slouken@11574
  1524
    // SDL_Log("SDL_ConvertPixels_ARGB8888_to_YUV (to %s)", SDL_GetPixelFormatName(dst_format));
slouken@11574
  1525
slouken@11574
  1526
    switch (dst_format) 
slouken@11574
  1527
    {
slouken@11574
  1528
        case SDL_PIXELFORMAT_YV12:
slouken@11574
  1529
        case SDL_PIXELFORMAT_IYUV:
slouken@11574
  1530
        case SDL_PIXELFORMAT_NV12:
slouken@11574
  1531
        case SDL_PIXELFORMAT_NV21:
slouken@11574
  1532
            {
slouken@11574
  1533
                const Uint8 *curr_row, *next_row;
slouken@11574
  1534
                
slouken@11574
  1535
                Uint8 *plane_y = (Uint8*) dst;
slouken@11574
  1536
                Uint8 *plane_u = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
slouken@11574
  1537
                Uint8 *plane_v = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
slouken@11574
  1538
                Uint8 *plane_interleaved_uv = plane_y + sz_plane;
slouken@11574
  1539
slouken@11574
  1540
                curr_row = (const Uint8*)src;
slouken@11574
  1541
slouken@11574
  1542
                /* Write Y plane */
slouken@11574
  1543
                for (j = 0; j < height; j++) {
slouken@11574
  1544
                    for (i = 0; i < width; i++) {
slouken@11574
  1545
                        const Uint8 b = curr_row[4 * i + 0];
slouken@11574
  1546
                        const Uint8 g = curr_row[4 * i + 1];
slouken@11574
  1547
                        const Uint8 r = curr_row[4 * i + 2];
slouken@11574
  1548
                        *plane_y++ = MAKE_Y(r, g, b);
slouken@11574
  1549
                    }
slouken@11574
  1550
                    curr_row += src_pitch;
slouken@11574
  1551
                }
slouken@11574
  1552
slouken@11574
  1553
                curr_row = (const Uint8*)src;
slouken@11574
  1554
                next_row = (const Uint8*)src;
slouken@11574
  1555
                next_row += src_pitch;
slouken@11574
  1556
slouken@11574
  1557
#if 1
slouken@11574
  1558
/* slightly faster */
slouken@11574
  1559
#define READ_2x2_PIXELS                                                                                                 \
slouken@11574
  1560
                const Uint32 p1 = ((Uint32 *)curr_row)[2 * i];                                                          \
slouken@11574
  1561
                const Uint32 p2 = ((Uint32 *)curr_row)[2 * i + 1];                                                      \
slouken@11574
  1562
                const Uint32 p3 = ((Uint32 *)next_row)[2 * i];                                                          \
slouken@11574
  1563
                const Uint32 p4 = ((Uint32 *)next_row)[2 * i + 1];                                                      \
slouken@11574
  1564
                const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2;  \
slouken@11574
  1565
                const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \
slouken@11574
  1566
                const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \
slouken@11574
  1567
slouken@11574
  1568
#else
slouken@11574
  1569
slouken@11574
  1570
#define READ_2x2_PIXELS                                                             \
slouken@11574
  1571
                const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4]          \
slouken@11574
  1572
                               + next_row[8 * i + 0] + next_row[8 * i + 4] ) >> 2;  \
slouken@11574
  1573
                const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5]          \
slouken@11574
  1574
                               + next_row[8 * i + 1] + next_row[8 * i + 5] ) >> 2;  \
slouken@11574
  1575
                const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6]          \
slouken@11574
  1576
                               + next_row[8 * i + 2] + next_row[8 * i + 6] ) >> 2;  \
slouken@11574
  1577
slouken@11574
  1578
#endif
slouken@11574
  1579
slouken@11574
  1580
#define READ_2x1_PIXELS                                                             \
slouken@11574
  1581
                const Uint8 b = (curr_row[8 * i + 0] + next_row[8 * i + 0]) >> 1;   \
slouken@11574
  1582
                const Uint8 g = (curr_row[8 * i + 1] + next_row[8 * i + 1]) >> 1;   \
slouken@11574
  1583
                const Uint8 r = (curr_row[8 * i + 2] + next_row[8 * i + 2]) >> 1;   \
slouken@11574
  1584
slouken@11574
  1585
#define READ_1x2_PIXELS                                                             \
slouken@11574
  1586
                const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4]) >> 1;   \
slouken@11574
  1587
                const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5]) >> 1;   \
slouken@11574
  1588
                const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6]) >> 1;   \
slouken@11574
  1589
slouken@11574
  1590
#define READ_1x1_PIXEL                                                              \
slouken@11574
  1591
                const Uint8 b = curr_row[8 * i + 0];                                \
slouken@11574
  1592
                const Uint8 g = curr_row[8 * i + 1];                                \
slouken@11574
  1593
                const Uint8 r = curr_row[8 * i + 2];                                \
slouken@11574
  1594
                
slouken@11574
  1595
                if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV)
slouken@11574
  1596
                {
slouken@11574
  1597
                    /* Write UV planes, not interleaved */
slouken@11574
  1598
                    for (j = 0; j < height_half; j++) {
slouken@11574
  1599
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1600
                            READ_2x2_PIXELS;
slouken@11574
  1601
                            *plane_u++ = MAKE_U(r, g, b);
slouken@11574
  1602
                            *plane_v++ = MAKE_V(r, g, b);
slouken@11574
  1603
                        }
slouken@11574
  1604
                        if (width_remainder) {
slouken@11574
  1605
                            READ_2x1_PIXELS;
slouken@11574
  1606
                            *plane_u++ = MAKE_U(r, g, b);
slouken@11574
  1607
                            *plane_v++ = MAKE_V(r, g, b);
slouken@11574
  1608
                        }
slouken@11574
  1609
                        curr_row += src_pitch_x_2;
slouken@11574
  1610
                        next_row += src_pitch_x_2;
slouken@11574
  1611
                    }
slouken@11574
  1612
                    if (height_remainder) {
slouken@11574
  1613
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1614
                            READ_1x2_PIXELS;
slouken@11574
  1615
                            *plane_u++ = MAKE_U(r, g, b);
slouken@11574
  1616
                            *plane_v++ = MAKE_V(r, g, b);
slouken@11574
  1617
                        }
slouken@11574
  1618
                        if (width_remainder) {
slouken@11574
  1619
                            READ_1x1_PIXEL;
slouken@11574
  1620
                            *plane_u++ = MAKE_U(r, g, b);
slouken@11574
  1621
                            *plane_v++ = MAKE_V(r, g, b);
slouken@11574
  1622
                        }
slouken@11574
  1623
                    }
slouken@11574
  1624
                }
slouken@11574
  1625
                else if (dst_format == SDL_PIXELFORMAT_NV12)
slouken@11574
  1626
                {
slouken@11574
  1627
                    for (j = 0; j < height_half; j++) {
slouken@11574
  1628
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1629
                            READ_2x2_PIXELS;
slouken@11574
  1630
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1631
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1632
                        }
slouken@11574
  1633
                        if (width_remainder) {
slouken@11574
  1634
                            READ_2x1_PIXELS;
slouken@11574
  1635
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1636
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1637
                        }
slouken@11574
  1638
                        curr_row += src_pitch_x_2;
slouken@11574
  1639
                        next_row += src_pitch_x_2;
slouken@11574
  1640
                    }
slouken@11574
  1641
                    if (height_remainder) {
slouken@11574
  1642
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1643
                            READ_1x2_PIXELS;
slouken@11574
  1644
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1645
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1646
                        }
slouken@11574
  1647
                        if (width_remainder) {
slouken@11574
  1648
                            READ_1x1_PIXEL;
slouken@11574
  1649
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1650
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1651
                        }
slouken@11574
  1652
                    }
slouken@11574
  1653
                } 
slouken@11574
  1654
                else /* dst_format == SDL_PIXELFORMAT_NV21 */
slouken@11574
  1655
                {
slouken@11574
  1656
                    for (j = 0; j < height_half; j++) {
slouken@11574
  1657
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1658
                            READ_2x2_PIXELS;
slouken@11574
  1659
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1660
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1661
                        }
slouken@11574
  1662
                        if (width_remainder) {
slouken@11574
  1663
                            READ_2x1_PIXELS;
slouken@11574
  1664
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1665
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1666
                        }
slouken@11574
  1667
                        curr_row += src_pitch_x_2;
slouken@11574
  1668
                        next_row += src_pitch_x_2;
slouken@11574
  1669
                    }
slouken@11574
  1670
                    if (height_remainder) {
slouken@11574
  1671
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1672
                            READ_1x2_PIXELS;
slouken@11574
  1673
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1674
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1675
                        }
slouken@11574
  1676
                        if (width_remainder) {
slouken@11574
  1677
                            READ_1x1_PIXEL;
slouken@11574
  1678
                            *plane_interleaved_uv++ = MAKE_V(r, g, b);
slouken@11574
  1679
                            *plane_interleaved_uv++ = MAKE_U(r, g, b);
slouken@11574
  1680
                        }
slouken@11574
  1681
                    }
slouken@11574
  1682
                }
slouken@11574
  1683
#undef READ_2x2_PIXELS
slouken@11574
  1684
#undef READ_2x1_PIXELS
slouken@11574
  1685
#undef READ_1x2_PIXELS
slouken@11574
  1686
#undef READ_1x1_PIXEL
slouken@11574
  1687
            }
slouken@11574
  1688
            break;
slouken@11574
  1689
slouken@11574
  1690
        case SDL_PIXELFORMAT_YUY2:
slouken@11574
  1691
        case SDL_PIXELFORMAT_UYVY:
slouken@11574
  1692
        case SDL_PIXELFORMAT_YVYU:
slouken@11574
  1693
            {
slouken@11574
  1694
                const Uint8 *curr_row = (const Uint8*) src;
slouken@11574
  1695
                Uint8 *plane           = (Uint8*) dst;
slouken@11574
  1696
slouken@11574
  1697
#define READ_TWO_RGB_PIXELS \
slouken@11574
  1698
                const Uint8 b = curr_row[8 * i + 0];    \
slouken@11574
  1699
                const Uint8 g = curr_row[8 * i + 1];    \
slouken@11574
  1700
                const Uint8 r = curr_row[8 * i + 2];    \
slouken@11574
  1701
                const Uint8 b1 = curr_row[8 * i + 4];   \
slouken@11574
  1702
                const Uint8 g1 = curr_row[8 * i + 5];   \
slouken@11574
  1703
                const Uint8 r1 = curr_row[8 * i + 6];   \
slouken@11574
  1704
                const Uint8 B = (b + b1) >> 1;          \
slouken@11574
  1705
                const Uint8 G = (g + g1) >> 1;          \
slouken@11574
  1706
                const Uint8 R = (r + r1) >> 1;          \
slouken@11574
  1707
slouken@11574
  1708
#define READ_ONE_RGB_PIXEL \
slouken@11574
  1709
                const Uint8 b = curr_row[8 * i + 0];    \
slouken@11574
  1710
                const Uint8 g = curr_row[8 * i + 1];    \
slouken@11574
  1711
                const Uint8 r = curr_row[8 * i + 2];    \
slouken@11574
  1712
slouken@11574
  1713
                /* Write YUV plane, packed */
slouken@11574
  1714
                if (dst_format == SDL_PIXELFORMAT_YUY2) 
slouken@11574
  1715
                {
slouken@11574
  1716
                    for (j = 0; j < height; j++) {
slouken@11574
  1717
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1718
                            READ_TWO_RGB_PIXELS;
slouken@11574
  1719
                            /* Y U Y1 V */
slouken@11574
  1720
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1721
                            *plane++ = MAKE_U(R, G, B);
slouken@11574
  1722
                            *plane++ = MAKE_Y(r1, g1, b1);
slouken@11574
  1723
                            *plane++ = MAKE_V(R, G, B);
slouken@11574
  1724
                        }
slouken@11574
  1725
                        if (width_remainder) {
slouken@11574
  1726
                            READ_ONE_RGB_PIXEL;
slouken@11574
  1727
                            /* Y U Y V */
slouken@11574
  1728
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1729
                            *plane++ = MAKE_U(r, g, b);
slouken@11574
  1730
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1731
                            *plane++ = MAKE_V(r, g, b);
slouken@11574
  1732
                        }
slouken@11574
  1733
                        curr_row += src_pitch;
slouken@11574
  1734
                    }
slouken@11574
  1735
                } 
slouken@11574
  1736
                else if (dst_format == SDL_PIXELFORMAT_UYVY)
slouken@11574
  1737
                {
slouken@11574
  1738
                    for (j = 0; j < height; j++) {
slouken@11574
  1739
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1740
                            READ_TWO_RGB_PIXELS;
slouken@11574
  1741
                            /* U Y V Y1 */
slouken@11574
  1742
                            *plane++ = MAKE_U(R, G, B);
slouken@11574
  1743
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1744
                            *plane++ = MAKE_V(R, G, B);
slouken@11574
  1745
                            *plane++ = MAKE_Y(r1, g1, b1);
slouken@11574
  1746
                        }
slouken@11574
  1747
                        if (width_remainder) {
slouken@11574
  1748
                            READ_ONE_RGB_PIXEL;
slouken@11574
  1749
                            /* U Y V Y */
slouken@11574
  1750
                            *plane++ = MAKE_U(r, g, b);
slouken@11574
  1751
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1752
                            *plane++ = MAKE_V(r, g, b);
slouken@11574
  1753
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1754
                        }
slouken@11574
  1755
                        curr_row += src_pitch;
slouken@11574
  1756
                    }
slouken@11574
  1757
                }
slouken@11574
  1758
                else if (dst_format == SDL_PIXELFORMAT_YVYU)
slouken@11574
  1759
                {
slouken@11574
  1760
                    for (j = 0; j < height; j++) {
slouken@11574
  1761
                        for (i = 0; i < width_half; i++) {
slouken@11574
  1762
                            READ_TWO_RGB_PIXELS;
slouken@11574
  1763
                            /* Y V Y1 U */
slouken@11574
  1764
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1765
                            *plane++ = MAKE_V(R, G, B);
slouken@11574
  1766
                            *plane++ = MAKE_Y(r1, g1, b1);
slouken@11574
  1767
                            *plane++ = MAKE_U(R, G, B);
slouken@11574
  1768
                        }
slouken@11574
  1769
                        if (width_remainder) {
slouken@11574
  1770
                            READ_ONE_RGB_PIXEL;
slouken@11574
  1771
                            /* Y V Y U */
slouken@11574
  1772
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1773
                            *plane++ = MAKE_V(r, g, b);
slouken@11574
  1774
                            *plane++ = MAKE_Y(r, g, b);
slouken@11574
  1775
                            *plane++ = MAKE_U(r, g, b);
slouken@11574
  1776
                        }
slouken@11574
  1777
                        curr_row += src_pitch;
slouken@11574
  1778
                    }
slouken@11574
  1779
                }
slouken@11574
  1780
#undef READ_TWO_RGB_PIXELS
slouken@11574
  1781
#undef READ_ONE_RGB_PIXEL
slouken@11574
  1782
            }
slouken@11574
  1783
            break;
slouken@11574
  1784
    }
slouken@11574
  1785
    return 0;
slouken@11574
  1786
}
slouken@11574
  1787
slouken@1895
  1788
/* vi: set ts=4 sw=4 expandtab: */